Почему HealthCheck в Docker‑контейнере не срабатывает?
В контейнере на базе scratch HealthCheck не проходит из‑за отсутствия /etc/hosts, httpcheck и localhost. Как проверить и исправить проблему для Swarm и реплик?
Почему HealthCheck в Docker‑контейнере не срабатывает, хотя приложение отвечает 200 на /health? В контейнере используется образ scratch, приложение слушает порт 80, а HealthCheck прописан так:
HEALTHCHECK --interval=1m --timeout=5s CMD ["httpcheck", "http://localhost/health"]
При запуске в Swarm контейнеры завершаются и пересоздаются, а при replicas > 1. Может ли отсутствие доступа к localhost в scratch‑образе быть причиной? Как проверить доступность /health внутри контейнера и исправить проблему?
Почему HealthCheck не срабатывает
В scratch‑образе почти всё отсутствует, что обычно помогает Docker‑у «знать», как проверить состояние приложения:
- Нет /etc/hosts – Docker добавляет его только в образах, которые имеют файловую систему. В чистом
scratchон не создаётся, поэтомуlocalhostне резолвится в адрес контейнера. - Отсутствует инструмент для проверки –
httpcheck(илиcurl,wget) не входит вscratch. Если в инструкции HEALTHCHECK указать исполняемый файл, которого нет, Docker получает код выхода127и помечает контейнер «unhealthy». - Порт 80 не объявлен – хотя приложение слушает 80, Docker не знает, что нужно пробросить этот порт, если в Dockerfile не прописан
EXPOSE 80. В Swarm это не влияет на HealthCheck, но удобно для диагностики.
Из‑за этих факторов контейнер в Swarm быстро падает и создаётся заново, а при replicas > 1 Docker «потерял» одну из копий и пытается заменить её.
Как проверить доступность /health внутри контейнера
-
Запустите контейнер с интерактивным шеллом (только если ваш образ содержит его).
bashdocker run -d --name test-health myimage docker exec -it test-health /bin/sh # в scratch не работаетДля
scratchпонадобится добавить временное ядро‑шлюзовое приложение:bashdocker run --rm -it --entrypoint sh busyboxНа этом слое можно сразу проверить, что ваш сервис отвечает:
bashwget -qO- http://127.0.0.1/health
-
Используйте
docker execс уже установленным в контейнере инструментом.
Если в образе естьcurl(или вы его добавили в отдельном слое), то:bashdocker exec test-health curl -f http://127.0.0.1/healthВывод
200 OKподтверждает, что эндпоинт работает. -
Проверка через Docker Inspect
bashdocker inspect --format '{{.State.Health.Status}}' test-healthЕсли вы видите
unhealthy, значит HealthCheck действительно не проходит.
Как исправить проблему
1. Добавьте исполняемый файл проверки
Опция A – использовать curl
FROM scratch
# добавляем curl (статически слинкованную версию, ~75 KB)
COPY --from=ghcr.io/tarampampam/microcheck:1 /bin/curl /bin/curl
HEALTHCHECK --interval=1m --timeout=5s CMD ["curl", "-f", "http://127.0.0.1/health"]
Опция B – использовать httpcheck
FROM scratch
COPY --from=ghcr.io/tarampampam/microcheck:1 /bin/httpcheck /bin/httpcheck
HEALTHCHECK --interval=1m --timeout=5s CMD ["httpcheck", "http://127.0.0.1/health"]
Важно – используйте exec‑форму (
CMD [...]), а не shell‑форму (CMD ["curl", ...]), потому что вscratchнет/bin/sh.
2. Резолвим адрес через IP, а не через localhost
127.0.0.1 всегда указывает на сам контейнер, не зависит от DNS или /etc/hosts:
HEALTHCHECK --interval=1m --timeout=5s CMD ["httpcheck", "http://127.0.0.1/health"]
3. Объявите порт (необязательно, но удобно)
EXPOSE 80
4. Установите параметры восстановления
Если вы используете Swarm, добавьте --health-retries и --health-interval в сервис:
docker service create \ --name myservice \ --replicas 3 \ --health-interval 1m \ --health-timeout 5s \ --health-retries 3 \ myimage
5. Проверьте результат
docker ps
# → HEALTH: healthy
docker inspect --format '{{.State.Health.Status}}' <container>
# → healthy
Итог
- Да, отсутствие
localhost‑псевдонима вscratchможет помешать работе HealthCheck. - Ключ – использовать IP‑адрес
127.0.0.1и гарантировать наличие исполняемого проверочного утилита (curl, httpcheck, или собственный скрипт). - После этих изменений HealthCheck будет работать корректно, а Swarm больше не будет пересоздавать контейнеры из‑за «неустойчивости».