Проверка работоспособности Docker
Вы когда-нибудь запускали контейнер, который работает, но на самом деле не работает? Такое случается. Именно здесь важную роль играют проверки работоспособности Docker Compose. Они не просто подтверждают, что контейнер запущен, — они гарантируют, что он действительно готов обрабатывать запросы.
Работающий контейнер не всегда является работоспособным, и это различие может означать разницу между успешным развертыванием и долгой ночью, полной поиска и устранения неполадок. Проверка работоспособности Docker Compose помогает запускать автоматизированные тесты, которые проверяют, функционируют ли ваши сервисы должным образом, чтобы вы могли выявлять проблемы до того, как они станут серьезными.
Зачем использовать проверки работоспособности Docker?
- Доступность сервиса: проверка работоспособности Docker помогает убедиться, что ваши контейнерные сервисы доступны и работают. В случае сбоя проверки работоспособности Docker может предпринять такие действия, как перезапуск контейнера или оповещение системного администратора.
- Автоматическое восстановление: если проверка работоспособности контейнера не проходит, Docker может автоматически перезапустить контейнер, обеспечивая минимальное время простоя и повышая надежность вашего приложения.
- Мониторинг и оповещения: проверки работоспособности могут быть интегрированы с системами мониторинга для создания оповещений в случае сбоя в работе сервиса. Это упрощает поддержку крупномасштабных приложений и позволяет быстро реагировать на проблемы.
- Улучшенное развертывание: с помощью проверок работоспособности вы можете убедиться, что сервисы работают корректно, прежде чем предоставлять их пользователям, что позволяет избежать таких проблем, как перенаправление трафика на неработающий сервис.
Базовый синтаксис для проверки работоспособности Docker
Проверка работоспособности выполняется в Dockerfile
с помощью инструкции HEALTHCHECK
. Базовый синтаксис:
HEALTHCHECK [OPTIONS] CMD <command>
CMD
: Команда для определения работоспособности контейнера. Если команда завершается с кодом состояния 0, контейнер считается работоспособным. В противном случае он считается неработоспособным.OPTIONS
Вы можете указать параметры для управления работой проверки работоспособности. К ним относятся:--interval
: Как часто выполнять проверку работоспособности (по умолчанию — каждые 30 секунд).--timeout
: Сколько времени нужно ждать завершения проверки работоспособности (по умолчанию — 30 секунд).--start-period
: Сколько времени должно пройти после запуска контейнера до первой проверки работоспособности (по умолчанию — 0).--retries
: Количество последовательных сбоев, при которых контейнер считается неработоспособным (по умолчанию — 3).
Пример проверки работоспособности Docker
Вот пример того, как можно определить проверку работоспособности в Dockerfile
веб-приложении:
FROM nginx:latest
# Copy the web app content into the container
COPY ./index.html /usr/share/nginx/html/index.html
# Define the health check
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD curl --fail http://localhost || exit 1
В этом примере:
- Проверка работоспособности пытается
curl
запустить HTTP-сервис контейнера (http://localhost
). - Если команда
curl
не сработает или будет выполнена с задержкой, контейнер будет помечен как нерабочий. - Флаг
--interval=30s
указывает Docker на необходимость выполнять проверку работоспособности каждые 30 секунд. - Флаг
--timeout=5s
означает, что проверка работоспособности завершится ошибкой, если выполнение команды займёт более 5 секунд. - Флаг
--retries=3
указывает на то, что контейнер будет считаться неработоспособным только после 3 последовательных неудачных проверок.
Варианты проверки работоспособности
--interval
: Как часто выполняется проверка работоспособности. Значение по умолчанию — 30 секунд.
HEALTHCHECK --interval=10s CMD curl --fail http://localhost
--timeout
: Сколько времени нужно ждать завершения проверки работоспособности, прежде чем она будет считаться неудачной. По умолчанию — 30 секунд.
HEALTHCHECK --timeout=5s CMD curl --fail http://localhost
--start-period
: Время ожидания после запуска контейнера до выполнения первой проверки работоспособности. Это полезно, если инициализация вашего приложения занимает некоторое время.
HEALTHCHECK --start-period=5s CMD curl --fail http://localhost
--retries
: Количество последовательных сбоев, которые должны произойти, прежде чем контейнер будет признан неработоспособным. Значение по умолчанию — 3.
HEALTHCHECK --retries=5 CMD curl --fail http://localhost
Запрос состояния контейнера
После настройки проверок работоспособности вы можете запросить информацию о состоянии вашего контейнера с помощью команды docker ps
docker ps
В столбце STATUS
отобразится состояние контейнера. Возможные состояния:
healthy
: Контейнер работает должным образом.unhealthy
: Контейнер не прошел проверку работоспособности.starting
: Контейнер запущен, но проверка работоспособности еще не выполнена.
Например:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d9b100f2f636 nginx:latest "/docker-entrypoint.…" 2 minutes ago Up 2 minutes (healthy) 80/tcp my-web-container
Использование проверки работоспособности Docker с помощью Docker Compose
Вы также можете настроить проверку работоспособности в файле docker-compose.yml
для сервисов, работающих как часть многоконтейнерного приложения.
Вот пример docker-compose.yml
с проверкой работоспособности:
version: '3'
services:
web:
image: nginx
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost"]
interval: 30s
retries: 3
start_period: 5s
timeout: 10s
В этом примере:
- Поле
test
определяет команду проверки работоспособности. - Опции
interval
,retries
,start_period
иtimeout
работают так же, как и вDockerfile
.
За кулисами Docker выполняет эту команду внутри вашего контейнера через определённые промежутки времени. Состояние контейнера может быть одним из трёх:
- starting: во время начальной проверки работоспособности
start_period
сбои не учитываются - healthy: команда проверки работоспособности вернула успешный код завершения (0)
- unhealthy: проверка состояния здоровья не пройдена
retries
раз подряд
Давайте разберёмся, что означает каждый из этих вариантов:
Вариант | Цель | Примерное значение |
---|---|---|
test | Команда для запуска проверки работоспособности | ["CMD", "curl", "-f", "http://localhost"] |
interval | Как часто нужно проводить проверку | 30 сек |
timeout | Сколько времени нужно ждать ответа | 10с |
retries | Количество последовательных сбоев, необходимых для определения неисправности | 3 |
start_period | Льготный период для запуска | 40 сек |
Проверка работоспособности запустит указанную команду внутри вашего контейнера. Если команда выполнена успешно (завершена с кодом 0), ваш контейнер работает нормально. Если нет, то контейнер неисправен.💡Устранение неполадок в работе контейнера? Фильтрация журналов может сэкономить время.
Команды проверки работоспособности для стандартных служб
Для разных сервисов нужны разные команды проверки работоспособности. Вот несколько готовых примеров с пояснениями, почему они работают хорошо:
Для веб-сервера (Nginx/Apache):
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
Это проверяет, отвечает ли веб-сервер на HTTP-запросы. Флаг -f
заставляет curl возвращать ненулевой код завершения, если сервер возвращает статус ошибки (например, 404 или 500).
Для MySQL:
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "${MYSQL_USER}", "-p${MYSQL_PASSWORD}"]
Команда mysqladmin ping
проверяет, работает ли сервер MySQL и отвечает ли он на подключения. Она проста в использовании и идеально подходит для проверки работоспособности.
Для PostgreSQL:
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
pg_isready
Это утилита PostgreSQL, специально разработанная для проверки того, принимает ли сервер подключения. Она не выполняет никаких реальных запросов, что делает ее очень эффективной.
Для Redis:
healthcheck:
test: ["CMD", "redis-cli", "ping"]
Команда Redis PING
— это самый простой способ проверить, отвечает ли сервер. Если всё работает правильно, Redis ответит «PONG».
Для MongoDB:
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
Это позволяет выполнить простую команду ping для базы данных администратора MongoDB, чтобы проверить, работает ли сервер.
Для RabbitMQ:
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"]
Инструмент диагностики RabbitMQ предоставляет специальные команды для проверки работоспособности брокера сообщений.
Заставляем сервисы ждать, пока не появятся работающие зависимости
Одним из самых больших преимуществ проверок работоспособности является контроль порядка запуска. Вы можете заставить один сервис ждать, пока другой не заработает:
version: '3.8'
services:
db:
image: postgres
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
api:
image: myapi
depends_on:
db:
condition: service_healthy
В этом примере служба API не запустится, пока база данных не будет исправна. Это намного надёжнее, чем базовый depends_on
вариант, который ожидает только запуска контейнеров, а не готовности сервисов внутри них.💡Если вам нужна более подробная информация о ваших контейнерах, ознакомьтесь с этим
руководством по журналам Docker Compose, чтобы эффективно отслеживать и устранять неполадки.
Система условных зависимостей
Docker Compose поддерживает несколько условий для зависимостей:
Состояние | Описание |
---|---|
service_started | Подождите, пока контейнер не запустится (поведение по умолчанию) |
service_healthy | Подождите, пока контейнер пройдёт проверку работоспособности |
service_completed_successfully | Дождитесь завершения работы контейнера с кодом выхода 0 |
Вы можете комбинировать эти условия для создания сложных последовательностей запуска. Например, у вас могут быть контейнеры инициализации, которые должны успешно завершиться до запуска основных сервисов:
services:
db-init:
image: flyway
command: migrate
depends_on:
db:
condition: service_healthy
api:
depends_on:
db:
condition: service_healthy
db-init:
condition: service_completed_successfully
Обработка циклических Зависимостей
Иногда сервисы могут зависеть друг от друга. Например, API может нуждаться в базе данных, а база данных может нуждаться в регистрации в API. В таких случаях можно использовать более сложный подход:
- Начните с минимальных проверок работоспособности, которые не проверяют зависимые службы
- После запуска основных служб обновите проверку работоспособности, включив в неё более тщательные тесты
- Используйте переменные среды, чтобы управлять этим поведением:
services:
api:
environment:
- STARTUP_MODE=standalone
healthcheck:
test: ["CMD", "sh", "-c", "if [ \"$STARTUP_MODE\" = \"standalone\" ]; then curl -f http://localhost/basic-health; else curl -f http://localhost/full-health; fi"]
Такой подход позволяет API запускаться в минимальном режиме, а затем переключаться на полную проверку работоспособности, как только будут доступны все зависимости.
Устранение неполадок При проверке работоспособности
Если ваши проверки работоспособности не работают должным образом, вот несколько распространенных проблем и способов их устранения:
Контейнер продолжает перезапускаться
Если ваш контейнер постоянно перезапускается, вероятно, проверка работоспособности не выполняется. Проверьте следующее:
- Команда, которую вы используете, доступна в контейнере (например, если вы используете
curl
, убедитесь, что она установлена) - Сервис внутри контейнера действительно работает
- Порты, которые вы проверяете, указаны верно
Проверка здоровья пройдена, но услуга ещё не готова
Это происходит, когда проверка работоспособности слишком проста. Например, база данных может отвечать на запрос, но не быть готовой к подключениям. Сделайте проверку работоспособности более надежной:
healthcheck:
test: ["CMD", "sh", "-c", "pg_isready -U postgres && psql -U postgres -c 'SELECT 1'"]
Это гарантирует, что база данных не просто работает, но и может выполнять запросы.
Запуск сервиса занимает слишком много времени
Если вашему сервису требуется больше времени для инициализации, измените параметр start_period
:
healthcheck:
start_period: 120s
Это дает вашему контейнеру 2-минутный льготный период до того, как проверка работоспособности приведет к «неработоспособному» статусу.💡Если вам нужно отслеживать журналы контейнеров в режиме реального времени, ознакомьтесь с этим
руководством по использованию функции tail в журналах Docker для получения быстрой информации.
Передовые Методы проверки работоспособности
Вот несколько профессиональных приёмов, которые превратят ваши проверки работоспособности Docker Compose из базовых в надёжные:
Пользовательские Конечные точки проверки работоспособности
Для веб-сервисов создайте специальную конечную точку /health
, которая проверяет критически важные зависимости:
// Node.js example
app.get('/health', async (req, res) => {
try {
// Check database connection
await db.query('SELECT 1');
// Check Redis connection
await redis.ping();
// Check external API connectivity
const apiResponse = await fetch('https://api.example.com/status');
if (!apiResponse.ok) throw new Error('External API unhealthy');
// Check disk space
const diskSpace = await checkDiskSpace();
if (diskSpace.free < 100 * 1024 * 1024) throw new Error('Low disk space');
// All checks passed
res.status(200).json({
status: 'healthy',
checks: {
database: 'connected',
redis: 'connected',
externalApi: 'available',
diskSpace: 'sufficient'
}
});
} catch (error) {
res.status(500).json({
status: 'unhealthy',
error: error.message
});
}
});
Затем обновите данные о состоянии вашего здоровья:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
Такой подход позволяет получить подробную информацию о состоянии системы и может быть расширен для проверки любых внутренних или внешних зависимостей, на которые опирается ваш сервис.
Многоступенчатые проверки работоспособности
Некоторые приложения имеют разные состояния работоспособности. Вы можете реализовать это с помощью сценариев командной оболочки:
healthcheck:
test: ["CMD", "sh", "-c", "./health-check.sh"]
Внутри health-check.sh
:
#!/bin/bash
# Check if service is running at all
pgrep -f myservice || exit 1
# Check if it's accepting connections
curl -s http://localhost:8080/ping > /dev/null || exit 1
# Check if it can connect to its database
./check-db-connection.sh || exit 1
# Check message queue connectivity
./check-rabbit-connection.sh || exit 1
# Check cache availability
redis-cli ping > /dev/null || exit 1
# Check for critical errors in logs (optional)
grep -q "FATAL ERROR" /var/log/myservice/error.log && exit 1
# All checks passed
exit 0
Проверки функционального состояния
Помимо простой проверки подключения, вы можете убедиться, что ваш сервис действительно работает правильно:
#!/bin/bash
# Create a test user
curl -s -X POST -d '{"username":"healthcheck","password":"test123"}' \
-H "Content-Type: application/json" \
http://localhost:8080/api/users > /dev/null || exit 1
# Try to authenticate with the test user
TOKEN=$(curl -s -X POST -d '{"username":"healthcheck","password":"test123"}' \
-H "Content-Type: application/json" \
http://localhost:8080/api/auth | jq -r .token)
# Check if we got a valid token
if [ -z "$TOKEN" ] || [ "$TOKEN" == "null" ]; then
exit 1
fi
# Clean up the test user
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" \
http://localhost:8080/api/users/healthcheck > /dev/null || exit 1
# All functional tests passed
exit 0
Этот скрипт фактически тестирует основные функции вашего API, чтобы убедиться, что оно работает должным образом.
Практические Примеры проверки работоспособности
Вот полный файл Docker Compose, демонстрирующий проверку работоспособности типичного стека веб-приложений:
version: '3.8'
services:
db:
image: postgres:13
environment:
POSTGRES_PASSWORD: example
POSTGRES_USER: app
POSTGRES_DB: appdb
healthcheck:
test: ["CMD", "pg_isready", "-U", "app"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
redis:
image: redis:6
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 3
api:
build: ./api
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 15s
web:
build: ./frontend
depends_on:
api:
condition: service_healthy
ports:
- "80:80"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 10s
retries: 3
Рекомендации по повышению производительности для бесперебойной работы
Проверка работоспособности — это здорово, но она требует некоторых затрат. Вот несколько подробных советов, которые помогут обеспечить бесперебойную работу:
Балансировка частоты и использования ресурсов
Чем чаще вы проводите проверку работоспособности, тем быстрее вы обнаружите проблемы, но за счёт увеличения нагрузки на систему:
- Среды разработки: вы можете быть более агрессивными (интервалы 5-10 секунд), поскольку у вас, скорее всего, меньше контейнеров
- Тестирование/подготовка к работе: умеренная частота (интервалы 15–30 секунд) для баланса между скоростью отклика и нагрузкой на систему
- Производственные среды: более консервативный подход (интервалы 30-60 секунд) для минимизации нагрузки на загруженные системы
Оптимизация команд проверки работоспособности
Выполняемые вами команды могут существенно повлиять на производительность системы:
- Избегайте сложных запросов к базе данных — используйте простые запросы, такие как
SELECT 1
вместо сложных объединений или агрегирования - Сведите к минимуму операции ввода-вывода — чтение больших файлов или каталогов может замедлить проверку работоспособности
- Используйте встроенные утилиты для проверки работоспособности — многие сервисы предоставляют специальные команды для проверки работоспособности, оптимизированные для этой цели
- Будьте осторожны с HTTP-проверками — из-за медленной работы API проверка работоспособности может завершиться с ошибкой, что приведет к ложноотрицательным результатам
Эффективное управление тайм-аутами
Установка соответствующих тайм-аутов предотвращает зависание проверок работоспособности:
Масштабирование в зависимости от сложности — для более сложных проверок работоспособности требуется больше времени
Измерьте базовое время отклика — выполните проверку работоспособности вручную 10–20 раз и запишите среднее и максимальное время отклика
Установите время ожидания чуть больше максимального — если обычно ваша проверка занимает 0,5–2 секунды, время ожидания в 3 секунды может быть подходящим
Учитывайте задержку в сети — в распределенных системах добавьте дополнительное время с учетом задержек в сети
Optimizing Docker Health Checks for Reliable and Resilient Containers