Files
orchestrator/docs/work-items/ORCH-062/01-brd.md

146 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
work_item: ORCH-062
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-09
model_used: claude-opus-4-8
---
# 01 — BRD (бизнес-требования): ORCH-062 — INFRA: авто-prune docker build cache на mva154
Work Item: **ORCH-062** · Repo: **orchestrator** · Стадия: analysis
## 1. Бизнес-контекст и проблема
**Установленный факт (инцидент 07.06.2026).** Хост-диск mva154 тихо дорос до 100% и положил
**весь конвейер всех проектов** (один прод-инстанс `orchestrator` на общей БД/очереди обслуживает
и `enduro-trails`, и `orchestrator`). Доминирующий «пожиратель» в этом инциденте — **docker build
cache**: частые пересборки образа (`docker compose up -d --build` при прод-деплое, пересборки
staging-образа `--profile staging` и `check_staging_image_fresh` ORCH-058) накапливают слои build
cache, который дорос до **≈11 ГБ**. Заполнение диска положило **CI + Gitea** и остановило приём
вебхуков/обработку очереди.
**Что уже сделано (ORCH-063, не дублировать).** Введён фоновый daemon `src/disk_watchdog.py`,
который **только сигнализирует** (Telegram-алерт при заполнении ≥85%). В ADR/INFRA ORCH-063 явно
зафиксировано: *«watchdog только сигнализирует — он не трогает диск/контейнер … Авто-очистка — вне
объёма ORCH-063 (отдельная задача)»*. **ORCH-062 — и есть эта отдельная задача:** автоматическое
освобождение места за счёт build cache, чтобы инцидент 07.06 не повторялся и не требовал ручного
вмешательства оператора.
**Приоритет:** P1 (риск повторной полной остановки конвейера всех проектов).
## 2. Объём (scope)
### В объёме
- Автоматическое периодическое освобождение **docker build cache** на хосте mva154, чтобы он не
мог бесконтрольно дорасти до заполнения диска.
- Удержание «тёплого» недавнего кэша (политика хранения по возрасту, ориентир из запроса —
`until=24h`), чтобы не убивать скорость штатных пересборок.
- Наблюдаемость результата авто-prune для оператора (когда последний раз отработал, сколько
освобождено / текущий объём build cache).
- Обратимость: kill-switch и конфигурируемость периода/порога/политики хранения.
- Документирование операционной процедуры в `docs/operations/INFRA.md` (и инфра-требований в
`07-infra-requirements.md` — заполняет архитектор).
### Вне объёма
- **Очистка прочих «пожирателей» диска** (старые worktree-каталоги `/home/slin/repos/_wt/*`
завершённых задач, логи, dangling-образы `docker image prune`) — это **ручная** операция
оператора по ORCH-063; авто-уборка этих категорий — отдельные задачи, здесь НЕ делается.
- **Изменение поведения disk-watchdog** (`src/disk_watchdog.py`, пороги/алерты ORCH-063) — не
трогаем; ORCH-062 ортогонален и комплементарен (watchdog сигналит, pruner убирает).
- **Любое управление конвейером / стадиями / Quality Gates.** Авто-prune — операционная фоновая
задача, НЕ элемент `STAGE_TRANSITIONS` / `QG_CHECKS` (ровно как watchdog/reconciler/job_reaper).
- **Перезапуск/рестарт прод-контейнера** `orchestrator` ради уборки — категорически вне объёма
(self-hosting групповой риск).
- Выбор между конкретными механизмами реализации (heartbeat-демон в приложении vs host
`daemon.json builder.gc` vs host-cron) — это **архитектурное решение** (06-adr), не предмет BRD.
## 3. Заинтересованные стороны
- **Owner / оператор (slin, homenet542@gmail.com)** — заказчик, принимает результат, владеет
хостом mva154 и его host-prerequisites.
- **Все прод-проекты** (`enduro-trails`, `orchestrator`) — косвенно затронуты: общий инстанс,
общий диск; падение диска = простой всех.
- **Self-hosting контур** — изменение касается инструмента, который работает в проде и обслуживает
другие проекты; безопасность изменения критична.
## 4. Бизнес-требования (BR)
- **BR-1 (авто-освобождение)** — docker build cache очищается **автоматически, периодически, без
ручного вмешательства** оператора, так что он не может бесконтрольно заполнить диск (устранение
корня инцидента 07.06).
- **BR-2 (удержание тёплого кэша)** — очистка удаляет преимущественно **старый** build cache
(политика по возрасту, ориентир `until=24h`); свежий кэш недавних сборок сохраняется, чтобы
штатные пересборки не теряли скорость без необходимости.
- **BR-3 (self-hosting безопасность)** — операция уборки **никогда не нарушает работу запущенных
контейнеров и не удаляет образы/слои, используемые работающими прод-контейнерами**, и **никогда
не рестартит/не роняет прод**. Затрагивается **только build cache** (`docker builder prune`), не
образы запущенных сервисов.
- **BR-4 (наблюдаемость)** — оператор может увидеть состояние авто-prune: включён ли, когда
последний раз отработал, объём/освобождено (через тот же канал наблюдаемости, что у фоновых
демонов — блок в `GET /queue`, и/или Telegram при значимом освобождении).
- **BR-5 (обратимость)** — поведение управляется **kill-switch**: выключение возвращает систему к
поведению «как сейчас» 1:1 (никакой авто-уборки), как у `ORCH_DISK_MONITOR_ENABLED` /
`ORCH_RECONCILE_ENABLED`.
- **BR-6 (конфигурируемость)** — период, порог запуска и политика хранения (возраст/объём
удержания) задаются конфигом (env), с безопасными дефолтами; невалидные значения деградируют на
дефолт (как валидаторы ORCH-063).
## 5. Нефункциональные требования (NFR)
- **NFR-1 (never-raise)** — фоновая уборка не должна ронять процесс/конвейер ни на одном уровне:
ошибка docker-команды / недоступность docker.sock / таймаут логируются и проглатываются (как
per-tick/per-send never-raise в `disk_watchdog.py`).
- **NFR-2 (изоляция от Quality Gate)** — `STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / схема БД
**не изменяются**; авто-prune — операционный демон/процедура, не гейт.
- **NFR-3 (нулевая регрессия при выключении)** — при выключенном kill-switch поведение байт-в-байт
как до задачи; никакого фонового потока/процедуры не стартует.
- **NFR-4 (низкий оверхед)** — частота уборки — порядка часов; сама команда `docker builder prune`
дешева и не должна влиять на латентность конвейера; уборка не должна конкурировать за ресурсы с
активными сборками сверх необходимого.
- **NFR-5 (best-effort состояние)** — учёт «когда убирали в последний раз» может быть in-memory /
best-effort (как анти-спам watchdog'а): сброс при рестарте безопасен (приведёт максимум к одной
лишней безопасной уборке), без новой миграции БД.
- **NFR-6 (документируемость)** — операционная процедура, env-переменные и поведение при сбое
зафиксированы в `docs/operations/INFRA.md` и `.env.example` в том же PR (golden source = код+доки).
## 6. Допущения и ограничения
- **A-1.** У контейнера `orchestrator` есть доступ к `/var/run/docker.sock` (через `group_add:
["999"]`, gid docker — НЕ удалять, ORCH-040), что технически позволяет приложению вызывать
`docker builder prune`. Это **не предрешает** выбор реализации (демон в приложении vs host-уровень).
- **A-2.** `docker builder prune` по контракту docker затрагивает **только build cache**, не
останавливает контейнеры и не удаляет образы запущенных сервисов — это основа безопасности BR-3.
- **A-3.** Доминирующий «пожиратель» в инциденте — именно build cache (≈11 ГБ); прочие категории
(worktree/логи/dangling-образы) адресуются отдельно (см. Вне объёма).
- **A-4.** Хост — mva154 (`network_mode: host`), uid рантайма 1000:1000; любые host-prerequisites
(например, права на docker.sock, настройка `daemon.json` если выбран этот путь) — процедура
Owner, в git не коммитятся (по аналогии с P-1…P-4 в INFRA.md).
- **Ограничение C-1.** Нельзя рестартить docker daemon в рабочее время без окна тишины, если
выбранный архитектором путь (`daemon.json builder.gc`) требует перезапуска демона — это решает и
планирует архитектор/Owner (вне объёма кода).
## 7. Критерии успеха
- Build cache на mva154 удерживается в безопасных пределах **автоматически**: после внедрения
повторение сценария 07.06 (build cache → 11 ГБ → диск 100%) предотвращается без ручных действий.
- Свежие сборки не теряют скорость без необходимости (тёплый кэш ≤ политики хранения сохраняется).
- Запущенные прод-контейнеры и обслуживание `enduro-trails` не затронуты; прод не рестартился.
- Оператор видит состояние авто-prune и может его выключить одним флагом.
- Детальные PASS/FAIL — в `03-acceptance-criteria.md`.
## 8. Риски
Краткий перечень (детальная проработка — `10-tech-risks.md`, заполняет архитектор):
- **R-1.** Слишком агрессивная политика (`-a` без возрастного фильтра / малый `until`) убивает
тёплый кэш → каждая сборка «холодная» и медленная. Митигирует BR-2 (удержание по возрасту).
- **R-2.** Гонка уборки с активной сборкой staging/прод-образа (`check_staging_image_fresh`,
build-once retag) → теоретически удаление кэша во время сборки. `docker builder prune` штатно не
трогает кэш, занятый активной сборкой, но политику/таймиг проверить (адресует архитектор).
- **R-3.** Реализация через host-`daemon.json` требует рестарта docker daemon → риск для
self-hosting; реализация через демон в приложении требует доступа к docker.sock и устойчивости к
его недоступности.
- **R-4.** Ошибочное расширение скоупа на `docker image prune` / `system prune` → удаление образов
запущенных контейнеров. Жёстко исключено BR-3 (только build cache).