Files
enduro-trails/docs/work-items/ET-015/01-brd.md
claude-bot c2cf8280ca
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 3s
analyst(ET): auto-commit from analyst run_id=101
2026-06-05 15:11:28 +00:00

106 lines
5.7 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.
# BRD: Healthcheck enduro-trails-app падает: в контейнере нет curl
**Work Item:** ET-015
**Тип:** Bugfix / Infrastructure
**Приоритет:** Низкий (приложение работает) / Важно для мониторинга
**Дата:** 2026-06-05
**Запросил:** Слава
## 1. Контекст
Контейнер `enduro-trails-app-1` (запускается из репозитория `enduro-trails`)
на тестовой среде `mva154` (https://openclaw.mva154.duckdns.org/enduro/)
показывает в Docker статус `unhealthy` уже ~31 час с `FailingStreak=3762`,
при том что само приложение работает:
- `curl снаружи :5556 → HTTP 200` (~7 мс отклик);
- в логах живой трафик `200 OK`;
- `RestartCount=0` (контейнер не перезапускался).
## 2. Корень проблемы
В `docker-compose.yml` healthcheck настроен как:
```yaml
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5556/api/health"]
```
Базовый образ — `python:3.12-slim` (см. `Dockerfile`). В `slim`-варианте
**нет** утилиты `curl`. Каждый цикл healthcheck завершается:
```
exec: "curl": executable file not found in $PATH
exit code = -1
```
Docker трактует это как «проверка провалена» и через `retries=3` помечает
контейнер `unhealthy`. На самом деле приложение здорово.
Дополнительный факт: эндпоинт `/api/health` **существует** в коде
(`src/api/main.py:1224`, отдаёт `{"status": "ok", ...}`), так что
двойной поломки (несуществующий путь) нет — проблема исключительно
в отсутствии `curl`.
## 3. Бизнес-проблема
1. **Ложные алерты в мониторинге.** Любая система оповещений, опирающаяся
на `docker inspect ... .State.Health.Status`, будет постоянно кричать
об инциденте, который не существует.
2. **Эрозия доверия к мониторингу.** Если `unhealthy` всегда ложный, его
игнорируют — и пропустят настоящий инцидент, когда он случится.
3. **Невозможность построения SLO/SLA.** Метрика «доступность контейнера»
деградирована и непригодна для отчётности.
## 4. Цель
Healthcheck контейнера `app` должен **честно** отражать состояние
приложения: `healthy`, когда HTTP-эндпоинт `/api/health` на `:5556`
отвечает `200 OK`; `unhealthy`, когда не отвечает.
## 5. Стейкхолдеры
| Роль | Имя / Группа | Интерес |
|------|--------------|---------|
| Заказчик | Слава | Корректный мониторинг тестовой и будущей prod-среды |
| Исполнитель | claude-bot | Реализация фикса |
| Эксплуатация | mva154 host owner | Минимальный размер образа, никаких лишних пакетов |
## 6. Ограничения и нефункциональные требования
- **Размер образа** не должен заметно расти. Добавление `curl` через
`apt-get install` тянет ~10 МБ зависимостей + слой APT-кэша →
нежелательно. Предпочтительно использовать то, что уже есть в образе
(Python).
- **Время выполнения healthcheck** не должно превышать `timeout: 5s`
(текущее значение в compose). Реальное время отклика `/api/health`
~7 мс, запас огромный.
- **Совместимость** с Docker Engine ≥ 20.10 (на mva154 стоит свежий).
- **Никаких изменений** в логике приложения — эндпоинт `/api/health`
уже существует и его поведение менять не нужно.
## 7. Out of scope
- Доработка содержимого `/api/health` (например, добавление проверки
OSRM, тайлов, диска) — отдельный work item, если понадобится.
- Healthcheck для сервиса `gps-collector` (batch profile) — у него
нет открытого порта и `restart: "no"`, healthcheck неуместен.
- Healthcheck-настройки на стороне Gitea Actions / CI.
## 8. Сценарий «как должно стать»
1. Образ собирается без добавления `curl`.
2. `docker compose up -d app` поднимает контейнер.
3. Через ≤ `interval * retries` (= 30s × 3 = 90s, с учётом
`start_period` если задан) `docker inspect ... .State.Health.Status`
возвращает `healthy`.
4. Если приложение «зависает» (порт не отвечает) — healthcheck
честно фиксирует `unhealthy` за то же окно.
## 9. Связи
- Затрагивает: `Dockerfile`, `docker-compose.yml`.
- Не затрагивает: `src/api/`, `src/web/`, БД, тайлы.
- Соседние ADR: глобальных архитектурных решений не требует —
локальное инженерное решение, оформляется в `06-adr/` work-item.