# Бэкап и восстановление Артефакты в репозитории (`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-.dump` (custom-format) | | Загруженные файлы (картинки товаров) | `tar czf` каталога uploads | `uploads-.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 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` читает.