15 KiB
INFRA.md — инфраструктура и эксплуатация оркестратора
RUNBOOK. Топология, контейнеры, порты, переменные окружения, границы. Секреты тут НЕ хранятся — только дескрипторы. Реальные значения — в
.envна хосте.
Топология
host: mva154 (slin@82.22.50.71), network_mode: host
┌──────────────────────────────────────────────────────────────────────┐
│ orchestrator (PROD) :8500 env_file .env │
│ БД: ./data/orchestrator.db (обслуживает ВСЕ прод-проекты) │
│ │
│ orchestrator-staging (STAGING) :8501 env_file .env.staging │
│ БД: ./data/staging/orchestrator.db (изолирована, только sandbox) │
│ profile: staging — НЕ стартует обычным `docker compose up` │
└──────────────────────────────────────────────────────────────────────┘
│ webhooks │ git
▼ ▼
Plane (ag_proj) Gitea (localhost:3000)
/repos/<project> ← общий каталог репозиториев (host: /home/slin/repos)
Контейнеры
| Контейнер | Роль | Порт | env_file | БД (хост) | Старт |
|---|---|---|---|---|---|
orchestrator |
прод | 8500 | .env |
./data/orchestrator.db |
docker compose up -d |
orchestrator-staging |
staging / песочница | 8501 | .env.staging |
./data/staging/orchestrator.db |
docker compose --profile staging up -d orchestrator-staging |
Оба: network_mode: host, init: true (tini как PID 1 — reaping зомби, B-2), restart: unless-stopped.
Рантайм-uid (ORCH-040)
Оба сервиса бегут под user: "1000:1000" (slin), не root. Артефакты конвейера
(git worktree /repos/_wt/..., коммиты в docs/work-items/...) создаются как
slin:slin, поэтому git pull / git reset на хосте под slin работают без ручного
chown. Доступ к docker.sock сохранён через group_add: ["999"] (gid docker, не
через root — НЕ удалять). При переносе на другой хост uid пересматривается. См.
ADR docs/work-items/ORCH-040/06-adr/ADR-001-run-agents-as-host-uid.md и глобальный
docs/architecture/adr/adr-0005-container-runs-as-host-uid.md.
Host-prerequisites (обязательная процедура Owner, в git не коммитятся):
- P-1 (блокер): uid 1000 читает claude creds —
chown -R 1000:1000 /home/slin/.claude; проверкаsudo -u '#1000' test -r /home/slin/.claude/.credentials.json. Без этого preflight (ORCH-044) заворачивает весь конвейер. - P-2: ssh-ключи в
/home/slin/.orchestrator-sshчитаемы uid 1000 (маунт ведёт в/home/slin/.ssh). - P-3:
id slin→1000:1000;/repos,/app/dataуже1000:1000. - P-4: прод-рестарт self — только в окно тишины (
GET /statusбез активных задач): общий инстанс с enduro-trails. - Разовый разгребающий
chown -R 1000:1000 /home/slin/repos/orchestratorдля старыхroot:rootфайлов из истории (вне объёма кода).
Тома (volumes)
./data→/app/data(БД; у staging —./data/staging)/home/slin/repos→/repos(рабочие репозитории проектов)/var/run/docker.sock(для docker-операций деплоя)- claude-code, node,
~/.claude*(CLI агентов, ro) ~/.orchestrator-ssh→/home/slin/.ssh(ro, деплой по ssh; target в HOME агента, согласован сHOME=/home/slinиз launcher — ORCH-040, ранее/root/.ssh)
Переменные окружения (карта; значения — в .env)
| Переменная | Назначение |
|---|---|
ORCH_PLANE_API_URL / _TOKEN / _WORKSPACE_SLUG |
доступ к Plane API |
ORCH_PLANE_WEB_URL |
внешний (браузерный) web-URL Plane для кликабельных ссылок на issue в уведомлениях (ORCH-017); пусто → фолбэк на ORCH_PLANE_API_URL, loopback-фолбэк → ссылка опускается |
ORCH_PLANE_WEBHOOK_SECRET |
HMAC-проверка вебхуков Plane |
ORCH_GITEA_URL / _TOKEN / _WEBHOOK_SECRET |
доступ к Gitea + HMAC |
ORCH_CLAUDE_BIN |
путь к claude CLI |
ORCH_REPOS_DIR / ORCH_HOST_REPOS_DIR |
каталог репозиториев (в контейнере / на хосте) |
ORCH_DB_PATH |
путь к SQLite БД |
ORCH_PROJECTS_JSON |
реестр проектов (Plane id → repo + prefix); пусто → дефолт из src/projects.py |
ORCH_AGENT_MODEL_DEFAULT |
LLM-модель агентов по умолчанию (ORCH-41); дефолт claude-opus-4-8 |
ORCH_AGENT_MODEL_<AGENT> |
per-agent модель (ANALYST/ARCHITECT/DEVELOPER/REVIEWER/TESTER/DEPLOYER); пусто → default |
ORCH_AGENT_EFFORT_DEFAULT |
режим работы --effort по умолчанию (ORCH-41): low|medium|high|xhigh|max; дефолт high |
ORCH_AGENT_EFFORT_<AGENT> |
per-agent effort; дефолт: думающие → high, tester/deployer → medium |
ORCH_AGENT_FALLBACK_MODEL |
опц. фолбэк-модель при overloaded (--fallback-model); пусто → без флага |
ORCH_SELF_DEPLOY_ENABLED |
ORCH-036 kill-switch исполняемого самодеплоя (true); false → legacy-путь для всех |
ORCH_SELF_DEPLOY_REPOS |
CSV репозиториев с реальным самодеплоем; пусто → только self-hosting orchestrator |
ORCH_DEPLOY_REQUIRE_MANUAL_APPROVE |
требовать человеческий Plane «Approved» для прод-деплоя (true, безопасно) |
ORCH_DEPLOY_FINALIZE_DELAY_S / _MAX_ATTEMPTS |
задержка и бюджет defer'ов finalizer'а (Фаза C; 90 / 10) |
ORCH_DEPLOY_SSH_USER / _SSH_HOST |
куда запускается detached хост-деплой (Фаза B, ssh user@host) |
ORCH_DEPLOY_HOOK_SCRIPT / _HOST_REPO_PATH |
путь к хук-скрипту (отн. репо) и чекаут orchestrator на хосте |
ORCH_DEPLOY_PROD_SOURCE_IMAGE |
staging-образ для build-once retag на прод-тег (без rebuild) |
ORCH_DEPLOY_PROD_TARGET_SERVICE / _TARGET_PORT / _TARGET_IMAGE / _COMPOSE_PROFILE / _PREV_IMAGE_FILE |
прод-цель хука + снапшот для авто-rollback |
ORCH_IMAGE_FRESHNESS_ENABLED |
ORCH-058 единый kill-switch провенанса staging-образа (A+B как целое); дефолт true, false → legacy build-once без проверки свежести |
ORCH_IMAGE_FRESHNESS_REPOS |
CSV репозиториев с реальным гейтом свежести; пусто → только self-hosting orchestrator |
ORCH_RECONCILE_ENABLED |
kill-switch sweeper потерянных webhook (ORCH-053); дефолт true. При инциденте/раскатке — false глушит весь фоновый reconciler |
ORCH_RECONCILE_PLANE_ENABLED |
отдельный флаг F-2 (опрос Plane API); false гасит только plane-ветку, F-1 продолжает работать; дефолт true |
ORCH_RECONCILE_INTERVAL_S |
период фонового прохода reconciler, сек; дефолт 120 |
ORCH_RECONCILE_GRACE_DEFAULT_S |
порог «застряла» по tasks.updated_at, сек; дефолт 600 |
ORCH_RECONCILE_GRACE_OVERRIDES_JSON |
per-stage пороги, напр. {"development":300}; невалидный JSON → дефолт |
ORCH_RECONCILE_NOTIFY_UNBLOCK |
слать Telegram при разблокировке застрявшей задачи; дефолт true |
DEPLOY_SSH_USER / _HOST / DEPLOY_HOOK_SCRIPT |
параметры деплой-хука |
Секреты — только в .env / .env.staging на хосте, в гит НЕ коммитятся. Канон — .env.example, .env.staging.example.
Реестр проектов (src/projects.py, ORCH-6)
Связывает Plane project id → gitea repo + work-item prefix. Источник: ORCH_PROJECTS_JSON, fallback — встроенный дефолт. Прод видит: enduro-trails (ET), orchestrator (ORCH). Staging видит ТОЛЬКО orchestrator-sandbox (SANDBOX) — изоляция.
Модель и effort агентов (src/config.py + src/agents/launcher.py, ORCH-41)
Модель LLM и режим работы (--effort) каждого агента конфигурируемы — глобально per-agent (env) и per-project (через ORCH_PROJECTS_JSON).
Приоритет резолвинга (resolve_agent_model / resolve_agent_effort):
- per-project override —
agent_models/agent_effortsв записиORCH_PROJECTS_JSON; - per-agent env —
ORCH_AGENT_MODEL_<AGENT>/ORCH_AGENT_EFFORT_<AGENT>(если непусто); - глобальный дефолт —
ORCH_AGENT_MODEL_DEFAULT(claude-opus-4-8) /ORCH_AGENT_EFFORT_DEFAULT(high); - пусто → флаг не передаётся, действует дефолт CLI.
Значения effort: low < medium < high < xhigh < max — рычаг «качество vs стоимость/время». Дефолтная раскладка: думающие агенты (analyst/architect/developer/reviewer) → high, механические (tester/deployer) → medium. Невалидное значение → лог-warning, флаг опускается.
Per-project override в ORCH_PROJECTS_JSON (поля agent_models / agent_efforts опциональны, старые записи работают):
{"plane_project_id":"...","repo":"orchestrator","work_item_prefix":"ORCH",
"agent_models":{"developer":"claude-opus-4-8","reviewer":"claude-sonnet-4-6"},
"agent_efforts":{"developer":"xhigh","tester":"low"}}
⚠️ Бюджет (ORCH-38):
claude-opus-4-8дефолт в коде; реальное переключение прод-env делается отдельно после согласования.
⚠️ Self-hosting — оркестратор дорабатывает САМ СЕБЯ
Факт: прод-инстанс orchestrator (8500) — ОДИН на ВСЕ прод-проекты (enduro-trails + orchestrator), с ОБЩЕЙ БД ./data/orchestrator.db и общей очередью задач (ORCH-1).
Следствие — групповой риск: когда орк выполняет задачу из проекта ORCH (дорабатывает себя), он бежит в том же инстансе, что обслуживает enduro-trails.
- Рестарт / падение прод-контейнера орк-задачей → конвейер ВСЕХ проектов встаёт.
- Кривой self-деплой (ORCH-36, Вариант B) → лежат все проекты сразу.
- Общая очередь → орк-задача занимает concurrency-слоты других проектов.
Что изолировано (безопасно):
- Staging (8501) — отдельная БД (
./data/staging), отдельный реестр (ORCH_PROJECTS_JSON= только sandbox). Прод-проекты не видит. - Репозитории разделены, изоляция веток через git worktree (ORCH-2).
Страховки:
- Стадия
deploy-staging(порт 8501) — обязательный гейт перед прод-деплоем орка. Прод-деплой недостижим, пока staging-гейт не зелёный (см.STAGING.md, ORCH-35). Гейт условный: реален только для self-hosting (repo=orchestrator), для остальных проектов — no-op. - Свежесть staging-образа (ORCH-058): на ребре
deploy-staging → deploy(ПОСЛЕ merge-gate, ДО Phase A) QG-под-чекcheck_staging_image_freshпересобирает staging-образ из валидированного коммита и пересоздаёт 8501 (Strategy A), а хук перед build-once retag fail-closed сверяет OCI-лейблrevisionсEXPECTED_REVISION(Strategy B). Гарантирует: в прод промоутится РОВНО провалидированный артефакт (инцидент LESSONS_ORCH-036 п.4 — тихий промоут устаревшего образа). Сборки/recreate — ТОЛЬКО staging (8501); FAIL → откат наdevelopment. Условный: реален только для self-hosting.
Правила для агентов при задачах ORCH:
- НЕ перезапускать / не ронять прод-контейнер
orchestratorв рамках задачи. - Все проверки деплоя — на staging (8501), боевой 8500 не трогать.
- Деплой self — только через хук с health-check + авто-rollback (
DEPLOY_HOOK.md).
Эксплуатация (быстрые команды)
# статус
docker ps --filter name=orchestrator
curl -s http://localhost:8500/health
curl -s http://localhost:8500/status # активные задачи
curl -s http://localhost:8500/queue # очередь
# поднять staging-песочницу
docker compose --profile staging up -d orchestrator-staging
curl -s http://localhost:8501/health
# логи
docker logs --tail 100 orchestrator
RUNBOOK 2026-06-05. Обновлять при изменении топологии/портов/переменных. См. CONTRIBUTING.md §8.