- 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>
6 KiB
6 KiB
Рунбук ПРОД 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/.envchmod 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),
.envchmod 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)
- Предыдущий образ: в registry по прошлому SHA.
~/deploy-prod.sh <prev-api> <prev-web> --yes(без--build) — вернёт прежние теги (бэкап снимется автоматически до переключения). - Данные: восстановить из дампа —
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. - Проверить
/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).