146 lines
14 KiB
Markdown
146 lines
14 KiB
Markdown
---
|
||
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).
|