План перехода проекта на docker-контур
Обновлён 1 апр. 2026 г., 12:41 · 0 комментариев
План перехода проекта на docker-контур
Паспорт документа
- Статус документа: working spec
- Актуально на: 31 марта 2026 года
- Владелец: backend/platform-команда
- Пересмотр: при изменении deploy-контура, инфраструктуры, rollback-модели или runtime topology
- Область применения: эксплуатационный и migration-слой production-инфраструктуры проекта
- Связанные документы:
Цель документа
Этот документ фиксирует профессиональный план перехода Qadam с текущего host-based runtime на управляемый docker-контур.
Под docker-контуром в этом документе понимается не просто наличие Dockerfile, а полный управляемый delivery/runtime-процесс, в котором:
- приложения собираются в версионируемые контейнерные образы;
- сервер разворачивает образы, а не исходники из git;
- деплой, rollback и smoke-проверки стандартизированы;
- frontend и backend могут релизиться независимо;
- окружение становится повторяемым для staging и production.
Ключевой вывод
Переход на docker-контур нужен, но делать его нужно поэтапно.
Правильный путь:
- Сначала контейнеризировать
web,apiиmigrate. - На первом production-переходе не трогать одновременно ingress, TLS и stateful services.
- Только после стабилизации контейнерного runtime решать, нужно ли контейнеризировать
nginx,redisиpostgres.
Попытка перевести всё сразу в контейнеры повышает риск outage без реальной пользы на первом этапе.
Текущее состояние проекта
Что уже есть
- в репозитории есть актуализированный Dockerfile для
apps/api; - в репозитории есть Dockerfile для
apps/web; - в
qadam-core/deploy/composeдобавлен первый канонический manifestdocker-compose.api-runtime.ymlдляapi,migrateиseed; - для
qadam-core/apiуже добавлены канонические helper scriptsdeploy/scripts/build-api-image.shиdeploy/scripts/smoke-api-runtime-compose.sh, которые стандартизируют image tag и compose-based shadow smoke на текущем host runtime; - для
qadam-core/apiуже подтверждён рабочий registry namespacegit.2fab.app/eldar/qadam-core-api, а publish/pull контур больше не держится на ручномdocker tag && docker push; - для
qadam-webуже добавлены лёгкий runtimeDockerfile,.dockerignore, compose manifestdeploy/compose/docker-compose.web-runtime.ymlи helper scriptsdeploy/scripts/build-web-image.sh,deploy/scripts/publish-web-image.sh,deploy/scripts/smoke-web-runtime-compose.sh; - для
qadam-webуже подтверждён рабочий registry namespacegit.2fab.app/eldar/qadam-web-app, а registry-backed shadow smoke проходит на127.0.0.1:3002без локальногоnext buildна production-хосте; - в корне лежит legacy
docker-compose.yml; - у приложения есть health endpoints;
- на сервере уже установлен Docker Engine, а его
data-rootвынесен в/mnt/qadam100gb/docker.
Что является реальным production-состоянием
На текущем сервере production сейчас работает в смешанном runtime-контуре:
- публичный
qadam-apiуже переведён наqadam-api-container.serviceи обслуживается container runtime на127.0.0.1:5002; - legacy
qadam-api.serviceоставлен установленным как rollback-контур на127.0.0.1:5001; qadam-webзапущен какsystemd-сервис;- для
qadam-webуже существует проверенный shadow runtime на127.0.0.1:3002, но production upstream пока остаётся на host-levelqadam-web.service; nginxработает на хосте;- PostgreSQL и Redis работают вне Docker;
- Docker Engine присутствует и уже используется как production runtime для
api, ноwebи roadmap-сервис пока ещё не переведены на container delivery.
Что это означает
- текущий
docker-compose.ymlи Docker-артефакты не являются каноническим runtime-контуром production; - production всё ещё частично зависит от
git pull, локальной сборки на сервере и host-level состояния из-заqadam-webи roadmap-сервиса; - rollback для
apiуже стандартизирован по image tag и nginx upstream, но общий rollback-контур ещё не унифицирован для всех приложений; - будущий вынос frontend в отдельную репу без docker-контура будет неполным с точки зрения delivery.
- при этом backend API уже прошёл дальше baseline: image публикуется в registry,
qadam-api-container.serviceреально обслуживает production-трафик, а host nginx использует named upstreamqadam_api_backend.
Почему проекту нужен docker-контур
1. Повторяемость окружения
Контейнерный runtime уменьшает расхождения между локальной разработкой, staging и production.
2. Иммутабельный деплой
Сервер должен получать не исходники, а конкретный образ с тегом. Это делает rollout и rollback предсказуемыми.
3. Разделение frontend и backend delivery
После выноса frontend в отдельную репу обе части должны поставляться независимо. Контейнерные образы лучше всего подходят для такого разделения.
4. Упрощение инфраструктурной автоматизации
С docker-контуром проще строить:
- image build;
- registry-based deploy;
- healthcheck orchestration;
- preview/staging среды;
- контролируемый rollback.
Принципы миграции
1. Не мигрировать stateful и stateless слои в один шаг
Stateless-сервисы:
webapimigrate
Stateful-сервисы:
- PostgreSQL
- Redis
- TLS state
- persistent storage
На первом этапе мигрируем только stateless-сервисы.
2. Репозиторий и runtime должны быть разделены
После перехода сервер не должен собирать приложение из рабочего дерева /data/uzbek. Production должен получать только image tag и env.
3. Один источник истины по деплою
Сейчас в проекте смешаны host runtime и Docker-артефакты. После migration должен остаться один канонический путь деплоя.
4. Rollback обязан быть проще, чем сейчас
Если после перехода rollback не становится проще, migration сделан неправильно.
5. Secrets и object storage credentials остаются runtime-only
- production secrets не должны попадать в
Dockerfile, image layers или git-managed compose manifests; - credentials для PostgreSQL, Redis, JWT, Telegram и будущего S3/object storage должны передаваться только через runtime env/secrets;
- переход на docker-контур не меняет это правило, а делает его строже.
Рекомендуемое целевое состояние
Этап 1. Практический docker-контур
Рекомендуемая первая целевая модель:
Internet
-> Host Nginx
-> web container
-> api container
Host / Managed services:
- PostgreSQL
- Redis
- Let's Encrypt / certbot
Это лучший первый этап, потому что:
- минимальный риск;
- не ломает текущий ingress;
- не требует одновременно переносить TLS;
- позволяет сразу перейти на image-based delivery;
- полностью совместим с отдельным frontend-репозиторием.
Этап 2. Расширенный docker-контур
После стабилизации можно отдельно решить:
- переносить ли
redisв контейнер; - переносить ли
nginxв контейнер; - нужен ли контейнерный
certbot; - есть ли смысл переносить PostgreSQL в Docker или правильнее оставить его host-managed / managed service.
Рекомендация по PostgreSQL
Для production не рекомендуется переносить PostgreSQL в Docker в тот же пакет работ, где проект впервые переводится на контейнерный runtime приложений.
Связь с выносом frontend в отдельную репу
Переход на docker-контур и вынос frontend в отдельную репу должны быть согласованы.
Итоговая модель должна быть такой:
- backend-репозиторий собирает свой образ
api; - frontend-репозиторий собирает свой образ
web; - серверный deploy-контур разворачивает оба образа независимо;
- ingress остаётся единым и маршрутизирует
/api/*и/*.
То есть repo split и docker-контур не заменяют друг друга, а дополняют.
Фаза 0. Инвентаризация и нормализация
Цель
Понять, какие Docker-артефакты уже пригодны, а какие являются legacy.
Работы
- Проверить актуальность Dockerfile для
apiиweb. - Проверить совпадение healthchecks и реальных runtime endpoints.
- Проверить env matrix:
- build-time env;
- runtime env;
- secrets;
- hostnames;
- internal URLs.
- Зафиксировать, что именно остаётся на host-level в первой фазе migration.
Результат фазы
- понятен реальный scope docker-перехода;
- отделены актуальные артефакты от legacy.
- для
apiэта фаза фактически закрыта: Dockerfile и runtime assumptions уже пересмотрены и подтверждены первым smoke.
Фаза 1. Канонический container runtime для приложений
Цель
Подготовить production-ready контейнерный runtime для web, api и migrate.
Работы
- Канонизировать Dockerfile:
- reproducible build;
- runtime user;
- health endpoints;
- стартовые команды;
- migrations.
- Подготовить канонический deployment manifest.
- Рекомендуется вынести production deploy manifests из корня в отдельный каталог, например:
deploy/
compose/
docker-compose.runtime.yml
env/
scripts/
- Убрать неоднозначность между старым и новым docker-контуром.
- Зафиксировать image naming и tagging strategy.
Результат фазы
- есть канонический runtime manifest;
apiуже можно поднять только из образа и env, а compose-based shadow smoke подтверждает этот runtime на текущем production-хосте без cutover;- для
apiуже существует source-controlled reversible cutover path и live production-трафик переведён на container runtime; - для
webуже подтверждены build/publish/pull и registry-backed shadow smoke, но production cutover и rollback-процедура ещё не доведены до канонического состояния.
Фаза 2. CI/CD для образов
Цель
Сделать доставку на сервер image-based.
Работы
- Настроить сборку и push образов в registry.
- Развести pipeline для
webиapi. - Добавить post-build smoke:
- image собирается;
- container стартует;
- health endpoint отвечает.
- Настроить deploy pipeline, который:
- выбирает image tag;
- обновляет runtime manifest/env;
- поднимает контейнеры;
- запускает smoke-check;
- даёт понятный rollback path.
Результат фазы
- сервер получает образы из registry;
- деплой перестаёт зависеть от локальной сборки на production-хосте.
- Для
apiэтот слой уже подтверждён end-to-end: registry push, registry pull smoke и production cutover runtime работают. - Для
webэтот слой уже подтверждён частично: registry publish/pull и shadow smoke работают, но пока не автоматизированы repo-side CI и не доведены до production cutover.
Фаза 3. Подготовка сервера
Цель
Подготовить production-машину к контейнерному runtime без выключения сервиса.
Работы
- Установить Docker Engine и Compose plugin.
- Подготовить каталоги runtime-контура:
- env;
- compose manifests;
- volumes, если нужны.
- Подготовить host nginx к проксированию на container ports.
- Подготовить rollback-путь обратно на
systemd, пока cutover не завершён.
Результат фазы
- сервер готов к запуску контейнеров;
- старый runtime ещё не выключен полностью.
- На 31 марта 2026 года эта фаза практически закрыта для
api:- Docker Engine установлен;
data-rootпереведён на/mnt/qadam100gb/docker;- host nginx умеет переключать
qadam_api_backendмежду5001и5002; qadam-api-container.serviceи/etc/qadam/qadam-api-runtime.envуже используются в production;- host-level
systemdruntime остаётся каноническим production-контуром только дляqadam-webиqadam-roadmap.
Фаза 4. Staging и предбоевой прогон
Цель
Проверить docker-контур до production cutover.
Работы
- Поднять docker-runtime в staging или на отдельном server profile.
- Проверить:
webhealth;apihealth;- migrations;
- login / refresh / logout;
- seller flow;
- buyer flow;
- roadmap portal.
- Проверить restart policy, логи и наблюдаемость.
Результат фазы
- docker-контур подтверждён на реальных сценариях;
- production cutover можно выполнять без гадания.
Фаза 5. Production cutover
Цель
Перевести production на container runtime приложений.
Работы
- Зафиксировать рабочий image tag для
webиapi. - Подготовить container runtime целиком.
- Остановить старый
systemdruntime приложений только после готовности container runtime. - Переключить nginx на новые upstream.
- Выполнить smoke-check:
GET /api/v1/health- главная страница web
- login
- refresh
- roadmap portal
- Для
apiсчитать этот шаг уже практически пройденным: production обслуживается черезqadam-api-container.service, а финальный смысл фазы теперь смещён наwebи общую унификацию app runtime.
Результат фазы
- production работает на container runtime приложений;
- host-based app runtime больше не является каноническим способом запуска.
Фаза 6. Постмиграционная зачистка
Цель
Убрать legacy-контур и зафиксировать новый источник истины.
Работы
- Обновить runbook.
- Удалить или архивировать устаревшие host-only deploy steps.
- Удалить неоднозначные скрипты и старые инструкции.
- Зафиксировать новую rollback-процедуру.
- Добавить регулярный smoke script и мониторинг.
- Для
apiвынести legacyqadam-api.serviceиз статуса равноправного runtime и оставить его только как временный rollback path до полного закрытияCP-301.
Результат фазы
- команда больше не путается между двумя способами деплоя;
- новый docker-контур становится единственным каноническим runtime.
Что нужно решить до старта migration
Перед стартом нужно принять явные решения по этим вопросам:
- Оставляем ли
nginxна хосте на первом этапе. - Оставляем ли PostgreSQL и Redis на хосте или за пределами Docker.
- Где будут жить production env и secrets.
- Какой registry канонический для образов.
На 31 марта 2026 года уже подтверждены два namespace в Gitea Container Registry:
git.2fab.app/eldar/qadam-core-apigit.2fab.app/eldar/qadam-web-app
- Какой manifest будет источником истины.
- Кто владеет cutover и кто утверждает rollback.
Основные риски
1. Одновременный перенос приложений, базы и ingress
Это самый частый путь к неуправляемому cutover. Его нужно избегать.
2. Ложное чувство готовности из-за наличия Dockerfile
Наличие Dockerfile ещё не означает наличие production-ready docker-контура.
3. Сохранение старого способа деплоя как “альтернативного”
Если после migration останутся равноправными и systemd, и Docker, команда быстро снова начнёт деплоить “кто как привык”.
4. Сервер продолжает собирать код из git
Если server всё ещё делает git pull && pnpm build, migration не завершён.
5. Отсутствие rollback по image tag
Если rollback требует ручной пересборки, значит image-based deployment не доведён до конца.
Критерии успеха
Переход на docker-контур считается завершённым, только если одновременно выполняются условия:
- production
webиapiработают в контейнерах; - сервер не собирает приложение из исходников;
- deploy выполняется по image tag;
- rollback выполняется по image tag;
- runbook описывает только новый канонический процесс;
- smoke-check после деплоя автоматизирован хотя бы на базовом уровне;
- frontend и backend можно выкатывать независимо.
Практический рекомендуемый порядок
- Канонизировать Docker runtime для
web,api,migrate. - Поднять image-based CI/CD.
- Установить Docker на сервер и подготовить host nginx.
- Прогнать staging.
- Сделать production cutover для приложений.
- Только после этого обсуждать контейнеризацию ingress, Redis и PostgreSQL.
Что делать не надо
- Не переносить PostgreSQL в Docker в тот же пакет, где впервые контейнеризируются приложения.
- Не менять одновременно repo split, auth model и runtime model.
- Не сохранять
git pullна production как нормальный путь обновления. - Не держать несколько равноправных production-контуров без чёткого статуса
legacy. - Не считать существующий
docker-compose.ymlканоническим только потому, что он уже лежит в репозитории.
Рекомендуемый следующий шаг
Следующим инженерным пакетом нужно не “включить Docker на сервере”, а развить уже начатый app-level docker-контур:
- считать
apibaseline уже канонизированным и не тратить новый пакет на повторное изобретение того же контура; - считать для
webзакрытыми build/publish/pull и shadow smoke, а следующий пакет направить уже на production cutover; - перевести
qadam-webна image-based production runtime и затем выровнять общий rollback/runbook; - только после этого начинать cutover с host
systemdна container runtime.