food-market/docs/prod-runbook.md
nns b49abfdbd7
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
feat(prod): запуск admin.food-market.kz — бэкапы (hourly/daily/офсайт), restore-verify, мониторинг, deploy-prod
- prod-backup.sh (tier hourly 48ч / daily 30д + uploads), prod-backup-offsite-pull.sh (DR на dev-vm)
- prod-restore-verify.sh: restore во временную БД + сверка числа строк, дроп
- prod-monitor.sh: api/web/public/БД/диск/5xx → Telegram владельцу (+ --test)
- deploy-prod.sh: guard'ы (prod-postgres, .env chmod600, не dev-пароль, quick-login off,
  SEED_DEMO_DATA=false, issuer), бэкап ДО миграций, только --yes, НЕ в ночных
- systemd таймеры (backup-hourly/daily, monitor, offsite-pull); docs/prod-runbook.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 19:31:55 +05:00

6 KiB
Raw Blame History

Рунбук ПРОД admin.food-market.kz (ALL MARKET)

Боевой сервер магазина. Прод-vm 192.168.1.190, compose ~/food-market/deploy, своя БД food-market-prod-postgres:5437 (НЕ shared-postgres!). gateway nginx (на хосте, только читать) проксирует admin.food-market.kz → :8081 (web). Публичный сайт food-market.kz — НЕ трогаем.

Чек-лист готовности (выполнено 09.10.2026)

  • Образы — релизные теги (SHA main, не test/latest): API_TAG/WEB_TAG в .env.
  • Секреты прода отдельны от стенда, в ~/food-market/deploy/.env chmod 600:
    • POSTGRES_PASSWORD — сильный (НЕ dev-дефолт). БД своя (5437).
    • OPENIDDICT_ISSUER=https://admin.food-market.kz/. OpenIddict PFX-ключи генерируются на сервере в томе food-market-api-data (очищен перед стартом → свежие прод-ключи, отдельные от стенда/dev). OPENIDDICT_CERT_PASSWORD пуст (ключи защищены правами ФС).
    • SEED_SUPERADMIN_PASSWORD — временный, см. ниже.
    • VAPID (web-push) — автогенерация в БД (PlatformSettings), секрет не нужен.
    • SMTP — НЕ настроен (задаёт владелец; до настройки сброс пароля по email неактивен).
  • Выключено на проде: quick-login (QUICK_LOGIN_ENABLED=false + code safety-override по issuer), стендовые подсказки, демо-сидеры и тест-орги (SEED_DEMO_DATA=false → нет «Demo Market»).
  • SuperAdmin admin@food-market.local — пароль из SEED_SUPERADMIN_PASSWORD; копия пароля: ~/.fm-watchdog/prod-superadmin-initial.txt (chmod 600) на dev-vm. ⚠ Владелец ОБЯЗАН сменить пароль при первом входе (UI → профиль). Рекомендуется также завести персональный аккаунт.
  • Проверено: вход SuperAdmin через https://admin.food-market.kz = HTTP 200; БД пуста (orgs=0, products=0, users=1=SuperAdmin, roles=4 системных); web SPA = 200; quick-login = 404.

Деплой прода (ТОЛЬКО вручную)

~/deploy-prod.sh --yes                 # взять теги из прод .env, backup → up
~/deploy-prod.sh <api> <web> --yes --build   # пересобрать+push+деплой с новыми тегами
  • Скрипт с guard'ами: проверяет что compose = food-market-prod-postgres (не shared-postgres), .env chmod 600, НЕ dev-пароль БД, quick-login off, SEED_DEMO_DATA=false, issuer прод.
  • Делает бэкап БД ДО pull/миграций. Миграции применяются автоматически при старте api (AppDbContext.Database.Migrate() → /health/ready = Healthy только после миграций).
  • Поднимает postgres api web (public НЕ трогает). НЕ в ночных задачах.

Бэкапы и восстановление

  • Ежечасно (хранение 48 ч): food-market-backup-hourly.timer → /opt/food-market-data/backups/hourly.
  • Ежедневно 03:30 (хранение 30 дн + uploads): food-market-backup-daily.timer → …/backups/daily; ExecStartPost — автопроверка восстановления.
  • Офсайт (другая VM): dev-vm таймер food-market-offsite-pull.timer (04:00) тянет последний daily-дамп на dev-vm ~/fm-prod-backups (хранение 30 дн).
  • Формат — pg_dump -Fc (pg_restore с параллелизмом/выборочно).
  • Проверка восстановления (вручную): ~/food-market/deploy/prod-restore-verify.sh — restore последнего дампа во временную БД food_market_restore_test + сверка числа строк с боевой + дроп временной. Боевую БД не трогает. Проверено 09.10: все ключевые таблицы совпали.

Мониторинг

  • food-market-prod-monitor.timer (каждые 5 мин): api /health/ready, web, публичный вход, БД (pg_isready), место на диске (порог 85%), 5xx в логах api за 5 мин. При проблеме — Telegram владельцу (бот: ~/.fm-watchdog/telegram-{token,chat} на prod-vm). Лог: ~/.fm-watchdog/prod-monitor.log.
  • Тест уведомления: ~/food-market/deploy/prod-monitor.sh --test (отправлено 09.10 ✓).

Откат (rollback)

  1. Предыдущий образ: в registry по прошлому SHA. ~/deploy-prod.sh <prev-api> <prev-web> --yes (без --build) — вернёт прежние теги (бэкап снимется автоматически до переключения).
  2. Данные: восстановить из дампа — docker exec -i food-market-prod-postgres pg_restore -U food_market -d food_market --clean --if-exists < <дамп> (на пустую/битую БД; при живой — сначала остановить api). Дампы: /opt/food-market-data/backups/{hourly,daily} или офсайт dev-vm ~/fm-prod-backups.
  3. Проверить /health/ready и вход. Если проблема в миграции — откат образа на прошлый SHA (миграции в этом проекте аддитивные; down-миграции не применяем на проде).

НЕ трогать

shared-postgres (5434) и его базы (sklad/purchase/calcman/makesales); gateway nginx (только чтение); стенд (test.admin.food-market.kz); публичный сайт food-market.kz (контейнер public, PUBLIC_TAG=test).