# Deployment ## 1. Назначение документа Этот документ фиксирует platform-agnostic модель деплоя проекта. Он отвечает на вопросы: - какие deployment artifacts должны быть в репозитории; - как проект должен запускаться в production-like окружении; - как routing должен работать через reverse proxy; - что должен делать CD pipeline. Документ не привязан к конкретному hypervisor, cloud provider, типу VM или домашней инфраструктуре. Практический post-deploy smoke checklist вынесен отдельно в [deploy-and-staging-smoke.md](deploy-and-staging-smoke.md). Отдельный release checklist именно для открытой редакции вынесен в [community-release-checklist.md](community-release-checklist.md). ## 2. Базовая модель деплоя Для MVP принимается контейнерная модель: - `admin-api`, `mcp-server` и `ui` упаковываются в контейнеры; - `PostgreSQL` запускается как отдельный контейнер; - сервисы запускаются через `docker-compose`; - перед приложением находится reverse proxy; - CI проверяет качество, CD доставляет и перезапускает сервисы. ## 3. Что должно быть в репозитории В проекте должны существовать: - `Dockerfile` для `apps/admin-api`; - `Dockerfile` для `apps/mcp-server`; - `Dockerfile` для `apps/ui` или отдельный production build flow для UI; - `deploy/community/docker-compose.yml` как canonical Community deployment manifest; - `deploy/community/.env.example` как canonical Community runtime env template; - `docker-compose.yml` и root `.env.example` только как local development convenience layers, а не как future private delivery boundary; - `.gitea/workflows/ci.yml`; - `.gitea/workflows/deploy.yml`; - примеры reverse proxy конфигураций. Рекомендуемое стартовое распределение портов: - `ui` -> `3000` - `admin-api` -> `3001` - `mcp-server` -> `3002` ## 4. Production-like runtime состав Минимальный набор сервисов: - `ui` - `admin-api` - `mcp-server` - `postgres` - optional `valkey` через compose profile `cache` Persistent data: - volume для `postgres`; - volume или bind mount для `artifact storage`. ## 5. Рекомендуемая routing model Под одним доменом: - `/` -> `ui` - `/api/admin/` -> `admin-api` - `/mcp/` -> `mcp-server` Это позволяет: - централизовать TLS; - не плодить поддомены без необходимости; - держать demo URL простым; - использовать один reverse proxy для UI, API и MCP. ## 6. Требования к reverse proxy Reverse proxy должен обеспечивать: - TLS termination; - редирект `HTTP -> HTTPS`; - `X-Forwarded-*` headers; - отключение buffering для MCP endpoint; - увеличенные таймауты для долгих runtime-запросов; - корректную маршрутизацию UI, admin API и MCP. Особенно для `mcp-server` важно: - `proxy_buffering off`; - `proxy_request_buffering off`; - длинный `proxy_read_timeout`. ## 7. Пример `nginx` ```nginx server { listen 80; server_name example.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; client_max_body_size 25m; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_http_version 1.1; location / { proxy_pass http://ui:3000; } location /api/admin/ { proxy_pass http://admin-api:3001/; } location /mcp/ { proxy_pass http://mcp-server:3002/; proxy_buffering off; proxy_request_buffering off; proxy_read_timeout 300s; proxy_send_timeout 300s; } } ``` ## 8. Пример `Traefik` ```yaml services: ui: labels: - traefik.enable=true - traefik.http.routers.ui.rule=Host(`example.com`) && PathPrefix(`/`) - traefik.http.services.ui.loadbalancer.server.port=3000 admin-api: labels: - traefik.enable=true - traefik.http.routers.admin.rule=Host(`example.com`) && PathPrefix(`/api/admin`) - traefik.http.services.admin.loadbalancer.server.port=3001 mcp-server: labels: - traefik.enable=true - traefik.http.routers.mcp.rule=Host(`example.com`) && PathPrefix(`/mcp`) - traefik.http.services.mcp.loadbalancer.server.port=3002 ``` Для production нужно отдельно проверить timeout behavior на MCP маршруте. ## 9. Требования к `docker-compose` `deploy/community/docker-compose.yml` должен: - поднимать `postgres`, `admin-api`, `mcp-server`, `ui`; - использовать env vars вместо hardcoded config; - иметь persistent storage для БД и artifacts; - публиковать `ui`, `admin-api` и `mcp-server` на loopback по умолчанию; - позволять переопределить publish bind одним env для случаев, когда reverse proxy вынесен на отдельный хост; - не публиковать внутренние сервисы наружу без необходимости; - содержать healthchecks; - поддерживать optional cache profile без превращения `Valkey` в обязательную runtime dependency. Для Community optional cache layer включается отдельно: - profile: `cache` - service: `valkey` - базовый запуск без profile должен оставаться полностью рабочим Пример: ```bash docker compose \ -f deploy/community/docker-compose.yml \ --env-file deploy/community/.env.example \ --profile cache up -d ``` ## 10. Healthchecks Нужны как минимум: - `GET /health` для `admin-api` - `GET /health` для `mcp-server` CD не должен считать deployment успешным, пока эти endpoints не начали возвращать `200 OK`. ## 11. CI и CD ### 11.1. CI CI должен выполнять: - `cargo fmt --all --check` - `cargo check --workspace` - `cargo clippy --workspace --all-targets --all-features -- -D warnings` - `cargo test --workspace --all-targets` ### 11.2. CD CD для MVP должен: - запускаться только после успешного `CI` на `main` или вручную; - собирать versioned container images; - пушить их в container registry с cache; - доставлять deployment files на целевой Linux host; - выполнять controlled restart через `pull`, без сборки на сервере; - проверять health endpoints после запуска. Минимальный flow: 1. push в `main` 2. успешный `CI` 3. build and push images в registry 4. upload runtime env и deployment files 5. `docker login` на registry на целевом хосте 6. `docker compose config -q` 7. `docker compose pull` 8. `docker compose up -d` 9. healthcheck verification для `ui`, `admin-api`, `mcp-server` Для текущего проекта базовая рекомендуемая схема: - registry на том же Gitea instance; - versioned tags по `git sha`; - self-hosted Gitea Actions runner; - на сервере только `pull + restart`, без `docker compose up --build`. Для private registry на сервере нужны отдельные deployment secrets: - `DEPLOY_REGISTRY_USER` - `DEPLOY_REGISTRY_TOKEN` Они используются только для `docker login` на целевом Linux host перед `docker compose pull`. Монолитный `DEPLOY_ENV_FILE` больше не используется. Workflow доставляет именно `deploy/community/docker-compose.yml` как public Community deployment manifest и собирает `.env` на сервере из отдельных Gitea secrets. Для runtime-переменных нужно создавать secrets с теми же именами, что и у приложений: - `POSTGRES_HOST` - `POSTGRES_PORT` - `POSTGRES_DB` - `POSTGRES_USER` - `POSTGRES_PASSWORD` - `CRANK_STORAGE_ROOT` - `CRANK_PUBLISH_BIND` - `CRANK_ADMIN_BIND` - `CRANK_MCP_BIND` - `CRANK_MCP_REFRESH_MS` - `CRANK_LOG_LEVEL` - `CRANK_MASTER_KEY` - `CRANK_BASE_URL` - `CRANK_CACHE_BACKEND` - `CRANK_CACHE_URL` - `CRANK_CACHE_DEFAULT_TTL_MS` - `CRANK_SESSION_SECRET` - `CRANK_PASSWORD_PEPPER` - `CRANK_SESSION_TTL_HOURS` - `CRANK_BOOTSTRAP_ADMIN_EMAIL` - `CRANK_BOOTSTRAP_ADMIN_PASSWORD` - `CRANK_BOOTSTRAP_ADMIN_DISPLAY_NAME` - `CRANK_DEMO_SEED` Практически это означает: - одна runtime-переменная = один GitHub secret; - ротация одного секрета не требует переписывать весь набор env; - `.env` на сервере каждый deploy собирается заново из актуальных secrets. ## 11. Граница Community против future commercial delivery Community delivery path должен оставаться отдельным и воспроизводимым сам по себе. Это означает: - `deploy/community/*` — public source of truth для открытой поставки; - future `Enterprise` и `Cloud` не должны появляться как еще один `.env` на том же compose-файле; - commercial manifests и pipelines должны жить отдельно после создания private repositories. ## 12. Что нельзя забыть - TLS и renewal сертификатов; - backup для `postgres` и artifact storage; - секреты вне репозитория; - app-level auth для `admin-api` и bootstrap admin credentials в env; - rollback на предыдущий image tag или предыдущую compose revision.