diff --git a/tradein-mvp/deploy/backup-tradein-db.sh b/tradein-mvp/deploy/backup-tradein-db.sh new file mode 100755 index 00000000..1829de51 --- /dev/null +++ b/tradein-mvp/deploy/backup-tradein-db.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# Бэкап БД tradein-postgres — pg_dump по cron + retention (#397). +# +# Запускается из cron на прод-хосте. pg_dump идёт через `docker exec` +# (локальный сокет внутри контейнера — пароль не нужен). +# +# Crontab пример (ежедневно в 04:30 UTC): +# 30 4 * * * /opt/gendesign/tradein-mvp/deploy/backup-tradein-db.sh >> /tmp/tradein-backup.log 2>&1 +# +# Restore: +# gunzip -c tradein-YYYYMMDD-HHMMSS.sql.gz | \ +# docker exec -i tradein-postgres psql -U tradein -d tradein + +set -euo pipefail + +BACKUP_DIR="${BACKUP_DIR:-/opt/gendesign/backups/tradein}" +KEEP="${KEEP:-7}" # сколько копий хранить +PG_CONTAINER="${PG_CONTAINER:-tradein-postgres}" + +mkdir -p "$BACKUP_DIR" +ts=$(date -u +'%Y%m%d-%H%M%S') +out="$BACKUP_DIR/tradein-$ts.sql.gz" + +# --clean --if-exists → дамп самодостаточен для восстановления «с нуля». +# --no-owner → restore не требует тех же ролей. +docker exec "$PG_CONTAINER" pg_dump -U tradein -d tradein \ + --no-owner --clean --if-exists 2>/dev/null | gzip -6 > "$out" + +if [[ ! -s "$out" ]]; then + echo "[$(date -u +%H:%M:%S)] ОШИБКА: дамп пустой — $out" >&2 + rm -f "$out" + exit 1 +fi + +# Retention — оставляем KEEP самых свежих, остальные tradein-*.sql.gz удаляем. +ls -1t "$BACKUP_DIR"/tradein-*.sql.gz 2>/dev/null \ + | tail -n +"$((KEEP + 1))" \ + | xargs -r rm -f + +size=$(du -h "$out" | cut -f1) +count=$(ls -1 "$BACKUP_DIR"/tradein-*.sql.gz 2>/dev/null | wc -l | tr -d ' ') +echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] backup ok: $out ($size), копий хранится: $count"