Docker HEALTHCHECK: как проверить готовность контейнера

Docker HEALTHCHECK: как проверить готовность контейнера
Содержание статьи

HEALTHCHECK запускает внутри контейнера команду, которая проверяет выбранный признак работоспособности. Живой основной процесс ещё не гарантирует, что приложение отвечает на запросы. При этом статус unhealthy сам по себе не является командой перезапуска.

В практическом разборе Mentoring.digital настроим проверку HTTP-маршрута Python-приложения, разберём ожидание готовности в Compose и порядок диагностики неудачной проверки.

Определите, что означает готовность

Начните с конкретного контракта: например, маршрут /healthz возвращает HTTP 200, когда приложение готово принимать запросы. В этой статье порт приложения внутри контейнера равен 8000. Адрес, порт и допустимый статус нужно согласовать со своим сервисом.

Не проверяйте произвольную главную страницу только потому, что она существует. Страница входа может отвечать нормально, пока нужная операция недоступна. С другой стороны, тяжёлая проверка всех внешних систем на каждом запуске probe сама создаёт нагрузку и делает статус зависимым от лишних факторов.

Если проверка должна учитывать базу данных, включите это в реализацию маршрута и ограничьте время обращения. Отдельно решите, нужны ли вам разные признаки: процесс жив, сервис готов принимать трафик, внешняя зависимость доступна. У Docker healthcheck один итоговый статус.

Сделайте проверку с явным кодом выхода

Следующий файл healthcheck.py предназначен для образа, в котором уже есть Python 3. Он не требует установки curl. Успехом считаем только HTTP 200; тайм-аут и ошибки соединения возвращают код 1:

import urllib.request

def check(url="http://127.0.0.1:8000/healthz"):
    try:
        with urllib.request.urlopen(url, timeout=2) as response:
            return 0 if response.status == 200 else 1
    except OSError:
        return 1

if __name__ == "__main__":
    raise SystemExit(check())

Адрес 127.0.0.1 здесь относится к самому контейнеру. Проверяется внутренний порт, а не опубликованный на хосте. Если приложение слушает другой адрес или путь, измените код. Если сервис возвращает 204 как нормальный ответ, нужно изменить и контракт проверки: текущий пример намеренно считает его неуспехом.

Добавьте HEALTHCHECK в Dockerfile

В уже существующий Dockerfile Python-приложения добавьте копирование скрипта и инструкцию проверки. Сборка приложения и его основная команда запуска остаются частью вашего Dockerfile:

COPY healthcheck.py /app/healthcheck.py
HEALTHCHECK --interval=20s --timeout=3s \
  --start-period=20s --retries=3 \
  CMD ["python", "/app/healthcheck.py"]
  • interval задаёт интервал между проверками после завершения предыдущей.
  • timeout ограничивает продолжительность одной проверки. Внутренний сетевой тайм-аут скрипта здесь короче внешнего.
  • retries задаёт число последовательных неудач до unhealthy.
  • start-period даёт время на запуск: неудачи в этот период не увеличивают счётчик, пока не произошла первая успешная проверка. После успеха последующие неудачи уже учитываются.

Это пример параметров, а не универсальные значения для всех сервисов. Сопоставьте их с реальным временем запуска и допустимой задержкой обнаружения проблемы. Не рассчитывайте точный момент смены статуса простым умножением interval на retries: длительность команд и начальный период тоже влияют на последовательность.

Дождитесь готовности зависимости в Compose

Если worker должен обращаться к API сразу после старта, короткой записи depends_on: [api] недостаточно для проверки готовности. В существующем проекте с Dockerfile API в корне и Dockerfile worker в директории ./worker можно использовать такой фрагмент:

services:
  api:
    build: .
    healthcheck:
      test:
        - CMD
        - python
        - /app/healthcheck.py
      interval: 20s
      timeout: 3s
      retries: 3
      start_period: 20s
  worker:
    build: ./worker
    depends_on:
      api:
        condition: service_healthy

Compose дождётся успешной проверки API перед запуском зависимого сервиса. Блок healthcheck может переопределять настройки образа. Сам worker всё равно должен уметь обработать потерю соединения позже: успешный запуск не гарантирует постоянную доступность зависимости.

Не путайте это с политикой restart. Для обычного контейнера она связана с завершением основного процесса. Один лишь неуспешный healthcheck не заставляет Docker Engine перезапустить работающий процесс.

Разберите причину unhealthy

Начните со статуса и журнала проверок. В командах ниже замените api-container именем своего контейнера:

docker ps
docker inspect api-container
docker exec api-container python /app/healthcheck.py

В выводе inspect найдите State.Health: там видны результаты последних запусков и их коды выхода. Наш скрипт не печатает диагностический текст, поэтому поле Output может быть пустым. Последняя команда повторяет probe внутри того же контейнера; сам код выхода смотрите средствами своей оболочки.

  • Код запуска команды сообщает, что python или файл не найдены: проверьте состав образа и абсолютный путь.
  • Маршрут отвечает 404 или 503: проверьте правильность пути и состояние приложения.
  • Запрос на хосте работает, а внутри нет: проверьте внутренний порт и адрес прослушивания.
  • Проверка регулярно превышает тайм-аут: выясните причину задержки, прежде чем просто увеличивать лимит.

Что проверено в этом примере

Скрипт был выполнен локально с учебным HTTP-сервером: при 200 он вернул 0, при 204, 503, задержке ответа и недоступном порте вернул 1. Dockerfile и Compose сверены с официальной документацией. Контейнерный запуск в редакционной среде не выполнялся, поскольку Docker здесь недоступен.

Перед внедрением в свой проект соберите образ, выполните docker compose config, проверьте успешный старт и воспроизведите отказ маршрута на тестовом стенде. Убедитесь, что восстановление отвечает вашей схеме эксплуатации, а не только меняет цвет статуса.

Если нужна помощь с контрактом готовности и порядком запуска сервисов, на разборе инфраструктуры с DevOps-ментором полезно показать Dockerfile, Compose и несколько последовательных записей Health.Log.

Похожие статьи по данной теме