Развёртывание
Базовый способ развёртывания проекта — docker compose. Структура и правила повторяют подход, который уже используется в crewnaut: отдельный слой для портов, отдельный слой для app/deploy-настроек, compose-файлы в deploy/docker/, запуск через Makefile, единая named network для межсервисной коммуникации.
Идентификаторы среды
| Параметр | Значение |
|---|---|
| Project name | tracium |
| Display name | Tracium |
| Production base domain | tracium.ru |
| Local testing base domain | tracium.dev |
| Compose project name | tracium |
Структура deploy-контура
/
├── .env.example # централизованные host ports и compose project name
├── Makefile # команды запуска и диагностики compose-стека
└── deploy/
├── .env.example # app settings, DSN, domains, credentials for local setup
├── auth/.env.example # auth-specific env для shared/auth
└── docker/
├── docker-compose.yml # базовый infra stack
├── docker-compose.dev.yml # локальный override с публикацией портов
├── docker-compose.web.yml # локальный HTTPS ingress + docs/api/auth/web
└── resources/
├── clickhouse/init/
├── certs/
├── docs/
├── go-dev/
├── nginx-local/
└── otel-collector/
Принципы развёртывания
- Один compose-stack на среду. На старте не используем Helm/Kubernetes.
- Порты отделены от app-конфига. Host ports лежат в
/.env, домены/DSN/секреты вdeploy/.env. - Auth-конфиг отделён от общего deploy-конфига.
deploy/auth/.envхранит только параметрыshared/auth. - Compose-файлы хранятся в
deploy/docker/. Это единая точка входа для локальной среды и production-like stack. - Внутренние вызовы идут по compose network. Сервисы общаются по DNS-именам контейнеров, а не по host ports.
- Все stateful сервисы имеют named volumes.
- Сервисы перезапускаются через
restart: unless-stopped. - На stateful компонентах обязательны healthcheck’и.
- Секреты в локальной среде идут через
deploy/.env; prod backend для master key может быть env, KMS или Vault Transit.
Базовый compose-stack
deploy/docker/docker-compose.yml поднимает общую инфраструктуру проекта:
- PostgreSQL — primary store и event store.
- Redis — rate limiter, locks, cache.
- Kafka — event bus.
- Kafka UI — локальная диагностика топиков.
- MinIO — S3-совместимое хранилище raw payloads и media.
- ClickHouse — история цен/остатков и аналитика.
- Elasticsearch — полнотекстовый и faceted search.
- OTel Collector — приём OTLP telemetry.
traciumnetwork — общая внутренняя сеть для infra и будущих прикладных сервисов.
deploy/docker/docker-compose.dev.yml поверх базового файла публикует host ports для локальной разработки и тестирования.
Коммуникация в рантайме
- Внутренние DSN и URLs всегда указывают на service DNS внутри compose:
postgres:5432,redis:6379,kafka:9092,catalog-core:8080. - Host ports (
25432,29092,19200, …) существуют только для человека, IDE, браузера и локальных CLI. - Новые сервисы обязаны подключаться к общей сети
traciumи не должны зависеть отlocalhostвнутри контейнера. - Исключение для Kafka: single-node KRaft broker и controller живут в одном
контейнере, поэтому внутренний
KAFKA_CONTROLLER_QUORUM_VOTERSуказывает наlocalhost:9093. Это не является межсервисным endpoint; все клиенты и сервисы продолжают использовать compose DNSkafka:9092.
Конфигурация
1. Центральные порты
/.env содержит только host ports и COMPOSE_PROJECT_NAME.
Примеры переменных:
POSTGRES_PORTREDIS_PORTKAFKA_PORTMINIO_API_PORTCLICKHOUSE_HTTP_PORTELASTICSEARCH_HTTP_PORT
2. App и deploy settings
deploy/.env содержит:
- имя проекта и display name;
- production и local base domains;
- DSN и параметры infra-сервисов;
- credentials локального окружения;
- bucket names и внутренние service endpoints.
deploy/auth/.env содержит:
APP_AUTH_HOST,APP_COOKIE_DOMAIN,APP_AUTH_COOKIE_DOMAIN;APP_MONGO_DSN,APP_AMQP_DSN;APP_JWT_SECRET;- CORS и anonymous JWT настройки
shared/auth.
Команды
make git-init
cp .env.example .env
cp deploy/.env.example deploy/.env
cp deploy/auth/.env.example deploy/auth/.env
make infra-up
make verify-compose
make infra-status
make infra-logs
make infra-downProduction и локальный нейминг
tracium.ru— production base domain.docs.tracium.ru— production docs domain.api.tracium.ru— production API domain.tracium.dev— локальный base domain для тестирования и ingress hosts.- На локальном ingress уже закреплены
tracium.dev,docs.tracium.dev,api.tracium.dev,id.tracium.dev. - API ingress проксирует запросы на Go API без переписывания путей. Публичные
клиентские endpoints (
/v1/*) и внутренние compatibility endpoints (/api/v1/*) регистрируются в Go-коде явно.
Production hosting
Текущее фактическое состояние production-хоста, доменов, runtime-state и systemd units вынесено в отдельный runbook:
Production-контур теперь живёт за системным nginx на хосте, а не за container ingress на :8444. Внешний nginx держит 80/443, TLS и reverse-proxy rules, а tracium публикует только loopback host ports для blue/green slot’ов.
Почему production ingress вынесен на хост
- сертификаты и домены централизованы в одном системном
nginx; server1c.1-fb.ruостаётся обычным plain-HTTP proxy на192.168.1.190и не зависит от deploy циклаtracium;- reload host
nginxделается без restart и без обрыва активных соединений; - blue/green переключает только upstream snippet, а не весь ingress-контур.
Состав production stack
deploy/docker/docker-compose.prod-bluegreen.yml поднимает один color-slot tracium:
web— статический web на loopback port18180или18280;docs— Quartz docs на loopback port18181или18281;api— Go API на loopback port18182или18282.
shared/auth живёт отдельным стеком и публикуется на loopback port 18183 или 18283.
Системный nginx использует snippet tracium-active-upstreams.conf, который указывает на активные loopback ports для:
tracium.rudocs.tracium.ruapi.tracium.ruid.tracium.ru
Production env
Для production используются две env-группы:
- корневой env:
COMPOSE_PROJECT_NAME,TRACIUM_*_HOST_PORT; deploy/.env:APP_PROD_BASE_DOMAIN,APP_PROD_DOCS_DOMAIN,APP_PROD_API_DOMAIN,APP_PROD_ADMIN_DOMAIN.
Сгенерировать production env можно скриптом:
APP_PROD_BASE_DOMAIN=tracium.ru \
APP_PROD_DOCS_DOMAIN=docs.tracium.ru \
APP_PROD_API_DOMAIN=api.tracium.ru \
sh ./scripts/render_production_env.sh /tmp/tracium-root.env /tmp/tracium-deploy.envПроверка конфига:
sh ./scripts/verify_compose.sh prodverify_compose.sh — единая точка валидации compose-конфигов, используется и CI (compose-validate job), и make verify-prod-compose. Режимы: dev, prod, all.
Production deploy — пошаговый flow
Весь production deploy запускается одним скриптом deploy/production-runtime/bin/deploy-full.sh, который CI-job deploy-production вызывает из ci-deploy runner’а, работающего на production-хосте. Скрипт оркестрирует 9 шагов:
sequenceDiagram participant CI as CI runner participant DF as deploy-full.sh participant Git as repo.git (bare) participant FS as filesystem<br/>($DEPLOY_ROOT) participant NG as host nginx participant App as tracium-{color} CI->>DF: sh deploy-full.sh DF->>FS: resolve-color.sh → CURRENT_COLOR / NEXT_COLOR DF->>Git: checkout-release.sh (git fetch + worktree add) Git-->>FS: releases/<sha> (worktree) DF->>FS: render_production_env.sh → .deploy/*.env DF->>FS: cp *.env → shared/ DF->>App: deploy-tracium-color.sh NEXT_COLOR (compose up) DF->>NG: render-nginx-upstreams.sh → snippet DF->>NG: install snippet → /etc/nginx/snippets/ DF->>NG: nsenter + nginx -t + systemctl reload nginx DF->>App: verify-public-endpoints.sh (HTTP smoke) alt smoke OK DF->>FS: echo NEXT_COLOR > tracium.active DF->>FS: ln -sfn releases/<sha> current opt CURRENT != NEXT DF->>App: retire-tracium-color.sh CURRENT_COLOR end DF->>FS: prune-releases.sh (keep 5) else smoke fails DF->>NG: render snippet for CURRENT_COLOR + reload DF->>CI: exit 1 (rollback) end
Привязка шагов к скриптам
| Шаг | Скрипт | Ответственность |
|---|---|---|
| 1. Resolve color | resolve-color.sh | Читает runtime-state/tracium.active, вычисляет NEXT_COLOR |
| 2. Checkout release | checkout-release.sh | git fetch в repo.git + git worktree add --detach releases/<sha> |
| 3. Render env | scripts/render_production_env.sh | Генерирует tracium-root.env и tracium-deploy.env |
| 4. Stage env | cp в deploy-full.sh | Копирует env в shared/ для compose |
| 5. Up new color | deploy-tracium-color.sh | docker compose up -d --build нового color-slot’а |
| 6. Render nginx snippet | render-nginx-upstreams.sh | Собирает tracium-active-upstreams.conf для NEXT_COLOR |
| 7. Install + reload nginx | nsenter → nginx -t + systemctl reload nginx | Применяет snippet в host-side nginx |
| 8. Smoke check | verify-public-endpoints.sh | HTTP-проверка 5 публичных endpoints |
| 9a. Promote (при успехе) | записывает tracium.active, симлинк current, retire-tracium-color.sh, prune-releases.sh | Фиксирует переключение |
| 9b. Rollback (при падении smoke) | повторный render+reload для CURRENT_COLOR | Возвращает active upstream |
restore-active-upstreams.sh — отдельный host-side скрипт, который пересобирает snippet и reload’ит nginx после reboot (не часть deploy flow, но использует те же runtime-state файлы).
Blue/green runtime state
- активный color
traciumхранится в/home/belkanov/apps/runtime-state/tracium.active; - активный color
shared/authхранится в/home/belkanov/apps/runtime-state/shared-auth.active; - renderer
deploy/production-runtime/bin/render-nginx-upstreams.shумеет собирать mixed-конфигурацию, гдеtraciumиidмогут быть в разных color-slot’ах; - host-side script
deploy/production-runtime/bin/restore-active-upstreams.shпересобирает snippet и делаетsystemctl reload nginxпосле reboot.
Release layout on host
/home/belkanov/apps/
├── runtime-state/
│ ├── tracium.active
│ └── shared-auth.active
├── production-runtime/
├── tracium/
│ ├── repo.git/ # персистентный bare git-репо (object store)
│ ├── current -> releases/<sha>
│ ├── releases/<sha> # git worktree, детачнутая на <sha>
│ └── shared/
│ ├── tracium-root.env
│ └── tracium-deploy.env
└── shared-auth/
├── current -> releases/<sha>
├── releases/<sha>
└── shared/.envRelease материализуется не rsync’ом, а через git worktree из repo.git:
- при первом деплое
repo.gitсоздаётсяgit clone --bare; - каждый следующий deploy делает
git fetch+git worktree add --detach releases/<sha> <sha>; - устаревшие релизы чистятся
prune-releases.shчерезgit worktree remove, а неrm -rf.
Плюс подхода: нет дубликатов исходников между runner’ом и хостом, релиз ровно соответствует git SHA, объектный store переиспользуется между релизами (incremental fetch).
Локальный web ingress (HTTPS :4444)
Локальный web-контур поднимается отдельным docker-compose.web.yml. Он публикует проект через TLS на порту 4444 и использует один ingress nginx:
| Домен | Что | Upstream |
|---|---|---|
https://tracium.dev:4444 | placeholder landing | web (nginx static) |
https://docs.tracium.dev:4444 | документация через Quartz v4 (livereload + граф связей) | docs (Node.js 22 + Quartz) |
https://api.tracium.dev:4444 | минимальный dev API | api (Go stdlib + hot reload) |
https://id.tracium.dev:4444 | Tracium ID на базе shared/auth | auth (/Users/belkanov/projects/shared/auth) |
Предусловия
-
/etc/hosts:127.0.0.1 tracium.dev docs.tracium.dev api.tracium.dev id.tracium.dev -
opensslдоступен локально.make ssl-initгенерирует self-signed сертификаты по шаблону изgarmony. -
SHARED_WORKSPACEвdeploy/.envуказывает на каталог общего репозитория:/Users/belkanov/projects/shared. -
Для проверки без изменения
/etc/hostsможно использовать./scripts/verify_local_web.sh— он применяетcurl --resolve.
Запуск
make init-env
make ssl-init
make web-upПроверка:
make verify-local-webЕсли hosts уже настроен, документация открывается в браузере по https://docs.tracium.dev:4444/.
Остановка и очистка
make web-down
make web-clean
make web-status
make web-logs SERVICE=nginxAuth flow (anonymous JWT)
- Для
tracium.dev,docs.tracium.dev,api.tracium.devnginx выполняетauth_request→http://auth:8080/auth/nginx. shared/authлибо валидирует пришедший JWT, либо выпускает anonymous JWT.- Nginx выставляет
Set-Cookie: jwt=...; Domain=.tracium.devклиенту и прокидываетjwt/jwt_refreshheaders в upstream. id.tracium.dev— безauth_request, чтобы избежать loop.
Это — фундамент для будущего typed-claim flow (роли, реальные customer’ы). Миграция на типизированные claims не требует переделки proxy-слоя.
Docs (Quartz v4)
- Движок: Quartz v4 — SSG на Preact/TypeScript поверх канонического markdown.
- Почему: граф связей (Obsidian-style), backlinks, дерево explorer, тёмная/светлая тема, KaTeX, Mermaid, поиск, RSS — всё из коробки.
- Content directory: bind-mount
docs/docs/ → /quartz/content(read-only). - Homepage:
docs/docs/index.md. - Конфиг:
deploy/docker/resources/docs-quartz/quartz.config.ts+quartz.layout.ts. - Static build для CI/Pages:
./scripts/build_quartz_site.sh public.
Hot reload
docs: Quartzbuild --serve→ incremental rebuild при изменении markdown вdocs/docs/+ livereload WebSocket → nginxproxy_http_version 1.1; Upgrade.- Изменения в
quartz.config.ts,quartz.layout.tsи кастомных стилях не попадают в running container автоматически: после них нуженmake web-upилиdocker compose ... up -d --build docs. api: CompileDaemon над./backend/....auth: CompileDaemon над bind-mountedshared/auth; сборка идёт вvendor-режиме самого auth-сервиса.nginx: watcher наtemplates/,includes/,certs/→render-configs.sh+nginx -s reload.web: статические файлы — bind mount (без пересборки).
Общий Elasticsearch
shared/auth и Tracium используют один Elasticsearch (сервис elasticsearch из базового docker-compose.yml). Разделение — по префиксам индексов: auth_* у shared/auth, tracium_* у Tracium.
RabbitMQ overhead
shared/auth требует RabbitMQ для нотификаций — добавлен как отдельный сервис rabbit в web-стэк. В будущем планируется миграция на Kafka (уже используется ядром Tracium), пока принят operational overhead.
Примечания по безопасности (локальная разработка)
deploy/auth/.envникогда не коммитится (gitignored).- JWT secret в
deploy/auth/.env.example— placeholder, обязателен override вdeploy/auth/.env. - Сертификаты в
deploy/docker/resources/certs/local/— gitignored. - В prod — отдельный ADR-0018 master key + KMS/Vault Transit.
Best practices, перенесённые из crewnaut
- Не смешивать compose-логику, app-конфиг и host ports в одном файле.
- Не хранить рабочие
.envв репозитории, только.env.example. - Все стандартные действия должны быть доступны через
Makefile, а не через длинныеdocker compose ...команды. - Локальная разработка должна поднимать HTTPS ingress отдельным compose-слоем, не ломая базовый infra stack.
- Production ingress должен использовать выделенный host port и не конфликтовать с другими проектами на том же сервере.
- Сначала поднимается инфраструктура, затем к ней подключаются прикладные сервисы
catalog-core,ingestion,search,pricing,public-api,admin-api. - GitLab CI валидирует compose-конфиг через
docker compose configдо merge.
Связано
- GitLab delivery pipeline:
../50-processes/gitlab-cicd.md - Release management:
../50-processes/release-management.md