Промышленное развёртывание¶
Статья описывает, как поставить Taimen на выделенный сервер: раскладку
каталогов, подготовку .env и секретов, выбор профилей, первый запуск,
bootstrap и вынос автономных исполнителей на отдельный runner-хост. Для
локального знакомства с платформой достаточно
быстрого старта; здесь — то, что отличает
промышленную установку.
Целевая топология¶
| Узел | Что работает | Откуда код |
|---|---|---|
| Хост платформы | Один compose-проект на корневом compose.yml: ядро (core), периметр (edge), по необходимости панель (platform) и прочие профили |
Клон суперпроекта с сабмодулями; релиз = коммит суперпроекта |
| Runner-хост (необязательно) | Демон control-plane-agent с кодовым агентом, bare-зеркала репозиториев, рабочие копии |
Тот же суперпроект: образ deploy/runner/docker или systemd-юниты deploy/runner/systemd |
| Рабочие места операторов | MCP-плагин / CLI control-plane, Human Harness |
Пакет control-plane из суперпроекта |
Хост платформы и runner-хост связаны только через публичный адрес платформы: runner обменивает свой PAT на access token в IAM и ходит в Control Plane API через Caddy. Прямого сетевого доступа к базам ему не нужно.
Почему runner отдельно
Кодовому агенту разрешено выполнять произвольные команды (режим
bypassPermissions), иначе он не может работать. Периметр вокруг него —
отдельная машина или контейнер без доступа к секретам платформы, а не
режим разрешений. Держать агента на хосте с базами и ключом подписи IAM
нельзя.
Требования к хосту¶
| Что | Минимум | Комментарий |
|---|---|---|
| ОС | Linux x86_64 с systemd | Проверено на Ubuntu 24.04 LTS |
| Docker Engine | 24+ | С плагином Compose v2 |
| Docker Compose | v2.24+ | env_file с required: false используется в compose.yml |
| git | любой современный | Клон с сабмодулями |
| python3 + PyYAML и jsonschema (или uv) | 3.10+ | На хосте запускаются deploy/bootstrap.py и tools/smoke.py. Установке каталога из пакетов (шаг 5b bootstrap) нужны PyYAML и jsonschema: make bootstrap при установленном uv подключает их сам; при прямом вызове скрипта (на хосте без make) — либо uv run --no-project --with pyyaml --with jsonschema python3 deploy/bootstrap.py …, либо системный python3 с ними (на Ubuntu пакеты python3-yaml, python3-jsonschema) |
| openssl, make | — | make secrets генерирует ключи подписи RSA 3072 |
| DNS | A/AAAA-запись публичного имени на хост | До первого запуска Caddy, см. Периметр и TLS |
| Порты | 80 и 443 снаружи | Остальные порты сервисов привязаны к 127.0.0.1 |
Ресурсы (CPU, RAM, диск) — в статье Ресурсы и масштабирование.
Раскладка каталогов¶
Рекомендуемая раскладка на хосте платформы:
/opt/taimen/
├── src/ клон суперпроекта с сабмодулями (релиз = коммит)
│ ├── compose.yml единое описание всех сервисов
│ ├── .env окружение установки, 0600
│ ├── secrets/ ключи подписи, PAT, env-файлы service accounts, 0600
│ │ ├── iam-signing.pem приватный ключ подписи IAM (владелец uid 10001)
│ │ ├── harness-pat PAT оператора, выпускает bootstrap
│ │ └── control-plane-iam.env service account ядра к памяти (bootstrap)
│ └── deploy/state/<env>.json идентификаторы, записанные bootstrap (не секрет)
├── Caddyfile конфигурация периметра этой установки
└── backups/ дампы БД (см. «Резервное копирование»)
.env, secrets/ и deploy/state/ перечислены в .gitignore суперпроекта:
git pull их не трогает.
Caddyfile держите вне клона
Переменная CADDYFILE задаёт путь к файлу, который монтируется в
контейнер caddy. Файл установки с вашим доменом удобнее держать вне
рабочего дерева git (например, /opt/taimen/Caddyfile), взяв за образец
deploy/staging/Caddyfile или deploy/caddy/Caddyfile.local. Так
обновление суперпроекта не конфликтует с локальными правками.
Профили compose¶
| Профиль | Сервисы | Когда нужен |
|---|---|---|
core |
iam-db, iam-service, control-plane-db, control-plane-api, control-plane-worker, context-adapter, memory-db, memory-service, minio, minio-bootstrap |
Всегда (MinIO — хранилище содержимого артефактов, см. Хранилище объектов) |
edge |
caddy |
Всегда: единственный вход снаружи |
platform |
platform-db, platform-redis, realm-render, keycloak, minio, minio-bootstrap, platform-migrations, platform-api, platform-web |
Нужен вход людей в веб-консоль через Keycloak |
policy |
policy-db, openfga-migrate, openfga, policy-service, policy-worker |
Экспериментальный PDP, см. Policy Service |
entitlement |
entitlement-db, entitlement-service |
Экспериментальная проверка лицензий |
demo |
support-bot |
Демонстрационный бот, в поставку не входит |
Замороженный периметр
Профили platform, policy, entitlement работают и
исправляются при поломке, но новых функций не получают. make up без
аргументов поднимает только core edge. Если людям нужен вход в
веб-консоль, профиль platform включается явно — на нём держится вход
через Keycloak.
Процедура первого развёртывания¶
1. Клон суперпроекта¶
sudo mkdir -p /opt/taimen && sudo chown "$USER" /opt/taimen
git clone --recursive <url-суперпроекта> /opt/taimen/src
cd /opt/taimen/src
git submodule status # все сабмодули без «-» в начале строки
Если клон сделан без --recursive, выполните make submodules
(git submodule update --init --recursive). Сборка без сабмодулей падает:
контекст сборки control-plane, memory-service и других — корень
суперпроекта, а platform-auth-sdk подключён path-зависимостью соседней папкой.
2. .env и ключи подписи¶
Цель make secrets:
- копирует
.env.exampleв.envс правами0600(если.envещё нет); - заполняет пустые секреты случайными значениями (
tools/fill_secrets.pyтрогает только пустые значения — повторный запуск ничего не перезапишет); - генерирует
secrets/iam-signing.pemиsecrets/entitlement-signing.pem(RSA 3072) и ставит им0600.
Затем отредактируйте .env под установку:
TAIMEN_PUBLIC_URL=https://platform.example.com
TAIMEN_PUBLIC_HOST=platform.example.com
COMPOSE_PROJECT_NAME=taimen
TAIMEN_NETWORK=taimen_default
CADDYFILE=/opt/taimen/Caddyfile
LOG_RENDERER=json
KEYCLOAK_HOSTNAME_STRICT=true
IAM_SIGNING_KEY_ID=prod-2026-01 # осмысленный kid, меняется при ротации ключа
CP_LEGACY_API_KEYS_ENABLED=false
Параметры провайдеров памяти (MEMORY_EMBEDDING_PROVIDER,
MEMORY_LLM_PROVIDER, LLM_BASE_URL, LLM_MODEL, ключ провайдера) описаны в
конфигурации памяти; полный список переменных —
в справочнике.
TAIMEN_PUBLIC_URL выбирается один раз
Из него строится issuer IAM (${TAIMEN_PUBLIC_URL}/iam), а Control Plane
ищет binding identity по паре (issuer, iam_principal_id). Смена
публичного адреса после bootstrap — отдельная процедура, см.
Аварийные процедуры.
3. Права секретов для контейнеров¶
Большинство сервисов платформы (iam-service, control-plane,
policy-service, entitlement-service) работают в
контейнере под uid 10001. Файлы из секции secrets: compose монтируются
bind-mount'ом с правами хоста, поэтому на Linux:
sudo chown 10001:10001 secrets/iam-signing.pem secrets/entitlement-signing.pem
sudo chmod 600 secrets/*.pem
Права не ослабляйте до 644: это приватные ключи. Если оставить владельцем
root при режиме 600, IAM не прочитает ключ и ответит 500 на выдаче токенов.
Env-файлы (secrets/*.env) читает сам docker compose на хосте, для них
chown не нужен.
4. Caddyfile¶
Возьмите за основу deploy/staging/Caddyfile, замените адрес сайта на своё
имя и уберите маршруты профилей, которые не поднимаете. Подробно — в статье
Периметр и TLS. Перед первым запуском убедитесь, что имя
уже резолвится на хост:
5. Проверка конфигурации и сборка¶
make config PROFILES="core platform edge" # docker compose ... config --quiet
make build PROFILES="core platform edge"
Сборка идёт на хосте из исходников, отдельный registry не нужен. Если
хотите держать предыдущие образы для быстрого отката, задайте в .env
IMAGE_TAG (например, короткий хэш коммита суперпроекта) — см.
Обновление и миграции.
6. Запуск¶
make up PROFILES="core platform edge" # docker compose --profile ... up -d --build
docker compose --profile "*" ps
Порядок старта задан depends_on с условиями service_healthy: базы →
IAM и память → control-plane-api (выполняет alembic upgrade head, затем
становится healthy, когда ревизия БД совпала с head) → control-plane-worker
и context-adapter. Первый старт с пустыми томами занимает 1–3 минуты
(Keycloak — до минуты сам по себе).
7. Bootstrap¶
deploy/bootstrap.py идемпотентен и делает за один проход:
| Шаг | Что создаётся | Куда пишется результат |
|---|---|---|
| 1 | Ожидание /health/ready Control Plane и /healthz IAM на 127.0.0.1 |
— |
| 2 | IAM tenant, audiences с потолками scope, human principal оператора | deploy/state/<env>.json |
| 2a | Service account ядра (память, entitlement, policy) | secrets/control-plane-iam.env |
| 3 | POST /api/v1/bootstrap Control Plane: tenant, admin principal и первый IAM binding |
state |
| 4 | Authentication context и PAT оператора (read/write/admin) | secrets/harness-pat |
| 5 | Шаблон проекта, project и workspace | state |
| 5b | Каталог из пакетов (--packages, по умолчанию deploy/packages.yaml) |
state |
| — | Отзыв legacy api-key, выданного bootstrap Control Plane | state |
| 7 | Если задан POL_BOOTSTRAP_TOKEN и policy-service отвечает на /healthz — каталоги и роли PDP. Иначе шаг пропускается с сообщением; с --policy скрипт ждёт сервис до 30 с и падает не дождался …/healthz |
secrets/memory-service-iam.env, secrets/policy-service-cp.env |
После первого прогона выполните то, что скрипт печатает с пометкой !!:
# 1. IAM tenant нужен platform-api и исполнителям пакетов
sed -i "s/^IAM_TENANT_ID=.*/IAM_TENANT_ID=<tenant-id>/" .env
# 2. Ядро должно подхватить env-файл service account (CP_CONTEXT_AUTH=auto)
docker compose up -d control-plane-api control-plane-worker context-adapter
Проверка, что ядро перешло с MEMORY_API_KEY на service account:
docker compose exec context-adapter env | grep -c CP_IAM_CLIENT_ID # 1
docker compose logs --since 5m context-adapter | grep -E ' 40[13] ' || echo "нет 401/403"
8. Проверка¶
make smoke
curl -fsS https://platform.example.com/health/ready
curl -fsS https://platform.example.com/iam/.well-known/jwks.json | head -c 200
make smoke (скрипт tools/smoke.py) опрашивает health каждого запущенного
сервиса через порты на 127.0.0.1; не поднятые профили помечаются
«не запущен» и ошибкой не считаются.
9. Credential оператора¶
PAT оператора лежит в secrets/harness-pat. На рабочем месте оператора он
кладётся в ~/.config/iam/credentials.json (режим строго 0600, иначе клиент
откажется читать файл) под ключом <issuer>|<tenant-id>|<principal-id> —
bootstrap печатает точный ключ последней строкой. Подробнее — в
MCP-плагине и
Credentials и PAT.
Перенос файла с сервера
Копируйте PAT по защищённому каналу (scp) и удаляйте промежуточные
копии. Не вставляйте токен в чаты, тикеты и командную строку с историей.
10. Панель платформы (профиль platform)¶
Для входа людей через Keycloak после bootstrap нужно: засидировать tenant
platform-core с тем же UUID, что у IAM (bootstrap печатает
SEED_TENANT_ID=<tenant-id>), завести пользователей в realm platform с
атрибутом tenant_id и привязать их к IAM principal, включить feature flag
консоли. Процедура — в статье Вход людей — Keycloak.
Runner-хост¶
Автономный исполнитель ставится отдельно от хоста платформы. В суперпроекте лежат два варианта:
Образ собирается из дерева суперпроекта, внутри — демон
control-plane-agent, Claude Code и тестовые базы (db-test,
memory-db-test) в tmpfs. Секреты — файлы в каталоге с правами 0700,
каждый 0600: PAT агента, токен подписки кодового агента, токен forge.
Docker-сокет в контейнер не пробрасывается.
Демон ставится uv-инструментом под непривилегированным пользователем
runner; юнит ограничивает ресурсы (CPUQuota, MemoryHigh,
MemoryMax, IOWeight) и файловую систему (ProtectSystem=strict,
ProtectHome=read-only, NoNewPrivileges). Конфигурация — env-файл
0600, PAT — ~/.config/iam/credentials.json пользователя runner.
Правила, общие для обоих вариантов:
- Один исполнитель — один principal. У каждого свой IAM principal вида
agent, свой PAT и binding безadminиapprovals.decide(bootstrap отказывается выдавать агенту эти права). CONTROL_PLANE_AGENT_ONLY_ASSIGNED=1и явныйCONTROL_PLANE_AGENT_WORKSPACE: без них агент берёт первую доступную задачу по приоритету из общей очереди.IAM_PRINCIPALобязателен, если на машине лежат credentials нескольких исполнителей одного tenant.- Сумма лимитов памяти всех исполнителей не должна превышать физическую память хоста — см. Ресурсы и масштабирование.
Установка и переменные подробно — в статьях Установка runner и Конфигурация runner.
Чек-лист готовности к эксплуатации¶
-
.envи все файлыsecrets/—0600;.envне лежит в git. - Ключ подписи IAM — владелец uid 10001, режим
600. -
CP_LEGACY_API_KEYS_ENABLED=false, legacy api-key отозван bootstrap. - Caddy выпустил сертификат,
http://редиректит наhttps://. -
/metricsзакрыт от внешнего доступа (см. Периметр и TLS). - Порты
127.0.0.1:18000,18001,18010и прочие не видны снаружи (ss -ltnpна хосте показывает их на127.0.0.1). - Настроены бэкапы всех томов БД и каталога
secrets/. - Записаны даты истечения всех PAT (
deploy/state/<env>.jsonхранитoperatorPatExpiresAt). - Runner-хост отделён от хоста платформы.