Healthcheck в Docker Compose
Практическая настройка healthcheck в Docker Compose: проверка состояния контейнера, интервалы, таймауты, retries и диагностика unhealthy.
Запущенный контейнер не всегда означает, что приложение внутри него действительно работает. Процесс может оставаться активным, но сервис уже не отвечает на запросы или не может подключиться к зависимостям.
Механизм healthcheck позволяет Docker регулярно выполнять проверочную команду и присваивать контейнеру состояние healthy или unhealthy.
В этой инструкции рассматривается только настройка и диагностика healthcheck в Docker Compose.
Проверено на: Ubuntu Server 24.04 LTS и Docker Compose Plugin
Уровень сложности: начальный
Время выполнения: около 15 минут
Требуемый доступ: пользователь с доступом к Docker
Что будет рассмотрено
После выполнения инструкции можно будет:
- добавить healthcheck в
compose.yaml; - проверять HTTP-сервис;
- настроить интервалы и таймауты;
- просматривать статус контейнера;
- изучать историю проверок;
- диагностировать состояние
unhealthy; - отключать встроенный healthcheck образа.
Создание тестового проекта
Создайте каталог:
mkdir -p ~/docker-healthcheck-example
cd ~/docker-healthcheck-example
Базовый пример с Nginx
Создайте файл compose.yaml:
cat >compose.yaml <<'EOF'
services:
web:
image: nginx:alpine
container_name: healthcheck-web
ports:
- "8080:80"
healthcheck:
test:
- CMD
- wget
- --spider
- -q
- http://127.0.0.1/
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
EOF
Проверьте конфигурацию:
docker compose config
Запустите контейнер:
docker compose up -d
Проверка статуса
docker compose ps
Сразу после запуска состояние может быть:
health: starting
После успешной проверки:
healthy
Проверьте через Docker:
docker ps --format 'table {{.Names}} {{.Status}}'
Параметры healthcheck
test
Команда проверки:
test:
- CMD
- wget
- --spider
- -q
- http://127.0.0.1/
Она запускается внутри контейнера.
В образе должна присутствовать используемая команда. В данном примере это wget.
interval
Интервал между проверками:
interval: 30s
Docker будет запускать проверку каждые 30 секунд.
timeout
Максимальное время выполнения одной проверки:
timeout: 5s
Если команда не завершилась за 5 секунд, проверка считается неуспешной.
retries
Количество последовательных ошибок:
retries: 3
После трёх неуспешных проверок контейнер получит статус:
unhealthy
start_period
Льготный период после запуска:
start_period: 10s
Ошибки в течение этого периода не учитываются как окончательный отказ.
Параметр полезен для приложений, которым требуется время на инициализацию.
Проверка HTTP через CMD-SHELL
Тот же healthcheck можно записать в строковой форме:
healthcheck:
test:
- CMD-SHELL
- wget --spider -q http://127.0.0.1/ || exit 1
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
CMD-SHELL запускает команду через shell и позволяет использовать:
||;&&;- перенаправления;
- переменные;
- несколько команд.
Для простой команды безопаснее использовать CMD.
Проверка с curl
Если в образе установлен curl:
healthcheck:
test:
- CMD
- curl
- --fail
- --silent
- http://127.0.0.1/health
Параметр --fail заставляет curl возвращать ошибку при HTTP-кодах 400 и 500.
Проверьте наличие команды внутри контейнера:
docker compose exec web which curl
Если команда отсутствует, такой healthcheck работать не будет.
Проверка TCP-порта
Если приложение не имеет HTTP endpoint, можно проверить открытый порт.
Пример с nc:
healthcheck:
test:
- CMD-SHELL
- nc -z 127.0.0.1 5432
interval: 30s
timeout: 5s
retries: 3
Перед использованием убедитесь, что nc установлен в образе.
Проверка процесса
Пример:
healthcheck:
test:
- CMD-SHELL
- pgrep nginx >/dev/null || exit 1
Такой вариант проверяет наличие процесса, но не подтверждает работоспособность сервиса.
Для веб-приложений лучше проверять реальный HTTP endpoint.
Просмотр результата healthcheck
Проверьте текущее состояние:
docker inspect --format '{{.State.Health.Status}}' healthcheck-web
Ожидаемый результат:
healthy
История проверок
Подробный вывод:
docker inspect healthcheck-web |
jq '.[0].State.Health'
Краткая история:
docker inspect --format '{{json .State.Health.Log}}' healthcheck-web |
jq
В журнале отображаются:
- время начала;
- время завершения;
- код возврата;
- вывод команды.
Код возврата
Для healthcheck важен код завершения команды:
0 — проверка успешна
1 — проверка неуспешна
Команду можно проверить вручную:
docker compose exec web wget --spider -q http://127.0.0.1/
Проверьте код:
echo $?
Успешный результат:
0
Создание состояния unhealthy
Остановите Nginx внутри контейнера:
docker compose exec web nginx -s stop
Подождите несколько интервалов и проверьте:
docker compose ps
Статус должен измениться на:
unhealthy
Посмотрите историю:
docker inspect healthcheck-web |
jq '.[0].State.Health.Log'
Важная особенность
Статус unhealthy сам по себе не перезапускает контейнер.
Docker продолжит считать контейнер запущенным, пока основной процесс не завершился.
Healthcheck нужен для:
- диагностики;
- оркестрации;
- зависимостей;
- внешнего мониторинга;
- автоматизации через дополнительные инструменты.
Перезапуск тестового контейнера
docker compose restart web
Проверьте:
docker compose ps
Сначала появится:
health: starting
затем:
healthy
Зависимость от healthy-сервиса
Пример приложения, которое должно запускаться после готовности базы данных:
services:
db:
image: postgres:alpine
environment:
POSTGRES_PASSWORD: CHANGE_ME
healthcheck:
test:
- CMD-SHELL
- pg_isready -U postgres
interval: 10s
timeout: 5s
retries: 5
start_period: 20s
app:
image: alpine
command:
- sh
- -c
- while true; do sleep 3600; done
depends_on:
db:
condition: service_healthy
Сервис app будет ожидать успешного healthcheck базы данных.
Это не заменяет повторные подключения внутри самого приложения.
Healthcheck для PostgreSQL
Пример:
healthcheck:
test:
- CMD-SHELL
- pg_isready -U "$${POSTGRES_USER}" -d "$${POSTGRES_DB}"
interval: 10s
timeout: 5s
retries: 5
start_period: 20s
Двойной знак доллара:
$$
передаёт переменную внутрь контейнера, не позволяя Compose подставить её заранее.
Healthcheck для MySQL
Пример:
healthcheck:
test:
- CMD-SHELL
- mysqladmin ping -h 127.0.0.1 -u root -p"$${MYSQL_ROOT_PASSWORD}" --silent
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
Не выводите пароль в журналы и не используйте чувствительные значения непосредственно в публичном Compose-файле.
Переопределение встроенного healthcheck
Некоторые образы уже содержат HEALTHCHECK.
Посмотрите конфигурацию образа:
docker image inspect nginx:alpine |
jq '.[0].Config.Healthcheck'
Собственный healthcheck в compose.yaml переопределит настройки образа.
Отключение healthcheck
Чтобы отключить встроенную проверку образа:
services:
app:
image: IMAGE_NAME
healthcheck:
disable: true
Проверьте:
docker compose config
Настройка частоты проверок
Слишком частые проверки:
- создают лишнюю нагрузку;
- увеличивают объём логов;
- могут ошибочно определять кратковременные задержки как отказ.
Для обычного веб-сервиса начальные параметры могут быть такими:
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
Для тяжёлого приложения период запуска следует увеличить.
Что должен проверять endpoint
Хороший endpoint /health должен быстро отвечать и отражать состояние сервиса.
Минимальная проверка:
- приложение принимает запросы;
- основной процесс не завис;
- критические внутренние компоненты доступны.
Не следует включать в каждую проверку тяжёлые операции или обращения ко всем внешним сервисам.
Типичные проблемы
Контейнер постоянно unhealthy
Проверьте историю:
docker inspect CONTAINER_NAME |
jq '.[0].State.Health'
Выполните тест вручную:
docker compose exec SERVICE_NAME HEALTHCHECK_COMMAND
Команда не найдена
Проверьте:
docker compose exec SERVICE_NAME which COMMAND_NAME
Используйте инструмент, который уже есть в образе, либо добавьте его при сборке собственного образа.
Healthcheck работает с хоста, но не в контейнере
Проверочная команда выполняется внутри контейнера.
Адрес:
127.0.0.1
указывает на сам контейнер, а не на хост.
Сервис запускается долго
Увеличьте:
start_period: 60s
При необходимости также увеличьте retries.
После изменения healthcheck остались старые настройки
Пересоздайте контейнер:
docker compose up -d --force-recreate
Обычный restart не изменяет конфигурацию контейнера.
Быстрый набор команд
Проверить статус:
docker compose ps
Получить состояние:
docker inspect --format '{{.State.Health.Status}}' CONTAINER_NAME
Посмотреть историю:
docker inspect CONTAINER_NAME |
jq '.[0].State.Health.Log'
Пересоздать контейнер:
docker compose up -d --force-recreate
Удаление тестового проекта
cd ~/docker-healthcheck-example
docker compose down
cd ~
rm -rf ~/docker-healthcheck-example
Итог
После выполнения инструкции:
- добавлен healthcheck в Docker Compose;
- настроены интервалы, таймауты и количество попыток;
- проверены состояния
starting,healthyиunhealthy; - изучена история проверок;
- рассмотрены HTTP-, TCP- и процессные проверки;
- показана зависимость
service_healthy; - разобраны типичные ошибки.
Healthcheck должен проверять реальную готовность сервиса, а не только наличие запущенного процесса.