fix(vds-backup): MSSQL backup INIT->FORMAT + estate backup audit

VDS daily backup пал с 12.06 (line 108, exit 1): mssql-блок (added 11.06,
commit f8ca0794) использовал `WITH ... INIT`, упирался в компрессованный
media-header майских .bak (созданы WITH COMPRESSION на Developer-источнике).
Express не пишет в compression-форматированный media set -> Msg 1844, молчаливый
провал первым же cron-запуском. 5 боевых CMS-баз 3 недели без offsite-копии.

Fix: INIT -> FORMAT (всегда новый media set, иммунно к остаткам). Прогон
verified зелёным: VDS backup OK 95m41s, все 5 .bak на kreknin
(MoreThenCms 910M, StayerCalculator 528M, StayerPrice 39M, TireService 4.5M,
stostayer 990M), speedup 22.62 (--link-dest хардлинкует).

- scripts/vds-backup-rsync-kreknin/run.sh: синхронизирован с задеплоенным
  (mssql-блока в репо не было); FORMAT
- .wiki/concepts/mssql-on-vds.md: gotcha #2 (INIT vs FORMAT) + backup-gap
- .wiki/concepts/backup-inventory-2026-06.md: новая — карта estate × что реально
  бэкапится (с доказательством); триаж дыр
- openwrt UCI backup настроен (cron 03:30 -> kreknin, restricted forced-command
  key) — документация в entity + inventory
- .tasks/kreknin-self-backup.md: backlog #1 SPOF (приёмник сам не бэкапится)
- STATUS.md: incident + audit summary

Урок: бэкап-шаг не готов, пока не предъявлен лог одного реального успеха;
прод-крон не должен быть первым тестом бэкап-пути.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-12 10:21:44 +03:00
parent 1fb7fc2e90
commit b332af66e4
7 changed files with 129 additions and 4 deletions

View File

@@ -100,6 +100,21 @@ docker cp redis:/data/dump.rdb "$DUMP_DIR/redis.rdb"
gzip -f "$DUMP_DIR/redis.rdb"
echo "redis: $(stat -c %s "$DUMP_DIR/redis.rdb.gz") bytes"
# MSSQL: backup 5 prod DBs via sqlcmd into bind-mounted /var/opt/mssql/backups/
# WITH FORMAT (not INIT): Express can't write to a media set previously formatted
# WITH COMPRESSION (e.g. migration-era .bak); FORMAT recreates the media set fresh.
source /opt/stacks/databases/mssql/.env # injects MSSQL_SA_PASSWORD
MSSQL_BACKUP_DIR=/opt/stacks/databases/mssql/backups
for DB in MoreThenCms StayerCalculator StayerPrice TireService stostayer; do
docker exec mssql /opt/mssql-tools18/bin/sqlcmd \
-S localhost -U sa -P "$MSSQL_SA_PASSWORD" -C -b \
-Q "BACKUP DATABASE [$DB] TO DISK='/var/opt/mssql/backups/${DB}.bak' WITH COPY_ONLY, FORMAT" \
> /dev/null
mv "$MSSQL_BACKUP_DIR/${DB}.bak" "$DUMP_DIR/mssql-${DB}.bak"
echo "mssql $DB: $(stat -c %s "$DUMP_DIR/mssql-${DB}.bak") bytes"
done
unset MSSQL_SA_PASSWORD
# === Step 2: rsync to kreknin ===
echo "--- rsync to $DEST_USER@$DEST_HOST:$DEST_PATH ---"
ssh $SSH_OPTS "$DEST_USER@$DEST_HOST" "mkdir -p '$DEST_PATH'"