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

5.7 KiB
Raw Blame History

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 настроен как:

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.