Сервисы и порты¶
Все сервисы корневого compose.yml: профиль, образ или контекст сборки,
внутренний и публикуемый порт, зависимости, volumes, healthcheck, лимит
памяти и маршрут во внешнем контуре (Caddy). Статья для инженера, который
разворачивает стек, открывает порты на хосте или ищет, какой контейнер
отвечает на путь /….
Общая схема¶
flowchart LR
B[Браузер / харнесс / агент] -->|80 / 443| CADDY[caddy<br/>edge]
CADDY -->|/iam/*| IAM[iam-service:8010]
CADDY -->|/api/v1/*, /health/*, /docs| CP[control-plane-api:8000]
CADDY -->|/auth/*| KC[keycloak:8080]
CADDY -->|/platform/*| PAPI[platform-api:8000]
CADDY -->|/support-demo/*| SB[support-bot:8000]
CADDY -->|/fleet/*| FC[fleet-controller:8040]
CADDY -->|/memory/* только локально| MEM[memory-service:8077]
CADDY -->|/ остальное| WEB[platform-web:3000]
CP --> MEM
CP --> IAM
CA[context-adapter] --> MEM
- Все контейнеры в одной сети
taimen(имя —${TAIMEN_NETWORK:-taimen_default}) и обращаются друг к другу по DNS-именам сервисов. - Наружу смотрит только
caddy. Остальные сервисы публикуют порт исключительно на127.0.0.1— дляmake smoke,make bootstrapи отладки с хоста. - У контейнера
caddyесть сетевой alias${TAIMEN_PUBLIC_HOST}: сервисы обращаются к Keycloak и IAM по публичному имени, чтобы issuer в токене совпадал с тем, что видит браузер.
Профили¶
По умолчанию make up поднимает core edge. Остальные профили включаются
явно: make up PROFILES="core platform edge" или
docker compose --profile core --profile edge up -d.
| Профиль | Статус | Сервисы |
|---|---|---|
core |
ядро | iam-db, iam-service, control-plane-db, control-plane-api, control-plane-worker, context-adapter, memory-db, memory-service |
edge |
ядро | caddy |
entitlement |
заморожен | entitlement-db, entitlement-service |
policy |
экспериментальный | policy-db, openfga-migrate, openfga, policy-service, policy-worker |
platform |
заморожен | platform-db, platform-redis, realm-render, keycloak, minio, minio-bootstrap, platform-migrations, platform-api, platform-web |
demo |
демо, не входит в поставку | support-bot |
fleet |
ядро агентов | fleet-controller |
Зависимости между профилями
depends_on работает только внутри активных профилей. Шлюз
platform-api ходит в control-plane-api — поднимайте профили вместе
(PROFILES="core platform edge").
Сводная таблица портов¶
| Сервис | Внутренний порт | Публикуется на хосте | Переменная порта | Путь в Caddy |
|---|---|---|---|---|
caddy |
80, 443 | 0.0.0.0:80, 0.0.0.0:443 |
EDGE_HTTP_PORT, EDGE_HTTPS_PORT |
— |
control-plane-api |
8000 | 127.0.0.1:18000 |
CP_HOST_PORT |
/api/v1/*, /health/*, /metrics, /docs, /docs/*, /redoc, /redoc/*, /openapi.json |
memory-service |
8077 | 127.0.0.1:18001 |
MEMORY_HOST_PORT |
/memory/* (только в локальном Caddyfile) |
iam-service |
8010 | 127.0.0.1:18010 |
IAM_HOST_PORT |
/iam/* (префикс срезается) |
entitlement-service |
8020 | 127.0.0.1:18020 |
ENT_HOST_PORT |
нет |
policy-service |
8030 | 127.0.0.1:18040 |
POL_HOST_PORT |
нет |
platform-api |
8000 (и 9464 — метрики Prometheus, не публикуется) | 127.0.0.1:18080 |
PLATFORM_API_HOST_PORT |
/platform/* (префикс срезается, X-Forwarded-Prefix: /platform) |
keycloak |
8080 (9000 — management, health) | 127.0.0.1:18081 |
KEYCLOAK_HOST_PORT |
/auth/* (без среза, Keycloak живёт под /auth) |
support-bot |
8000 | 127.0.0.1:18090 |
SUPPORT_HOST_PORT |
/support-demo/* (префикс срезается; /support-demo → 301) |
fleet-controller |
8040 | нет | — | /fleet/* (префикс срезается) |
platform-web |
3000 | 127.0.0.1:13000 |
PLATFORM_WEB_HOST_PORT |
/ — всё, что не совпало выше |
openfga |
8080 | нет | — | нет |
platform-redis |
6379 | нет | — | нет |
minio |
9000 | нет | — | нет |
базы *-db |
5432 | нет | — | нет |
control-plane-worker, context-adapter, policy-worker |
— | нет | — | нет |
Порядок маршрутов Caddy
Caddy выбирает первый совпавший handle. Специфичные префиксы (/iam/*,
/auth/*, /platform/* …) и матчер Control Plane @cp_api стоят раньше
общего handle, который отдаёт всё остальное веб-консоли. Добавляя свой
маршрут, ставьте его перед общим handle.
Ядро (core)¶
iam-db¶
| Параметр | Значение |
|---|---|
| Образ | postgres:16-alpine |
| БД / роль | iam / iam, пароль ${IAM_POSTGRES_PASSWORD} |
| Volume | iam_db → /var/lib/postgresql/data |
| Healthcheck | pg_isready -U iam -d iam |
| Лимит памяти | ${PG_MEM_LIMIT:-256m} |
iam-service¶
| Параметр | Значение |
|---|---|
| Образ / сборка | ${IMAGE_PREFIX}/iam-service:${IMAGE_TAG}, контекст ${IAM_BUILD_CONTEXT:-./iam-service} |
| Команда | alembic upgrade head && uvicorn iam_service.app:app --host 0.0.0.0 --port 8010 |
| Порт | 8010 → 127.0.0.1:${IAM_HOST_PORT:-18010} |
| Зависит от | iam-db (healthy) |
| Секреты | iam_signing_key → /run/secrets/iam_signing_key (файл ${IAM_SIGNING_KEY_FILE}) |
| Healthcheck | GET http://127.0.0.1:8010/healthz |
| Лимит памяти | ${IAM_MEM_LIMIT:-256m} |
| Пользователь | uid 10001 |
control-plane-db¶
| Параметр | Значение |
|---|---|
| Образ | postgres:16-alpine |
| БД / роль | control_plane / control_plane |
| Volume | control_plane_db |
| Healthcheck | pg_isready -U control_plane -d control_plane |
| Лимит памяти | ${PG_MEM_LIMIT:-256m} |
control-plane-api¶
| Параметр | Значение |
|---|---|
| Образ / сборка | ${IMAGE_PREFIX}/control-plane:${IMAGE_TAG}, контекст ${CP_BUILD_CONTEXT:-.} (корень суперпроекта), Dockerfile control-plane/Dockerfile |
| Команда | alembic upgrade head && uvicorn control_plane.main:app --host 0.0.0.0 --port 8000 |
| Порт | 8000 → 127.0.0.1:${CP_HOST_PORT:-18000} |
| Зависит от | control-plane-db, memory-service, iam-service (все healthy) |
| env_file | ./secrets/control-plane-iam.env (необязательный) |
| Healthcheck | GET http://127.0.0.1:8000/health/ready |
| Лимит памяти | ${CP_MEM_LIMIT:-512m} |
| Пользователь | uid 10001 |
control-plane-worker¶
| Параметр | Значение |
|---|---|
| Образ | тот же, что у control-plane-api (не собирается отдельно) |
| Команда | python -m control_plane.worker |
| Порт | нет |
| Зависит от | control-plane-db (healthy), control-plane-api (healthy) |
| env_file | ./secrets/control-plane-iam.env |
| Healthcheck | нет |
| Лимит памяти | ${CP_WORKER_MEM_LIMIT:-256m} |
context-adapter¶
| Параметр | Значение |
|---|---|
| Образ | тот же, что у control-plane-api |
| Команда | python -m control_plane.worker.context_adapter |
| Порт | нет |
| Зависит от | control-plane-db, control-plane-api, memory-service (все healthy) |
| env_file | ./secrets/control-plane-iam.env |
| Healthcheck | нет |
| Лимит памяти | ${CP_WORKER_MEM_LIMIT:-256m} |
Один образ на три процесса
control-plane-api, control-plane-worker и context-adapter работают
на одном образе. Образ собирается только сервисом control-plane-api;
после сборки пересоздайте все три контейнера, иначе worker и адаптер
останутся на прежнем коде.
memory-db¶
| Параметр | Значение |
|---|---|
| Образ / сборка | ${IMAGE_PREFIX}/memory-db:${IMAGE_TAG}, контекст ${MEMORY_BUILD_CONTEXT:-./memory-service}/infra/memory-db (PostgreSQL 16 + Apache AGE + pgvector) |
| БД / роль | company_brain / memory |
| Volume | memory_db |
| Healthcheck | pg_isready -U memory -d company_brain |
| Лимит памяти | ${MEMORY_DB_MEM_LIMIT:-512m} |
memory-service¶
| Параметр | Значение |
|---|---|
| Образ / сборка | ${IMAGE_PREFIX}/memory-service:${IMAGE_TAG}, контекст ${MEMORY_BUILD_CONTEXT:-.}, Dockerfile memory-service/Dockerfile |
| Порт | 8077 → 127.0.0.1:${MEMORY_HOST_PORT:-18001} |
| Зависит от | memory-db (healthy) |
| env_file | ./secrets/memory-service-iam.env (необязательный) |
| Healthcheck | GET http://127.0.0.1:8077/healthz |
| Лимит памяти | ${MEMORY_MEM_LIMIT:-512m} |
Периметр (edge)¶
caddy¶
| Параметр | Значение |
|---|---|
| Образ | caddy:2-alpine |
| Порты | ${EDGE_HTTP_PORT:-80}:80, ${EDGE_HTTPS_PORT:-443}:443 на всех интерфейсах |
| Volumes | ${CADDYFILE} → /etc/caddy/Caddyfile (read-only), caddy_data → /data (сертификаты ACME), caddy_config → /config |
| Сетевой alias | ${TAIMEN_PUBLIC_HOST:-taimen.localhost} |
| Healthcheck | нет |
Локальный deploy/caddy/Caddyfile.local обслуживает http://taimen.localhost
и http://localhost без ACME, пишет лог в stderr и сжимает ответы
(zstd, gzip). Промышленный Caddyfile задаётся переменной CADDYFILE и
повторяет ту же раскладку путей с TLS, но без маршрута /memory/*: память
наружу не публикуется. Подробнее — Периметр и TLS.
Правка Caddyfile на месте
Файл смонтирован bind-mount'ом и держит inode. Если заменить файл через
mv, caddy reload перечитает старую версию. Правьте файл на месте или
пересоздайте контейнер: docker compose up -d --force-recreate caddy.
Entitlement (entitlement, заморожен)¶
| Сервис | Образ / сборка | Порт | Зависит от | Volume | Healthcheck | Лимит |
|---|---|---|---|---|---|---|
entitlement-db |
postgres:16-alpine, БД entitlement |
— | — | entitlement_db |
pg_isready -U entitlement -d entitlement |
${PG_MEM_LIMIT} |
entitlement-service |
контекст ${ENT_BUILD_CONTEXT:-.}, Dockerfile entitlement-service/Dockerfile; команда alembic upgrade head && uvicorn entitlement_service.app:app --port 8020 |
8020 → 127.0.0.1:18020 |
entitlement-db |
секрет entitlement_signing_key |
нет | ${ENT_MEM_LIMIT:-256m} |
Policy (policy, экспериментальный)¶
| Сервис | Образ / сборка | Порт | Зависит от | Volume / файлы | Healthcheck | Лимит |
|---|---|---|---|---|---|---|
policy-db |
postgres:16-alpine, БД policy и openfga |
— | — | policy_db; policy-service/deploy/init-openfga.sql → init-скрипт |
pg_isready -U policy -d policy |
${PG_MEM_LIMIT} |
openfga-migrate |
openfga/openfga:v1.20.0, migrate (одноразовый) |
— | policy-db (healthy) |
— | — | — |
openfga |
openfga/openfga:v1.20.0, run, playground выключен, логи JSON |
8080, не публикуется | openfga-migrate (завершён успешно) |
— | /openfga version |
${OPENFGA_MEM_LIMIT:-256m} |
policy-service |
контекст ${POL_BUILD_CONTEXT:-.}, Dockerfile policy-service/Dockerfile; alembic upgrade head && uvicorn policy_service.app:app --port 8030 |
8030 → 127.0.0.1:18040 |
policy-db, openfga (healthy) |
— | GET /healthz |
${POL_MEM_LIMIT:-256m} |
policy-worker |
образ policy-service, команда policy-worker |
— | policy-service (healthy) |
env_file ./secrets/policy-service-cp.env |
нет | ${POL_MEM_LIMIT:-256m} |
Панель платформы (platform, заморожен)¶
| Сервис | Образ / сборка | Порт | Зависит от | Volume / файлы | Healthcheck | Лимит |
|---|---|---|---|---|---|---|
platform-db |
postgres:16-alpine, БД platform + БД keycloak (init-скрипт) |
— | — | platform_db; deploy/staging/platform/postgres/init-keycloak-db.sh |
pg_isready -U platform -d platform (10 s × 10) |
${PG_MEM_LIMIT} |
platform-redis |
redis:7-alpine, AOF, пароль |
— | — | platform_redis → /data |
redis-cli ping |
${REDIS_MEM_LIMIT:-128m} |
realm-render |
busybox:1.36, одноразовый: подставляет секрет клиента и адрес веба в шаблон realm |
— | — | deploy/staging/platform/keycloak → /template, realm_import → /import |
— | — |
keycloak |
quay.io/keycloak/keycloak:26.5.2, start --import-realm |
8080 → 127.0.0.1:18081 |
platform-db (healthy), realm-render (завершён) |
realm_import (read-only) |
GET /auth/health/ready на порту 9000 (15 s × 20, start 40 s) |
${KEYCLOAK_MEM_LIMIT:-768m} |
minio |
minio/minio:RELEASE.2024-10-13T13-34-11Z, server /data |
9000, не публикуется | — | platform_minio |
mc ready local |
${MINIO_MEM_LIMIT:-256m} |
minio-bootstrap |
minio/mc:RELEASE.2024-10-08T09-37-26Z, одноразовый: создаёт бакет ${S3_BUCKET} |
— | minio (healthy) |
— | — | — |
platform-migrations |
контекст ${PLATFORM_BUILD_CONTEXT:-./platform-core}, Dockerfile workers/migrations/Dockerfile, одноразовый |
— | platform-db (healthy) |
— | — | — |
platform-api |
тот же контекст, Dockerfile apps/api/Dockerfile, UVICORN_ROOT_PATH=/platform |
8000 → 127.0.0.1:18080 |
platform-db, platform-redis (healthy), platform-migrations, minio-bootstrap (завершены) |
— | из образа: GET /health (15 s × 6, start 20 s) |
${PLATFORM_API_MEM_LIMIT:-512m} |
platform-web |
контекст ${PLATFORM_WEB_BUILD_CONTEXT:-./platform-web}, build-args NEXT_PUBLIC_* |
3000 → 127.0.0.1:13000 |
platform-api (healthy) |
— | из образа: wget на :3000 (30 s × 3) |
${PLATFORM_WEB_MEM_LIMIT:-512m} |
Realm импортируется один раз
--import-realm импортирует realm только при первом старте с пустой
БД. Правки шаблона на существующий realm не попадают — меняйте живой
realm через Admin API. См. Вход людей — Keycloak.
Fleet (fleet)¶
Контроллер узлов и размещения декларативных агентов (TAI-ADR-0052). Узлы
(fleet-node) работают на машинах исполнителей вне этого compose и ходят к
контроллеру только исходящими запросами через Caddy /fleet/*.
| Сервис | Образ / сборка | Порт | Зависит от | Volume / env | Healthcheck | Лимит |
|---|---|---|---|---|---|---|
fleet-controller |
${IMAGE_PREFIX:-taimen}/fleet-controller:${IMAGE_TAG:-local}, контекст ${FLEET_BUILD_CONTEXT:-.}, Dockerfile fleet/Dockerfile; команда fleet-controller serve |
8040, не публикуется | control-plane-api, iam-service (healthy) |
fleet_data → /data; env_file ./secrets/fleet-iam.env |
GET /healthz на 127.0.0.1:8040 |
${FLEET_MEM_LIMIT:-128m} |
Без secrets/fleet-iam.env (bootstrap, шаг 5d) все маршруты, кроме
/healthz, отвечают 503 not_configured. Переменные — в
Переменных окружения, устройство — в
Узлах и fleet.
Демо¶
| Сервис | Профиль | Образ / сборка | Порт | Volume | Healthcheck | Лимит |
|---|---|---|---|---|---|---|
support-bot |
demo |
контекст ${SUPPORT_BUILD_CONTEXT:-.}, Dockerfile demos/support-demo/Dockerfile |
8000 → 127.0.0.1:18090 |
support_data → /srv/data |
GET /api/config (10 s × 12) |
${SUPPORT_MEM_LIMIT:-256m} |
support-bot не объявляет depends_on: memory-service и Control Plane
должны быть подняты заранее.
Коннектор git — агент, а не сервис compose
Источник наблюдений git в compose.yml платформы не входит: это агент вида
исполнителя git-connector, которого запускает узел fleet (образ
integrations/selfdev/Dockerfile, том реплики — fleet-<agent>-<replica>-data,
токен forge — секрет узла github-token). См. Узлы и
fleet.
Healthcheck'и и smoke¶
У Python-сервисов ядра общий шаблон healthcheck: интервал 5 s, таймаут
5 s, 30 попыток; проверка — urllib.request.urlopen на 127.0.0.1
(не localhost: в slim-образах localhost может резолвиться в IPv6
::1, где сервер не слушает).
make smoke (tools/smoke.py) проверяет поднятые сервисы по портам на
127.0.0.1 и пропускает не запущенные:
| Сервис | Порт по умолчанию | Путь |
|---|---|---|
iam-service |
18010 | /healthz |
control-plane-api |
18000 | /health/ready |
memory-service |
18001 | /healthz |
entitlement-service |
18020 | /healthz |
platform-api |
18080 | /health |
keycloak |
18081 | /auth/realms/platform |
platform-web |
13000 | / |
support-bot |
18090 | /api/config |
Ответ с кодом < 400 — OK, иначе ERR и ненулевой код выхода.
policy-service в smoke не входит.
Volumes¶
| Volume | Сервис | Что хранит |
|---|---|---|
iam_db |
iam-db |
Tenants, principals, credentials IAM |
control_plane_db |
control-plane-db |
Work graph, журнал событий, bindings |
memory_db |
memory-db |
Граф знаний, чанки, наблюдения |
entitlement_db |
entitlement-db |
Лицензии, квоты |
policy_db |
policy-db |
Роли, bindings и store OpenFGA |
platform_db |
platform-db |
БД platform и keycloak |
platform_redis |
platform-redis |
Кэш, брокер событий |
platform_minio |
minio |
Документы |
realm_import |
realm-render, keycloak |
Отрендеренный realm |
support_data |
support-bot |
SQLite демо |
fleet_data |
fleet-controller |
SQLite: узлы, размещения, личности агентов, шифротексты PAT |
caddy_data, caddy_config |
caddy |
Сертификаты и состояние Caddy |
Имена задаются переменными VOLUME_* (см.
Переменные окружения). make down volumes не удаляет.
Docker-секреты¶
| Секрет | Файл по умолчанию | Кому |
|---|---|---|
iam_signing_key |
./secrets/iam-signing.pem |
iam-service |
entitlement_signing_key |
./secrets/entitlement-signing.pem |
entitlement-service |
Контейнеры читают секреты под непривилегированным uid (10001 у сервисов
ядра). На Linux выполните chown 10001 для файлов в secrets/, права
оставьте 600.