Промышленное развёртывание¶
Статья описывает, как поставить Taimen на выделенный сервер: раскладку
каталогов, подготовку .env и секретов, выбор профилей, первый запуск,
bootstrap и вынос автономных исполнителей на отдельный runner-хост. Для
локального знакомства с платформой достаточно
быстрого старта; здесь — то, что отличает
промышленную установку.
Целевая топология¶
| Узел | Что работает | Откуда код |
|---|---|---|
| Хост платформы | Один compose-проект на deploy/local/compose.yml: ядро (core), периметр (edge) и по необходимости консоль со входом людей (console, idp), ассистент (harness), уведомления (notify) и контроллер исполнителей (fleet) |
Клон суперпроекта с сабмодулями; релиз = коммит суперпроекта |
| Узлы исполнителей (необязательно) | fleet-node и контейнеры агентов с демоном control-plane-agent, рабочие копии и зеркала на томах реплик |
Compose узла deploy/node/, образ исполнителя deploy/agent-runner/ |
| Рабочие места операторов | Консоль в браузере, MCP-плагин / CLI control-plane |
Пакет 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 используется в deploy/local/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/ клон суперпроекта с сабмодулями (релиз = коммит)
│ ├── services/, sdk/ сабмодули компонентов (TAI-ADR-0064)
│ ├── deploy/local/compose.yml единое описание всех сервисов (запуск из корня: tools/compose)
│ ├── .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/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 |
Всегда: единственный вход снаружи |
notify |
notification-db, notification-service |
Уведомления людей о событиях платформы |
idp |
keycloak-db, realm-render, keycloak |
Вход людей через Keycloak (внешний IdP), см. Keycloak — внешний IdP |
console |
console и сервисы idp |
Консоль: работа, решения, настройки организации |
harness |
harness-image, harness-docker-proxy, harness-launcher |
Движок ассистента людей (панель консоли, Telegram); требует idp, см. Рабочее место человека |
fleet |
fleet-controller |
Размещение агентов на узлах, см. Узлы и fleet |
make up без аргументов поднимает только core edge; остальные профили
включаются явно, например make up PROFILES="core edge console".
Процедура первого развёртывания¶
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(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) работают в контейнере
под uid 10001. Файлы из секции secrets: compose монтируются
bind-mount'ом с правами хоста, поэтому на Linux:
Права не ослабляйте до 644: это приватные ключи. Если оставить владельцем
root при режиме 600, IAM не прочитает ключ и ответит 500 на выдаче токенов.
Env-файлы (secrets/*.env) читает сам docker compose на хосте, для них
chown не нужен.
4. Caddyfile¶
Возьмите за основу deploy/caddy/Caddyfile.local: замените адрес сайта
http://taimen.localhost на своё имя без схемы (тогда Caddy сам выпустит
сертификат), уберите auto_https off и маршруты профилей, которые не
поднимаете. Подробно — в статье Периметр и TLS. Перед
первым запуском убедитесь, что имя уже резолвится на хост:
5. Проверка конфигурации и сборка¶
Сборка идёт на хосте из исходников, отдельный registry не нужен. Если
хотите держать предыдущие образы для быстрого отката, задайте в .env
IMAGE_TAG (например, короткий хэш коммита суперпроекта) — см.
Обновление и миграции.
6. Запуск¶
make up PROFILES="core edge" # tools/compose --profile ... up -d --build
tools/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 ядра (память, хранилище секретов) | 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 |
После первого прогона выполните то, что скрипт печатает с пометкой !!:
# 1. IAM tenant нужен launcher'у рабочих мест, fleet-controller и исполнителям пакетов
sed -i "s/^IAM_TENANT_ID=.*/IAM_TENANT_ID=<tenant-id>/" .env
# 2. Ядро должно подхватить env-файл service account (CP_CONTEXT_AUTH=auto)
tools/compose up -d control-plane-api control-plane-worker context-adapter
Проверка, что ядро перешло с MEMORY_API_KEY на service account:
tools/compose exec context-adapter env | grep -c CP_IAM_CLIENT_ID # 1
tools/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. Вход людей и рабочие места (профили idp, harness)¶
Для входа людей через Keycloak после bootstrap нужно один раз зарегистрировать realm в IAM как identity provider, а затем для каждого человека: IAM principal, пользователь Keycloak, связь external identity, principal и binding в Control Plane, запись в реестре рабочих мест. Процедура — в статье Keycloak — внешний IdP.
Runner-хост¶
Автономных исполнителей запускает fleet: на машине исполнителей работает узел
(fleet-node, референсный compose — deploy/node/), который поднимает контейнеры
агентов из образа deploy/agent-runner/ по их описаниям в пакетах (см. Установка
исполнителя). Для отладки демон можно поставить и вручную —
в контейнере или как systemd-сервис.
Образ содержит демон control-plane-agent, кодового агента и, при
необходимости, тестовые базы в 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.
Чек-лист готовности к эксплуатации¶
-
.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-хост отделён от хоста платформы.