---
work_item: ORCH-062
stage: architecture
author_agent: architect
status: proposed
created_at: 2026-06-09
model_used: claude-opus-4-8
---

# 07 — Инфра-требования: ORCH-062 — авто-prune docker build cache на mva154

Work Item: **ORCH-062** · Repo: **orchestrator** · Стадия: architecture

> Решение: **Вариант A** (фоновый демон приложения, `docker builder prune` на хосте через ssh) —
> см. `06-adr/ADR-001-build-cache-pruner.md`. Этот файл фиксирует host-prerequisites выбранного
> пути и задокументированный ручной fallback (Вариант C, host-cron).

## I-1. Топология / окружения

- Без изменений топологии: **новый внутренний фоновый daemon-поток** в существующем прод-контейнере
  `orchestrator` (8500), наравне с `reconciler`/`job_reaper`/`disk_watchdog`. Новых контейнеров,
  портов, сетей, томов — **нет**.
- Уборка исполняется **на хосте mva154** (host docker daemon — там физически живёт build cache)
  через уже существующий ssh-канал `deploy_ssh_user@deploy_ssh_host`
  (по образцу `image_freshness`/`self_deploy` Phase B). В контейнере `docker` CLI **нет**
  (`Dockerfile:11` — только `openssh-client git curl`), поэтому raw-вызов CLI в контейнере
  невозможен — только ssh на хост.

## I-2. Переменные окружения / секреты

Новые env (дефолты безопасны; полная карта — `docs/operations/INFRA.md`; канон — `.env.example`):

| env | Дефолт | Назначение |
|-----|--------|------------|
| `ORCH_BUILD_CACHE_PRUNE_ENABLED` | `true` | kill-switch; `false` → демон не стартует, 1:1 как до задачи |
| `ORCH_BUILD_CACHE_PRUNE_INTERVAL_S` | `21600` (6ч) | период тика, сек (валидация >0, иначе → дефолт) |
| `ORCH_BUILD_CACHE_PRUNE_UNTIL` | `24h` | возраст удержания тёплого кэша (`--filter until=`); валидация `^\d+[smhdw]?$`, иначе → `24h` |
| `ORCH_BUILD_CACHE_PRUNE_ALL` | `false` | добавить `-a` (только в паре с `until`) |
| `ORCH_BUILD_CACHE_PRUNE_TIMEOUT_S` | `120` | таймаут ssh-команды, сек |
| `ORCH_BUILD_CACHE_PRUNE_NOTIFY_MIN_GB` | `0` | Telegram при освобождении ≥ N ГБ; `0` → тихо |

- Переиспользуются существующие `ORCH_DEPLOY_SSH_USER` (дефолт `slin`) / `ORCH_DEPLOY_SSH_HOST` как
  ssh-таргет. **Пустой `ORCH_DEPLOY_SSH_HOST` → тик no-op** (фича не активна вне self-host).
- Секретов не добавляет. ssh-ключи уже проброшены ro (`~/.orchestrator-ssh → /home/slin/.ssh`,
  ORCH-040); в git не коммитятся.

## I-3. Деплой / рестарт

- **Рестарт docker daemon — НЕ требуется** (ключевое отличие от отклонённого Варианта B). Уборка —
  это `docker builder prune` (BuildKit GC), без правки `daemon.json`.
- **Рестарт прод-контейнера ради уборки — категорически НЕ требуется и запрещён** (self-hosting
  групповой риск). Сам код демона активируется штатным конвейерным деплоем оркестратора
  (staging 8501 → Confirm Deploy → prod), не отдельной операцией.
- Host-prerequisites выбранного пути A (процедура Owner, в git не коммитятся — как P-1…P-4 в
  INFRA.md):
  1. На хосте установлен `docker` и пользователь `slin` — в группе `docker` (уже выполняется:
     деплой-хук запускает `docker compose` на хосте).
  2. ssh с контейнера на хост под `slin` работает без пароля (уже настроено для Phase B деплоя).
  Иные действия Owner не требуются — фича включена дефолтом и активна при наличии ssh-таргета.

### Ручной fallback (Вариант C, host-cron) — если ssh-канал недоступен

Если по какой-то причине ssh-канал на хост закрыт, эквивалентную защиту можно временно обеспечить
host-cron на mva154 (процедура Owner, off-git):
```cron
# каждые 6 часов: удалить build cache старше 24ч (только build cache, не образы/контейнеры)
0 */6 * * *  docker builder prune -f --filter until=24h >> /var/log/orch-build-cache-prune.log 2>&1
```
Это fallback, не основной путь: cron не наблюдаем в `GET /queue` и не имеет config-kill-switch.

## I-4. CI/CD

- `.gitea/workflows/` — **без изменений**. Добавляется юнит-тест `tests/test_build_cache_pruner.py`
  (путь A), исполняется существующим `pytest tests/ -q`; docker/ssh в тестах мокируются (как
  `image_freshness`-тесты не требуют реального docker).
</content>
