Головна/Експлуатація/Деплой ENУКРРУС API-довідник (ReDoc) ↗

Деплой

Де це працює, як відбувається деплой і що робити, коли він падає.

Топологія

languages.service.custom.mt на спільному хості сервісів, за спільним edge-проксі Caddy.

Інтернет ──▶ Caddy (:443, /opt/caddy)
                └─ languages.service.custom.mt ──▶ language-service:8000
                                                        └─▶ postgres (свій контейнер, свій том)

Сервіс має власний Postgres — у власному compose-стеку, з власним томом. Він не має з'єднання з базою легасі-консолі в жоден момент: та база читається рівно один раз, вручну, щоб зібрати сід. Див. Rebuilding the Seed.

Усе живе в /opt/language-service/ на хості: docker-compose.prod.yml, .env і том Postgres.

Автодеплой

Пуш у main → CI → збірка → деплой, через .github/workflows/.

  1. CI — ruff, mypy, pytest проти SQLite і Postgres, перевірка цілісності сіду, збірка Docker-образу зі smoke-тестом.
  2. Build — образ linux/arm64 у ghcr.io/custommt/language_service, теги — SHA коміту й latest. Хост на Graviton; образ лише під amd64 впав би з «exec format error».
  3. Deploy — по SSH: синк compose і Caddy-файлів, pull, alembic upgrade head, сід, рестарт, очікування health-гейта, reload Caddy.

Керується змінною репозиторію DEPLOY_ENABLED=true. Секрети: DEPLOY_HOST, DEPLOY_USER, DEPLOY_SSH_KEY.

Сід виконується на кожному деплої

python -m app.cli seed ідемпотентний і працює як upsert: зіставляє рядки за природними ключами, оновлює на місці й ніколи не видаляє. Правки в адмінці для рядків, про які сід не знає, лишаються недоторканими. Але закріплений код, про який сід знає, буде скинутий до засіяного значення — тож виправлення, задумане як постійне, має бути в сіді, а не лише в панелі.

Конфігурація

Змінна Обов'язкова Примітки
DATABASE_URL так postgresql+asyncpg://…
APP_ENV так production на сервері
ADMIN_USERNAME так
ADMIN_PASSWORD_HASH_FILE так file holding the argon2id hash — see Admin Panel
ADMIN_SECRET_KEY_FILE так openssl rand -hex 48 into a file
ADMIN_ENABLED ні false прибирає панель повністю
DOCS_ENABLED ні Swagger UI. /redoc і /wiki публічні завжди
CACHE_TTL_SECONDS ні дефолт 300

З APP_ENV=production і увімкненою адмінкою відсутній ADMIN_SECRET_KEY чи ADMIN_PASSWORD_HASH — це помилка старту. Секрети генеруються на сервері й ніколи його не покидають.

Health

Проба Перевіряє Для чого
/health нічого — процес живий liveness контейнера
/health/ready база доступна, каталог непорожній гейт деплою, балансувальник

Readiness падає, коли міграції пройшли, а сід — ні: порожній каталог відповідав би 404 на все.

Експлуатація

cd /opt/language-service

docker compose -f docker-compose.prod.yml logs -f api
docker compose -f docker-compose.prod.yml run --rm api python -m app.cli stats
docker compose -f docker-compose.prod.yml run --rm api python -m app.cli resolve deepl_api pt_BR

# ротація пароля адміна
docker compose -f docker-compose.prod.yml run --rm api python -m app.cli hash-password
# → вставити в .env, далі:
docker compose -f docker-compose.prod.yml up -d api

Логи — один JSON-об'єкт на рядок: event, level і поля події. Рядки запитів несуть correlation_id.

Відкат

Задеплойте попередній тег образу:

cd /opt/language-service
sed -i "s|^IMAGE=.*|IMAGE=ghcr.io/custommt/language_service:<sha>|" .env
docker compose -f docker-compose.prod.yml up -d api

Міграції адитивні, тож один реліз назад не потребує downgrade.

Коли деплой падає

Симптом Що дивитись
Контейнер unhealthy logs api — зазвичай DATABASE_URL або відсутній секрет адмінки
/health/ready 503, catalog: false сід не виконався: run --rm api python -m app.cli seed
502 від Caddy контейнер не в мережі edge, або site-файл не синкнувся
TLS не видався DNS: *.service.custom.mt має резолвитись на хост

Далі