Управление порядком запуска в Docker Compose

TL;DR
Docker Compose по умолчанию запускает сервисы параллельно. Чтобы гарантировать порядок запуска, используйте поле depends_on в файле docker-compose.yml, а для реальной готовности сервиса комбинируйте depends_on с healthcheck или внешними утилитами типа wait-for-it. В статье — примеры YAML, рекомендации, чек-листы и варианты отладки.
Быстрые ссылки
- Основы
- Ожидание готовности
- Ожидание успешного завершения
- Дополнительные инструменты
- Когда это не работает
- Чек-листы для ролей
- Итог
Основы
Docker Compose поддерживает поле
depends_onв файлах
docker-compose.ymlСервис может перечислить имена других сервисов в
depends_on, чтобы предотвратить запуск до тех пор, пока указанные зависимости не будут созданы. Пример минимальной конфигурации:
services:
api:
image: example.com/api:latest
depends_on:
- db
web-app:
image: example.com/web-app:latest
depends_on:
- api
db:
image: mysql:8.0В этом примере поля
depends_onопределяют порядок создания контейнеров: сначала db, затем api и в конце web-app. Зависимости разрешаются рекурсивно: сервис, который объявляет depends_on, запускается после сервисов, от которых он зависит. Если сервис зависит от нескольких сервисов, Compose попытается запустить их в порядке перечисления.
При остановке стека команда
docker-compose stopпользуется обратным порядком: web-app будет остановлен первым, затем api и в конце db. Это предотвращает ситуацию, когда frontend всё ещё принимает запросы, а backend уже выключен.
Важно: depends_on по умолчанию ждёт только создания контейнера, но не его готовности к обслуживанию.
Ожидание готовности
Поле
depends_onв базовой форме гарантирует лишь, что зависимый контейнер создан и запущен, но не что приложение внутри него готово принимать запросы. Чтобы дождаться реальной готовности, используйте встроенные healthcheck-ы Docker и указывайте условие service_healthy.
Пример с healthcheck:
services:
api:
image: example.com/api:latest
depends_on:
- db
healthcheck:
test: ["CMD-SHELL", "curl --fail http://127.0.0.1 || exit 1"]
interval: 10s
retries: 5
start_period: 5s
timeout: 10s
web-app:
image: example.com/web-app:latest
depends_on:
api:
condition: service_healthy
db:
image: mysql:8.0В этом примере для api определён healthcheck, который возвращает успешный статус только когда API отвечает на HTTP-запросы. web-app не будет запущен, пока состояние api не станет healthy. Подсказка: используйте CMD-SHELL в healthcheck для возможности писать более сложные команды.
Советы по healthcheck:
- Тест должен быть быстрым и идемпотентным. Проверяйте конкретную точку здоровья (health endpoint) вместо общей страницы.
- Настраивайте start_period, interval, timeout и retries для учета времени прогрева сервисов.
- Healthcheck исполняется внутри контейнера, значит пути и утилиты должны быть доступны внутри образа.
Ожидание успешного завершения
Иногда зависимость — это контейнер одноразовой задачи (one-off), который должен успешно завершиться перед стартом другого сервиса. Пример: генерация конфига или миграции БД. Для этого используйте condition: service_completed_successfully.
services:
app:
image: example.com/app:latest
depends_on:
config_builder:
condition: service_completed_successfully
volumes:
- config:/opt/app/config
config_builder:
image: example.com/config_builder:latest
env:
- EXAMPLE_KEY
- ANOTHER_KEY
volumes:
- config:/output
volumes:
config:Здесь config_builder запускается первым, записывает конфигурацию в общий том и корректно завершается. Compose ожидает успешного выхода config_builder и затем запускает app.
Обратите внимание: если config_builder завершится с ненулевым кодом — зависимый сервис не будет запущен.
Дополнительные инструменты
В ситуациях, когда вы не можете добавить healthcheck в образ (например, сторонний образ без утилит), вы можете использовать внешние скрипты и утилиты, которые ждут доступности порта или ответа сервиса. Одним из популярных инструментов является wait-for-it или similar-wait-scripts.
Пример использования wait-for-it в docker-compose:
services:
api:
image: example.com/api:latest
depends_on:
- db
web-app:
image: example.com/web-app:latest
depends_on:
- api
command: ["./wait-for-it.sh", "api:8080", "--", "node", "app.js"]
db:
image: mysql:8.0Здесь web-app сам проверяет доступность api на порту 8080 и запускает node app.js только после того, как api отвечает. Такой подход полезен, когда нельзя изменить образ api или прописать в нём healthcheck.
Уточнение по wait-for-it:
- Это внешняя утилита, которая блокирует запуск основного процесса до достижения условия.
- Она проверяет лишь достижимость TCP-порта, что не всегда означает готовность приложения (например, порт может быть открыт, но сервис ещё не инициализирован).
- Подходит как быстрый обходной путь, но лучше реализовать полноценный healthcheck в образе.
Когда depends_on не решает проблему
Несколько типичных ситуаций, когда базовый depends_on недостаточен:
- Сервис поднят, но не готов обрабатывать запросы (например, миграция БД ещё выполняется).
- Сторонний образ не имеет необходимых утилит для выполнения healthcheck.
- Сервис считает себя “готовым” только после выполнения фоновых задач, которые не отражаются на простом TCP-пинговании.
Что делать:
- Добавьте healthcheck в Dockerfile/образ, если возможно.
- Используйте one-off контейнеры для инициализации (миграции, генерация конфигов) и condition: service_completed_successfully.
- Если образ нельзя изменить, используйте обёртки типа wait-for-it или собственные скрипты запуска с логикой проверки.
- Рассмотрите оркестрацию (Kubernetes), если вам нужна более гибкая логика восстановления и зависимости на уровне приложений.
Отладка и распространённые ошибки
- Логи healthcheck: смотрите docker inspect –format=’{{json .State.Health}}’
для детального состояния healthcheck. - Проверяйте, что команды healthcheck доступны в образе и работают локально.
- Если depend_on использует condition, убедитесь, что вы используете совместimую версию Compose (v2+ синтаксис vs v3 может отличаться по поддержке условных зависимостей).
- Не путайте завершение контейнера с безопасным завершением; если контейнер постоянно падает — зависимый сервис не запустится.
Чек-листы для ролей
Разделённый по ролям, краткие списки задач, которые помогут стандартизировать работу при настройке порядка запуска.
Разработчик приложения:
- Добавить эндпоинт /health или /ready.
- Написать простой healthcheck, который проверяет реальные зависимости (БД, кеш).
- Убедиться, что командный образ содержит curl или иной инструмент для проверки.
DevOps-инженер:
- Добавить healthcheck в docker-compose.yml или Dockerfile.
- Настроить depends_on с condition: service_healthy при необходимости.
- Организовать раздельные one-off сервисы для миграций и генерации конфигов.
Тестировщик:
- Проверить сценарии старта: чистая база, миграции, потеря сети.
- Воспроизвести падение зависимого сервиса и убедиться, что поведение ожидаемое.
- Написать автоматические тесты, которые проверяют порядок запуска и доступность конечных точек.
Факт-бокс
- depends_on по умолчанию проверяет только создание контейнера, а не его внутреннюю готовность.
- service_healthy требует корректно настроенного healthcheck внутри контейнера.
- service_completed_successfully полезен для одноразовых задач и миграций.
Модель принятия решения
Ниже — упрощённый поток принятия решения, который поможет выбрать подходящий механизм.
flowchart TD
A[Нужен порядок запуска?] -->|Нет| B[Запускать параллельно]
A -->|Да| C[Являются ли зависимости долгоживущими сервисами?]
C -->|Да| D[Можно ли добавить healthcheck в образ?]
C -->|Нет| E[Использовать service_completed_successfully]
D -->|Да| F[Добавить healthcheck и depends_on: service_healthy]
D -->|Нет| G[Использовать wait-for-it или обёртку в command]Критерии приёмки
- Сервисы стартуют в ожидаемом порядке при запуске docker-compose up.
- Сервисы не падают в процессе старта из-за отсутствия зависимостей.
- Healthcheck корректно отражает готовность сервиса.
- One-off контейнеры корректно завершаются с кодом 0, и зависимые сервисы стартуют после этого.
Краткий словарь
- depends_on: директива Compose для объявления порядка запуска.
- healthcheck: команда внутри образа для проверки состояния сервиса.
- service_healthy: условие, что сервис считается ready по результатам healthcheck.
- service_completed_successfully: условие, когда контейнер завершился с кодом 0.
Частые вопросы
Можно ли заставить depends_on ждать только порт TCP?
Да. Если добавить в образ или команду обёртку вроде wait-for-it, зависимый сервис может проверять доступность TCP-порта и запускать основную команду только после открытия порта.
Что делать с образами, в которых нельзя установить healthcheck?
Используйте внешние скрипты ожидания или создайте вспомогательный контейнер-инициализатор, который проверяет готовность стороннего сервиса.
Зависит ли поведение от версии Compose или формата файла?
Да. Некоторые старые версии docker-compose имели отличия в поддержке условных зависимостей. Рекомендуется использовать современный синтаксис и проверять документацию для вашей версии.
Итог
- Используйте depends_on для упорядочивания старта контейнеров.
- Для реальной готовности комбинируйте depends_on с healthcheck и condition: service_healthy.
- Для одноразовых задач применяйте condition: service_completed_successfully.
- Если образ нельзя изменить, используйте утилиты ожидания или собственные скрипты.
Важно: настройка порядка запуска — это один из инструментов надёжного развёртывания, но для более сложных сценариев стоит рассмотреть полноценные системы оркестрации и стратегии восстановления.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента