Files
orchestrator/docs/operations/REPLICATION.md
claude-bot 8351e91382 docs(deployment): ORCH-10a Lite-тираж — LITE_SETUP.md + канон watchdog-конфига + анти-дрейф контур
Закрывает Type A эпика ORCH-10 (поверх 10-common ORCH-101). Docs+tests
(паттерн ORCH-077/092): src/**, docker-compose.yml, Dockerfile, scripts/** —
ноль изменений; конвейер (STAGE_TRANSITIONS/QG_CHECKS/check_*/machine-verdict/
схема БД) — байт-в-байт.

- docs/deployment/LITE_SETUP.md (D1/D2): golden source Lite-тиража — 13
  нормативных разделов в порядке маршрута оператора, каждый шаг =
  fenced-команда + явная «Проверка:»/PASS/FAIL, хост-специфика только
  плейсхолдерами; канон не форкается (статусы/env/вебхуки/smoke — ссылками
  на ONBOARDING §1 / REPLICATION §2–§4 / SETUP_WEBHOOKS; явно — только
  fail-closed Confirm Deploy/STOP и обязательные ключи нового хоста).
- .env.watchdog.example (D5, исход А-4): третий канонический env-example;
  key-set = блок WATCHDOG_* .env.example (19 ключей, токены — пустые
  плейсхолдеры); закрывает ловушку файла-носителя (sidecar читает ТОЛЬКО
  .env.watchdog); C-1 ORCH-100 + когерентность порта в шапке; .env.watchdog
  добавлен в .gitignore (секрет-гигиена, зеркало .env.staging).
- tests/test_lite_setup_doc.py (D8): 25 структурных тестов без
  сети/LLM/subprocess — 13 разделов в порядке D2, кирпичи FR-6.1, key-sync
  watchdog-канона, env-ключи ⊂ .env.example, compose-подмножество (ровно
  орк+watchdog по дефолту, staging за профилем, анти-появление
  plane*/gitea*), fenced-скан FORBIDDEN (импорт из test_no_host_hardcodes)
  + секрет-эвристика с негативным самочеком, «22 статуса» сверкой импорта
  plane_sync._PLANE_NAME_TO_KEY, перекрёстность.
- Перекрёстные доки (FR-7): REPLICATION.md §1 (Type A — Lite →  ORCH-102 +
  ссылка), README.md (способность Lite + docs/deployment/ в структуре),
  INFRA.md (.env.watchdog в секрет-нормативе + ссылка на deployment),
  CLAUDE.md (блок ORCH-102), CHANGELOG.md.

Нормативы разделов: Gitea — branch protection на main НЕ включать (D3 /
ADR D10 ORCH-009 / INV-4), pre-receive не вводится, ОДИН глобальный
webhook-секрет; staging-вилка опциональна (D6); источник кода —
параметризованный git clone <ORCHESTRATOR_GIT_URL> (D7); stateless —
данные/задачи/секреты боевого хоста НЕ переносятся (AC-3).

Тесты: pytest tests/ -q — 1789 passed (полный регресс зелёный).

Refs: ORCH-102

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 00:42:15 +03:00

13 KiB
Raw Blame History

REPLICATION — тираж платформы на новую инфраструктуру (ORCH-101)

RUNBOOK фундамента тиража (эпик ORCH-10, слой 10-common). Как развернуть оркестратор на чужом хосте без правки кода: переменные → секреты → smoke. Тираж stateless: данные/БД/секреты боевого хоста НЕ переносятся ни на одном шаге — на целевой инфре всё создаётся заново.


1. Границы: 10-common vs Lite vs Bundled

Слой Что это Статус
10-common (этот док) фундамент: все хост-значения параметризованы (env/конфиг), секреты выпускаются заново, smoke-процедура с PASS/FAIL ORCH-101
Type A — Lite инструкция «поставь Plane+Gitea сам, подключи оркестратор» поверх 10-common ORCH-102 — docs/deployment/LITE_SETUP.md
Type B — Bundled комплект «всё в одном» (Plane+Gitea+оркестратор) поверх 10-common отдельная задача эпика

Этот док НЕ описывает установку Plane/Gitea — только параметризацию, секреты и smoke самого оркестратора (анти-скоуп-крип Р-5).

Платформенные конвенции тиража (нормативно, ADR-001 D3/D4)

  • Репо платформы обязан называться orchestrator. Имя — узел безопасности (SELF_HOSTING_REPO, на него завязаны все *_repos-leaf'ы «empty CSV → self-hosting only»); оно сознательно НЕ конфигурируется.
  • Имена compose-сервисов/профиля (orchestrator, orchestrator-staging, orchestrator-watchdog, профиль staging) — константы платформы.
  • Контейнерные пути (/app/data, /repos, /opt/claude-code) — layout контейнера, не хост-значения; не параметризуются.

2. Карта переменных нового хоста

Принцип (ADR-001 D1): дефолт каждой переменной = боевое значение текущего хоста — пустой .env ⇒ поведение байт-в-байт; на новом хосте задаёшь только то, что отличается. Одно env-имя = один факт: pydantic Settings читает имя из env_file, compose-интерполяция ${VAR:-default} — из .env проекта/shell (⚠️ НЕ из env_file сервиса: .env.staging на интерполяцию не влияет — значения для маунтов/uid/портов живут в .env).

2.1. Хост-параметризация (новое в ORCH-101)

Переменная Дефолт Назначение
ORCH_AGENT_HOME_DIR /home/slin HOME всех акторов (агенты, finalizer, monitor) + таргет маунтов .claude/.claude.json/.ssh + ARG APP_HOME (группа ORCH-040 двигается вместе)
ORCH_AGENT_GIT_NAME claude-bot git-имя коммитов агентов
ORCH_GIT_EMAIL_DOMAIN mva154.local домен git-email всех акторов (claude-bot@…, deploy-finalizer@…, post-deploy-monitor@…)
ORCH_STAGING_PORT 8501 порт staging; читают image_freshness И compose command:; guard: совпадение с прод-портом → отказ fail-closed (ORCH-058 AC-9)
ORCH_HOST_REPOS_DIR /home/slin/repos каталог репозиториев на хосте (источник маунта /repos)
ORCH_HOST_CLAUDE_DIR /home/slin/.claude источник маунта ~/.claude
ORCH_HOST_CLAUDE_JSON /home/slin/.claude.json источник маунта ~/.claude.json
ORCH_HOST_SSH_DIR /home/slin/.orchestrator-ssh источник маунта ssh-ключей (→ $HOME/.ssh:ro)
ORCH_HOST_CLAUDE_CODE_DIR /usr/lib/node_modules/@anthropic-ai/claude-code дистрибутив claude-code на хосте
ORCH_HOST_NODE_BIN /usr/bin/node бинарь node на хосте
ORCH_RUN_UID / ORCH_RUN_GID 1000 / 1000 uid:gid контейнера (user: + ARG APP_UID/APP_GID); = uid владельца ORCH_HOST_REPOS_DIR (ORCH-040)
ORCH_DOCKER_GID 999 gid группы docker хоста (group_add, «МИНА 1» — обязателен для docker.sock); узнать: getent group docker
ORCH_DEPLOY_PROD_TARGET_PORT 8500 (реюз) прод-порт; интерполируется в command: прод-сервиса
ORCH_DEPLOY_SSH_USER / ORCH_DEPLOY_HOST_REPO_PATH slin / /home/slin/repos/orchestrator (реюз) ssh-юзер хука и чекаут платформы на хосте; REPO= передаётся хуку явно из конфига

2.2. Обязательные ключи идентичности нового хоста

Переменная Где взять
ORCH_PLANE_API_URL / ORCH_PLANE_WEB_URL / ORCH_PLANE_WORKSPACE_SLUG инсталляция Plane целевого хоста
ORCH_GITEA_URL / ORCH_GITEA_PUBLIC_URL / ORCH_GITEA_OWNER инсталляция Gitea целевого хоста
ORCH_PROJECTS_JSON обязателен на новом хосте: встроенный fallback (src/projects.py) несёт Plane-UUID исходного хоста — чужие UUID безвредны (не сматчатся), но без своего реестра конвейер не увидит проекты. Сгенерировать: scripts/onboard_project.py apply печатает merged-значение
Когерентность портов сменил прод-порт → синхронно ORCH_DEPLOY_PROD_TARGET_PORTWATCHDOG_METRICS_URLORCH_POST_DEPLOY_BASE_URL

Полный справочник всех остальных флагов — .env.example (канон) и docs/operations/INFRA.md (карта env).


3. Секреты нового хоста (FR-4 / AC-5)

Нормативно: боевые секреты текущего хоста НЕ копируются ни на одном шаге. Для нового хоста всегда выпускается новый комплект.

3.1. Генерация локальных webhook-секретов

python3 scripts/gen_secrets.py            # печать .env-фрагмента в stdout
python3 scripts/gen_secrets.py --write    # создать .env (существующий → отказ exit=2)
python3 scripts/gen_secrets.py --write --force  # перезапись только явно

Скрипт stdlib-only (secrets.token_hex(32) — 32 байта энтропии); повторный запуск даёт другие значения; существующий .env никогда не перезаписывается молча.

Секрет Генерируется Куда вписать
ORCH_PLANE_WEBHOOK_SECRET локально (gen_secrets) .env + настройка webhook в Plane (см. SETUP_WEBHOOKS.md)
ORCH_GITEA_WEBHOOK_SECRET локально (gen_secrets) .env + webhook Gitea (создаёт onboard_project.py apply)

3.2. Чек-лист внешних токенов

Секрет Где выпустить Куда вписать Как проверить
ORCH_PLANE_API_TOKEN Plane UI → Workspace Settings → API tokens .env curl -H "X-API-Key: $TOKEN" $ORCH_PLANE_API_URL/api/v1/workspaces/<slug>/projects/ → 200
ORCH_PLANE_BOT_* (7, опциональны) Plane UI: bot-аккаунты per-агент; пусто → fallback на ORCH_PLANE_API_TOKEN .env комментарий в Plane от имени бота
ORCH_GITEA_TOKEN Gitea UI → Settings → Applications → Generate Token (scope: repo, admin:repo_hook) .env curl -H "Authorization: token $TOKEN" $ORCH_GITEA_URL/api/v1/user → 200
ORCH_TELEGRAM_BOT_TOKEN BotFather (/newbot) .env curl https://api.telegram.org/bot$TOKEN/getMe → ok
ORCH_TELEGRAM_CHAT_ID (несекретный) id чата оператора .env тестовое сообщение
WATCHDOG_TG_BOT_TOKEN / WATCHDOG_TG_CHAT_ID отдельный бот sidecar-watchdog (ORCH-100, независимый канал) .env.watchdog алерт от sidecar

3.3. Полнота

.env.example — канон 100% ключей старта (секретные значения — только плейсхолдеры). Состав вывода gen_secrets.py сверяется с .env.example тестом (tests/test_secrets_gen.py).


4. Smoke-верификация тиража (FR-5 / AC-3)

Процедура «инстанс → тестовый проект → тестовая задача → конвейер доехал» из существующих кирпичей; каждый шаг имеет явный PASS/FAIL. Итог — однозначный вердикт: все шаги PASS ⇒ тираж PASS; любой шаг FAIL ⇒ тираж FAIL (собери логи контейнера docker logs orchestrator и снапшот GET /queue и разбирайся).

Воспроизводимость без нового железа: процедура прогоняется на текущей инфре — staging-песочница (порт ORCH_STAGING_PORT, дефолт 8501) + sandbox-проект. Stateless: ни один шаг не предполагает перенос данных/БД/секретов.

# Шаг Команда PASS FAIL
0 Конфиг резолвится docker compose config резолв без ошибок; при пустом env значения = боевым дефолтам ошибка интерполяции / неожиданные значения
1 Инстанс жив curl -fsS http://127.0.0.1:<port>/health HTTP 200, "status":"ok" не-200 / таймаут
2 Контракты отвечают curl -fsS …/queue и …/metrics JSON со штатными блоками; /metricsschema_version: 1 не-JSON / 5xx
3 Тестовый проект python3 scripts/onboard_project.py planapplyverify (sandbox) verify зелёный (статусы/лейблы/repo/webhook на месте) verify красный / manual-step не выполнен
4 Тестовая задача создать issue в Plane → статус «To Analyse» задача в БД, analyst-job виден в GET /queue задача не появилась (webhook/секрет/реестр)
5 Минимальный сигнал «конвейер доехал» дождаться окончания analysis артефакты 0104 в ветке задачи: git ls-tree origin/<branch> docs/work-items/<id>/ стадия не завершилась / артефактов нет
6 Расширенный режим (опционально) Approved → … → Confirm Deploy задача дошла до done застряла (разбор по GET /queue + логам)

Ручной запуск deploy-хука на нестандартных портах — всегда с явными REPO=/TARGET_PORT= (wired-путь оркестратора передаёт их сам из конфига; дефолты хука — staging текущего хоста).


5. Что НЕ переносится (stateless, решение 10.06)

  • БД (data/orchestrator.db) — создаётся пустой при первом старте;
  • .env / .env.staging / .env.watchdog — собираются заново (§2§3);
  • worktree'ы/runs/логи — рабочее состояние, не данные;
  • боевые секреты — никогда (§3).

RUNBOOK ORCH-101. Поддерживать при добавлении хост-переменных (карта §2 + .env.example + INFRA.md в том же PR). Анти-регресс возврата хардкодов — tests/test_no_host_hardcodes.py; параметризация инфра-файлов — tests/test_infra_parametrization.py.