food-market/docs/backup-restore.md
nns 7c34bb1abd feat(deploy): авто-бэкап БД+uploads — systemd timer/service + скрипт (P0-6)
food-market-backup.sh: pg_dump -Fc контейнера + tar uploads, ротация 30 дней,
атомарная запись через .tmp+mv. food-market-backup.{service,timer} — ежедневно
03:00 с догоном пропущенных. docs/backup-restore.md — установка таймера, ручной
бэкап, восстановление БД (drop+create / --clean) и uploads, проверка дампа.

Скрипт проверен против food-market-postgres: дамп PGDMP custom-format,
248 TOC, pg_restore --list читает. Установку на prod-vm не делаем — только артефакты.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 02:49:08 +05:00

102 lines
4.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Бэкап и восстановление
Артефакты в репозитории (`deploy/`):
- `food-market-backup.sh` — скрипт бэкапа БД + uploads с ротацией.
- `food-market-backup.service` — systemd oneshot-юнит, запускающий скрипт.
- `food-market-backup.timer` — ежедневный таймер (03:00, с догоном пропущенных).
> Установку на prod-vm выполняет отдельный деплой-шаг (см. ниже) — здесь только
> подготовленные артефакты.
## Что бэкапится
| Что | Как | Файл |
|---|---|---|
| База данных | `pg_dump -Fc` из контейнера `food-market-postgres` | `db-<TS>.dump` (custom-format) |
| Загруженные файлы (картинки товаров) | `tar czf` каталога uploads | `uploads-<TS>.tgz` |
Папка назначения по умолчанию — `/opt/food-market-data/backups`. Хранение —
30 дней (`FM_BACKUP_RETENTION_DAYS`), старые удаляются ротацией. Конфиг —
переменными `FM_*` (см. шапку `food-market-backup.sh`).
## Установка таймера на сервере (деплой-шаг)
Предполагается, что репозиторий выложен в `/opt/food-market` (иначе скорректировать
`ExecStart`/`EnvironmentFile` в `.service` и пути ниже).
```bash
sudo install -m 0755 /opt/food-market/deploy/food-market-backup.sh /opt/food-market/deploy/food-market-backup.sh
sudo cp /opt/food-market/deploy/food-market-backup.service /etc/systemd/system/
sudo cp /opt/food-market/deploy/food-market-backup.timer /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now food-market-backup.timer
# Проверить расписание и последний запуск
systemctl list-timers food-market-backup.timer
# Прогнать бэкап немедленно (разово)
sudo systemctl start food-market-backup.service
journalctl -u food-market-backup.service --no-pager | tail -20
```
## Ручной бэкап
```bash
sudo /opt/food-market/deploy/food-market-backup.sh
# или с переопределением каталога:
FM_BACKUP_DIR=/mnt/backups sudo -E /opt/food-market/deploy/food-market-backup.sh
```
## Восстановление БД
> ⚠️ Восстановление перезаписывает данные. Сначала остановить API, чтобы не было
> записи во время восстановления.
```bash
cd /opt/food-market/deploy
docker compose stop api web
DUMP=/opt/food-market-data/backups/db-YYYYMMDD-HHMMSS.dump
# Скопировать дамп внутрь контейнера БД
docker cp "$DUMP" food-market-postgres:/tmp/restore.dump
# Вариант A — восстановить в чистую БД (рекомендуется):
docker exec food-market-postgres psql -U food_market -d postgres -c \
"DROP DATABASE IF EXISTS food_market WITH (FORCE); CREATE DATABASE food_market OWNER food_market;"
docker exec food-market-postgres pg_restore -U food_market -d food_market --no-owner /tmp/restore.dump
# Вариант B — в существующую БД, заменив объекты (без пересоздания БД):
# docker exec food-market-postgres pg_restore -U food_market -d food_market --clean --if-exists --no-owner /tmp/restore.dump
docker exec food-market-postgres rm -f /tmp/restore.dump
docker compose start api web
```
После старта API применит миграции (`Migrate()` идемпотентен) и поднимется. Проверить:
```bash
curl -fsS http://localhost:8080/health/ready
```
## Восстановление uploads
```bash
TGZ=/opt/food-market-data/backups/uploads-YYYYMMDD-HHMMSS.tgz
# tar содержит каталог uploads/ — распаковать в родителя смонтированного пути
sudo tar xzf "$TGZ" -C /opt/food-market-data/
```
(Каталог `/opt/food-market-data/uploads` смонтирован в контейнер api как `/app/uploads`.)
## Проверка дампа без восстановления
```bash
docker cp <dump> food-market-postgres:/tmp/v.dump
docker exec food-market-postgres pg_restore --list /tmp/v.dump | head # TOC валидного архива
docker exec food-market-postgres rm -f /tmp/v.dump
```
Скрипт и формат проверены локально (2026-05-27): дамп `PGDMP`, custom-format,
248 TOC-записей, `pg_restore --list` читает.