Контейнер со статусом
Секция
Поле
Если
После запуска контейнер проходит через несколько состояний здоровья:
Посмотреть текущий статус и вывод последней проверки:
В
Короткая форма
Доступные значения
Если у зависимости нет
Начиная с Docker Compose 2.20.0 доступен параметр
Флаг
Для сложной логики (проверка нескольких эндпоинтов, валидация ответа, проверка дискового пространства) лучше положить скрипт в образ:
Скрипт должен возвращать 0 при успехе и любой ненулевой код при проблеме. Это даёт полный контроль над диагностикой и позволяет логировать причину сбоя в stdout — вывод попадёт в
Проверка не учитывает время инициализации. Без
Команда проверки отсутствует в образе.
Проверка проходит, но сервис не работает. Например,
Слишком агрессивные тайминги.
Зависимость от
Shell-форма в distroless-образах. Если образ собран без
Если контейнер не переходит в
Сам по себе статус
Для автоматического рестарта при
Ключевой принцип: проверяйте то, что реально важно для потребителя сервиса. Если веб-приложение ходит в базу данных, healthcheck базы должен подтверждать готовность принимать запросы, а не просто наличие процесса.
Up в выводе docker ps означает лишь одно: процесс внутри запущен. Приложение может зависнуть на инициализации, потерять соединение с базой данных или отвечать ошибками на каждый запрос — контейнер при этом остаётся «живым». Healthcheck решает эту проблему: Docker периодически выполняет команду проверки внутри контейнера и по её коду возврата определяет, действительно ли сервис работает.Синтаксис healthcheck в Compose-файле
Секция
healthcheck объявляется внутри определения сервиса. Минимальный рабочий пример:
YAML:
services:
web:
image: nginx:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Поле
test задаёт команду проверки. Два формата записи:- Exec-форма (массив):
["CMD", "curl", "-f", "http://localhost"]— команда выполняется напрямую без оболочки.
- Shell-форма:
["CMD-SHELL", "curl -f http://localhost || exit 1"]— команда передаётся в/bin/sh -c. Удобна, когда нужны пайпы, перенаправления или логические операторы.
Если
test установлен в ["NONE"], healthcheck отключается — это полезно, когда базовый образ содержит проверку, которая не подходит для вашего сценария.Параметры таймингов и их влияние на поведение
| Параметр | Значение по умолчанию | Что контролирует |
|---|---|---|
interval | 30s | Пауза между последовательными проверками |
timeout | 30s | Максимальное время ожидания ответа от команды проверки |
retries | 3 | Сколько подряд неудачных проверок нужно для перехода в статус unhealthy |
start_period | 0s | Окно после старта контейнера, в течение которого неудачные проверки не засчитываются |
start_interval | 5s | Интервал проверок внутри start_period (доступен в новых версиях Compose) |
start_period критичен для сервисов с долгой инициализацией — например, PostgreSQL, который восстанавливает данные из WAL, или Java-приложения с тяжёлым спринг-контекстом. Без него контейнер может получить статус unhealthy ещё до того, как приложение успело подняться.start_interval позволяет опрашивать сервис чаще в начальной фазе, не увеличивая нагрузку в штатном режиме. Например, start_interval: 5s при interval: 30s даёт быстрый детект готовности сразу после старта. Параметр поддерживается в актуальных версиях Compose; в более ранних он игнорируется.Статусы контейнера и их смысл
После запуска контейнер проходит через несколько состояний здоровья:
starting— контейнер запущен, ноstart_periodещё не истёк. Неудачные проверки не влияют на статус.
healthy— последняя проверка (или серия проверок) завершилась с кодом 0.
unhealthy— количество подряд неудачных проверок достиглоretries.
none— healthcheck не определён или отключён черезNONE.
Посмотреть текущий статус и вывод последней проверки:
Bash:
docker inspect --format='{{.State.Health.Status}}' <container>
docker inspect --format='{{json .State.Health.Log}}' <container> | jq .
В
Health.Log хранится массив последних проверок с таймстампом, кодом возврата и выводом stdout/stderr — это первое место, куда стоит смотреть при диагностике.Интеграция с depends_on: запуск по готовности, а не по старту
Короткая форма
depends_on гарантирует только порядок создания контейнеров. Compose запустит зависимый сервис сразу после старта зависимости, не дожидаясь её готовности. Длинная форма с condition: service_healthy меняет поведение: зависимый сервис не стартует, пока зависимость не перейдёт в healthy.
YAML:
services:
db:
image: postgres:18
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
POSTGRES_DB: appdb
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
web:
build: .
depends_on:
db:
condition: service_healthy
Доступные значения
condition:service_started— эквивалент короткой формы, ждёт только запуска процесса.
service_healthy— ждёт перехода зависимости в статусhealthy. Требует, чтобы у зависимости был определёнhealthcheck.
service_completed_successfully— ждёт успешного завершения контейнера (код 0). Подходит для init-джобов и миграций.
Если у зависимости нет
healthcheck, а указан condition: service_healthy, Compose выдаст ошибку конфигурации.Начиная с Docker Compose 2.20.0 доступен параметр
required: false внутри depends_on. При таком значении Compose не блокирует запуск зависимого сервиса, если зависимость не стала здоровой, а лишь выдаёт предупреждение. Это полезно для опциональных сервисов, без которых приложение может работать в деградированном режиме.Практические примеры проверок для популярных сервисов
PostgreSQL
YAML:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
pg_isready проверяет, принимает ли сервер соединения, не требуя аутентификации. Двойной $$ экранирует переменную от подстановки на уровне Compose — значение подставится из переменных окружения контейнера.Redis
YAML:
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
redis-cli ping возвращает PONG с кодом 0, если сервер отвечает. Если настроен пароль, добавьте -a <password> или используйте переменную окружения.Nginx / HTTP-сервисы
YAML:
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost/health || exit 1"]
interval: 15s
timeout: 5s
retries: 3
Флаг
-f заставляет curl вернуть ненулевой код при HTTP-статусах 400+. Если в образе нет curl, подойдёт wget -q --spider http://localhost/health.Проверка через скрипт внутри образа
Для сложной логики (проверка нескольких эндпоинтов, валидация ответа, проверка дискового пространства) лучше положить скрипт в образ:
YAML:
healthcheck:
test: ["CMD", "/app/healthcheck.sh"]
interval: 30s
timeout: 10s
retries: 3
Скрипт должен возвращать 0 при успехе и любой ненулевой код при проблеме. Это даёт полный контроль над диагностикой и позволяет логировать причину сбоя в stdout — вывод попадёт в
Health.Log.Типичные ошибки и как их избежать
Проверка не учитывает время инициализации. Без
start_period тяжёлый сервис получает unhealthy до завершения запуска, и зависимые контейнеры не стартуют. Решение: оцените реальное время старта и задайте start_period с запасом.Команда проверки отсутствует в образе.
curl есть не во всех образах — в alpine-вариантах его часто нет. Проверьте состав образа или используйте wget, который обычно присутствует в Alpine.Проверка проходит, но сервис не работает. Например,
curl получает 200 от nginx, но backend-приложение за прокси уже упало. Healthcheck должен проверять реальный путь запроса, а не только наличие процесса.Слишком агрессивные тайминги.
interval: 1s с timeout: 1s создаёт нагрузку на контейнер и может давать ложные срабатывания при кратковременных задержках. Для большинства сервисов interval: 10–30s достаточен.Зависимость от
depends_on без healthcheck. Если сервис-зависимость не имеет healthcheck, условие service_healthy невозможно. Compose не будет ждать готовности — только факта запуска.Shell-форма в distroless-образах. Если образ собран без
/bin/sh (например, distroless), CMD-SHELL не сработает. Используйте exec-форму CMD с прямым указанием бинарника.Диагностика проблем с healthcheck
Если контейнер не переходит в
healthy:- Проверьте статус и лог проверок:
Bash:
docker inspect --format='{{json .State.Health}}' <container> | jq .
- Выполните команду проверки вручную внутри контейнера:
Bash:
docker exec <container> curl -sf http://localhost/health
- Убедитесь, что необходимые утилиты присутствуют в образе:
Bash:
docker exec <container> which curl
- Проверьте, не блокирует ли
start_periodпереход: если контейнер в статусеstarting, проверки ещё не засчитываются.
- Если используется
CMD-SHELL, убедитесь, что/bin/shсуществует в образе. В distroless-образах его нет — используйте exec-формуCMD.
- Проверьте права пользователя: если основной процесс запущен от непривилегированного пользователя, команда проверки выполняется с теми же правами и может не иметь доступа к нужным ресурсам.
Healthcheck и автоматический рестарт
Сам по себе статус
unhealthy не перезапускает контейнер. В standalone Docker и Docker Compose смена статуса здоровья — это сигнал, а не триггер для действия. Директива restart: unless-stopped или restart: always перезапускает контейнер только при его остановке, а не при переходе в unhealthy.Для автоматического рестарта при
unhealthy в Compose-среде обычно используют внешний watchdog-скрипт, который опрашивает статус контейнеров и выполняет docker compose restart при необходимости. В оркестраторах уровня Kubernetes liveness-пробы управляют жизненным циклом подов напрямую, и аналогичная логика встроена в платформу.Ограничения и нюансы спецификации
- Healthcheck выполняется внутри контейнера. Он не может проверить сетевую доступность сервиса снаружи или корректность маппинга портов.
- Команда проверки работает с тем же пользователем, что и основной процесс (если не переопределено через
USERв Dockerfile). Если процесс запущен от непривилегированного пользователя, проверка может не иметь доступа к нужным ресурсам.
start_intervalподдерживается в актуальных версиях Compose. В более ранних версиях параметр игнорируется без ошибки.
- При использовании
depends_onсcondition: service_healthyиrequired: false(Compose 2.20.0+) Compose не блокирует запуск зависимого сервиса, если зависимость не стала здоровой, а лишь выдаёт предупреждение.
- Healthcheck не заменяет внешний мониторинг. Он фиксирует состояние сервиса в момент проверки, но не отслеживает деградацию между проверками. Для продакшена комбинируйте его с метриками и алертами.
Выбор стратегии проверки под задачу
| Задача | Что проверять | Формат |
|---|---|---|
| Сервер принимает соединения | pg_isready, redis-cli ping | Exec-форма |
| HTTP-эндпоинт отвечает корректно | curl -sf на health-эндпоинт | Shell-форма |
| Приложение обрабатывает запросы | Скрипт с реальным запросом и валидацией ответа | Скрипт в образе |
| Зависимость готова к работе | depends_on + condition: service_healthy | Compose-конфигурация |
| Init-джоб завершился | condition: service_completed_successfully | Compose-конфигурация |
Ключевой принцип: проверяйте то, что реально важно для потребителя сервиса. Если веб-приложение ходит в базу данных, healthcheck базы должен подтверждать готовность принимать запросы, а не просто наличие процесса.
