106 lines
5.7 KiB
Markdown
106 lines
5.7 KiB
Markdown
# 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.
|