Files
orchestrator/docs/operations/DEPLOY_HOOK.md
claude-bot 6ddff5583d
All checks were successful
CI / test (push) Successful in 19s
CI / test (pull_request) Successful in 18s
fix(ORCH-058): parametrize staging_check in --build-staging + explicit staging target
Round-3 review follow-up on c53d625 (P1/P2):

- P1: --build-staging now runs staging_check via parametrized
  STAGING_CONTAINER / STAGING_CHECK_PATH / STAGING_CHECK_MODE (default
  orchestrator-staging / bind-mount path / stub) instead of hardcoding
  $TARGET_SERVICE + the script path. docker exec runs INSIDE the staging
  container (ORCH-048 canonical: B6 registry isolation), after health,
  before exit 0. Fail-closed: any non-zero -> exit 1. STAGING only (8501).
- P2a: rebuild_staging_image now passes the STAGING target EXPLICITLY
  (TARGET_SERVICE/TARGET_PORT/COMPOSE_PROFILE/STAGING_CONTAINER) so the
  self-rebuild can never drift onto prod 8500 if hook defaults change (AC-9).
- P2b: TC-09 caller<->hook contract tests assert the ssh command carries
  GIT_SHA + BUILD_CONTEXT + the staging target and never the prod 8500 one;
  no-ssh-host fails closed.
- P3: consolidated the three duplicate README footers into one.
- Docs (golden source): DEPLOY_HOOK.md step 4 + env rows, README footer,
  CHANGELOG, Dockerfile ARG GIT_SHA="" comment, .env.example freshness block.

Validates exactly the artefact later BUILD-ONCE retagged to prod (AC-4,
ADR-001 step 3). 632 tests pass, ruff clean, bash -n OK.

Refs: ORCH-058

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 09:24:38 +00:00

10 KiB
Raw Permalink Blame History

Orchestrator Deploy Hook

scripts/orchestrator-deploy-hook.sh — хост-скрипт деплоя orchestrator с health-чеком и авто-rollback.

Как работает

Режим --deploy (по умолчанию)

  1. Захват текущего образа — до рестарта записывает ID образа работающего контейнера в $PREV_IMAGE_FILE (best-effort, не падает если сервис не запущен).
  2. git pull — обновляет код репозитория. 2b. Build-once retag (ORCH-036, BR-6) — если задан $SOURCE_IMAGE, хук ретегает его на $TARGET_IMAGE (docker tag $SOURCE_IMAGE $TARGET_IMAGE) и поднимает контейнер на этом образе через up -d --no-build. Это деплой РОВНО того образа, что прошёл staging, без docker build. Если $SOURCE_IMAGE не задан (дефолт) — шаг пропускается (обратная совместимость).
    • Fail-closed провенанс-guard (ORCH-058, Strategy B) — ПЕРЕД docker tag, если задан $EXPECTED_REVISION, хук сверяет OCI-лейбл org.opencontainers.image.revision у $SOURCE_IMAGE с $EXPECTED_REVISION. Несовпадение / пустой лейбл (<no value>) / ошибка inspect → лог + exit 1 (FAILED → авто-rollback), прод не трогается. Не задан $EXPECTED_REVISION (дефолт) → проверка пропускается (обратная совместимость для не-self репозиториев).
  3. Рестарт контейнераdocker compose --profile $COMPOSE_PROFILE up -d --no-build $TARGET_SERVICE.
  4. Health-цикл — 10 попыток × 6с = до 60с. Критерий: HTTP 200 + тело содержит "status":"ok".
    • Успехexit 0, лог "Deploy SUCCESS".
    • Провал → авто-rollback (шаг 5).
  5. Авто-rollback — восстанавливает образ из $PREV_IMAGE_FILE, рестарт, повторный health 5×3с.
    • Если восстановился → exit 1 (деплой провалился, откат успешен).
    • Если и откат не помог → exit 2 (критично).

Режим --build-staging (ORCH-058, Strategy A)

Пересобирает staging-образ из провалидированного коммита и пересоздаёт 8501, чтобы артефакт, который мы валидируем, был РОВНО тем, что позже build-once ретегается в прод (инвариант INV-FRESH). Собирает/пересоздаёт только staging (8501) — никогда прод (8500).

  1. docker build --build-arg GIT_SHA=$GIT_SHA -t $TARGET_IMAGE $BUILD_CONTEXT — пересборка из host-worktree валидированного коммита; GIT_SHA штампуется в OCI-лейбл org.opencontainers.image.revision.
  2. docker compose [--profile $COMPOSE_PROFILE] up -d --no-build $TARGET_SERVICE — пересоздание staging на свежем образе.
  3. Health-цикл 10×6с. Провал сборки/health → exit 1.
  4. staging_check против СВЕЖЕГО образа (Strategy A, шаг 3 — ADR-001, AC-4) — после health хук запускает docker exec $STAGING_CONTAINER python3 $STAGING_CHECK_PATH --base-url http://localhost:$TARGET_PORT --mode $STAGING_CHECK_MODE (дефолт --mode stub, без LLM-трат). Запуск внутри staging-контейнера канонический (ORCH-048): suite читает реестр из собственного env контейнера, а staging_check.py берётся из bind-mount (/repos/orchestrator/scripts/..., не из образа). Это ровно тот артефакт, что позже build-once ретегается в прод → валидируем то, что промоутим (AC-4). PASS → exit 0; любой не-ноль (FAIL чека или safety-abort ORCH_STAGING≠true) → exit 1.

Запускается оркестратором на ребре deploy-staging → deploy (QG-под-чек check_staging_image_freshrebuild_staging_image пробрасывает явный staging-таргет, см. INFRA.md). Тот же контракт кодов выхода (0 = здоров и staging_check PASS).

Режим --rollback

Вручную откатывает сервис на предыдущий образ из $PREV_IMAGE_FILE.

Переменные окружения

Переменная Дефолт Описание
TARGET_SERVICE orchestrator-staging Имя docker-compose сервиса
TARGET_PORT 8501 Порт health-check
TARGET_IMAGE orchestrator-orchestrator-staging Имя образа для retag при rollback
COMPOSE_PROFILE staging Docker compose profile (пусто = без профиля)
PREV_IMAGE_FILE $REPO/.deploy-prev-image-staging Файл для сохранения предыдущего образа
SOURCE_IMAGE (unset) Build-once (ORCH-036): провалидированный образ для retag на $TARGET_IMAGE перед рестартом (без rebuild). Не задан → шаг пропущен.
EXPECTED_REVISION (unset) Build-once (ORCH-058, Strategy B): ожидаемый git-SHA $SOURCE_IMAGE (лейбл org.opencontainers.image.revision). Задан → fail-closed guard перед docker tag. Не задан → проверка пропущена.
GIT_SHA (unset) --build-staging (ORCH-058, Strategy A): коммит, штампуемый в OCI-лейбл revision при пересборке staging-образа.
BUILD_CONTEXT $REPO --build-staging: docker build context (host-worktree валидированного коммита).
STAGING_CONTAINER $TARGET_SERVICE (orchestrator-staging) --build-staging (ORCH-058): контейнер, внутри которого docker exec запускает staging_check.
STAGING_CHECK_PATH /repos/orchestrator/scripts/staging_check.py --build-staging (ORCH-058): путь к staging_check.py внутри контейнера (bind-mount, не образ).
STAGING_CHECK_MODE stub --build-staging (ORCH-058): режим staging_check (stub — быстро, без LLM; full-real — дожидается аналитика).
LOG /var/log/orchestrator/deploy-hook.log Лог-файл (fallback: $REPO/deploy-hook.log)

⚠️ Дефолт — всегда STAGING. Прод активируется только явным переопределением env.

Примеры запуска

Staging (дефолт, безопасно)

cd /home/slin/repos/orchestrator
bash scripts/orchestrator-deploy-hook.sh --deploy
# или просто:
bash scripts/orchestrator-deploy-hook.sh

Прод (осознанный шаг, Этап 5)

TARGET_SERVICE=orchestrator \
TARGET_PORT=8500 \
TARGET_IMAGE=orchestrator-orchestrator \
COMPOSE_PROFILE="" \
PREV_IMAGE_FILE=/home/slin/repos/orchestrator/.deploy-prev-image-prod \
bash scripts/orchestrator-deploy-hook.sh --deploy

Прод build-once (ORCH-036) — ретег staging-образа, без rebuild

Так прод-деплой запускается автоматически исполняемым самодеплоем (Фаза B: ssh + setsid, см. INFRA.md). Ключевое отличие — SOURCE_IMAGE указывает на провалидированный staging-образ, который ретегается на прод-тег:

SOURCE_IMAGE=orchestrator-orchestrator-staging \
TARGET_SERVICE=orchestrator \
TARGET_PORT=8500 \
TARGET_IMAGE=orchestrator-orchestrator \
COMPOSE_PROFILE="" \
PREV_IMAGE_FILE=/home/slin/repos/orchestrator/.deploy-prev-image-prod \
bash scripts/orchestrator-deploy-hook.sh --deploy

Ручной rollback staging

bash scripts/orchestrator-deploy-hook.sh --rollback

Коды выхода

Код Значение
0 Деплой успешен, сервис здоров
1 Деплой провалился; откат выполнен (или пропущен)
2 Деплой провалился И откат тоже провалился (критично)

Логи

/var/log/orchestrator/deploy-hook.log

Каждая строка с UTC-таймстампом в формате [2026-06-05T06:30:00Z].

Разница с enduro-deploy-hook.sh

Функция enduro-deploy-hook.sh orchestrator-deploy-hook.sh
Захват PREV_IMG
git pull
Рестарт
Health-цикл (60с) 10×6с
Авто-rollback
Параметризация (env) хардкод дефолт=staging
Compose profile --profile staging