Пошук уроків, статей та іншого контенту
Визначите порядок запуску контейнерів за допомогою depends_on і зрозумієте обмеження простого очікування запуску.
У застосунку, що складається з кількох контейнерів, сервіси часто залежать один від одного:
API використовує базу даних;
вебсервер передає запити до API;
фоновий обробник отримує завдання з черги.
Docker Compose може запустити всі сервіси однією командою:
docker compose upЗа замовчуванням Compose намагається запускати сервіси в порядку, визначеному їхніми залежностями. Для опису залежності використовується властивість depends_on.
depends_onРозглянемо файл compose.yaml:
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: appdb
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
api:
image: alpine:3.20
depends_on:
- db
command: ["sh", "-c", "echo 'API запущено'; sleep 3600"]У цьому прикладі api залежить від db.
depends_on:
- dbПід час виконання docker compose up Compose:
створить і запустить контейнер db;
після цього створить і запустить контейнер api.
Назва db також є мережевим іменем сервісу. Інші контейнери можуть звертатися до бази даних за адресою:
dbНаприклад, рядок підключення до PostgreSQL може мати такий вигляд:
postgresql://app:secret@db:5432/appdbdepends_onПростий синтаксис гарантує порядок запуску контейнерів, але не готовність застосунку всередині контейнера.
Після запуску контейнера PostgreSQL процес бази даних може ще виконувати ініціалізацію:
створювати системні таблиці;
застосовувати початкові налаштування;
відкривати порт для підключень.
Compose бачить, що контейнер db уже запущений, але не обов’язково знає, що PostgreSQL вже приймає підключення.
Тому api може стартувати занадто рано:
api запущено
помилка підключення до бази данихЦе важлива різниця:
контейнер запущений — процес контейнера працює;
сервіс готовий — сервіс завершив ініціалізацію і може обробляти запити.
depends_on у простій формі очікує саме запуск контейнера, а не готовність сервісу.
healthcheckЩоб очікувати не лише запуск контейнера, сервісу можна додати перевірку стану:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
interval: 5s
timeout: 5s
retries: 5
start_period: 5sЗначення властивостей:
test — команда, якою перевіряється сервіс;
interval — інтервал між перевірками;
timeout — максимальний час однієї перевірки;
retries — кількість невдалих перевірок до статусу unhealthy;
start_period — час на початковий запуск, коли невдалі перевірки не враховуються.
Для PostgreSQL команда pg_isready перевіряє, чи сервер приймає підключення.
healthyУ розширеному синтаксисі depends_on можна вказати умову service_healthy:
depends_on:
db:
condition: service_healthyТоді залежний сервіс буде запущено лише після того, як перевірка стану бази даних завершиться успішно.
Повний приклад:
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: appdb
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
interval: 5s
timeout: 5s
retries: 5
start_period: 5s
adminer:
image: adminer:4
depends_on:
db:
condition: service_healthy
ports:
- "8080:8080"Запустіть сервіси:
docker compose upУ цьому випадку:
Compose запустить db;
PostgreSQL почне проходити перевірки стану;
після успішної перевірки Compose запустить adminer.
Adminer буде доступний на порту 8080. Під час підключення до PostgreSQL як сервер потрібно вказати:
dbКористувацькі дані:
Сервер: db
Користувач: app
Пароль: secret
База даних: appdbУ розширеному синтаксисі можна використовувати кілька умов.
service_starteddepends_on:
db:
condition: service_startedЗалежний сервіс запускається після запуску контейнера db.
Це фактично поведінка простого синтаксису:
depends_on:
- dbЦя умова не перевіряє готовність застосунку.
service_healthydepends_on:
db:
condition: service_healthyЗалежний сервіс запускається після того, як залежність отримає статус healthy.
Для цього залежність повинна мати налаштований healthcheck.
service_completed_successfullyservices:
migration:
image: example/migrations
command: ["./run-migrations"]
api:
image: example/api
depends_on:
migration:
condition: service_completed_successfullyУ такому випадку api запуститься після успішного завершення контейнера migration.
Цей варіант підходить для одноразового завдання, наприклад міграції бази даних. Він відрізняється від довготривалого сервісу: контейнер migration має завершити роботу з кодом 0.
Статус контейнерів можна переглянути командою:
docker compose psУ результаті для бази даних буде видно стан на кшталт:
Up (healthy)Логи сервісу можна переглянути так:
docker compose logs dbАбо в режимі реального часу:
docker compose logs -f dbСтатус перевірки можна також подивитися через Docker:
docker inspect --format='{{json .State.Health}}' <container_name>Назву контейнера можна отримати за допомогою:
docker compose pshealthcheck не вирішує всі проблемиhealthcheck перевіряє лише конкретну умову, яку ви описали. Наприклад, pg_isready підтверджує, що PostgreSQL приймає підключення, але не гарантує, що:
потрібна таблиця вже створена;
міграції вже виконані;
дані мають очікувану структуру;
API може успішно виконати будь-який запит.
Тому перевірка повинна відповідати реальній умові готовності сервісу.
Також запуск у правильному порядку не гарантує безперервної роботи. Після запуску база даних може тимчасово стати недоступною через перезапуск або помилку. Застосунок має коректно обробляти такі ситуації та повторювати підключення, якщо це потрібно.
depends_on перевіряє портdepends_on:
- dbЦя конструкція не гарантує, що порт бази даних уже приймає підключення. Вона визначає порядок запуску контейнерів.
Для очікування готовності додайте healthcheck і використайте service_healthy.
Усередині мережі Compose сервіси звертаються один до одного за іменем сервісу:
dbНе потрібно використовувати localhost. Усередині контейнера localhost вказує на поточний контейнер, а не на контейнер бази даних.
healthcheck для service_healthyТакий фрагмент не має очікуваного сенсу:
depends_on:
db:
condition: service_healthyЯкщо для db не налаштовано перевірку стану, Compose не матиме визначеного способу перевірити готовність сервісу.
Перевірка на кшталт успішного існування процесу не завжди означає, що сервіс готовий приймати запити. Команда в healthcheck має перевіряти саме доступність потрібної функції.
healthcheck довгою затримкоюКоманда такого типу ненадійна:
command: ["sh", "-c", "sleep 10 && ./start-api"]Фіксована затримка може бути:
замалою на повільному середовищі;
зайвою на швидкому середовищі;
нездатною визначити реальну помилку запуску залежності.
Перевірка стану описує умову готовності, а не вгадує час запуску.
depends_on визначає порядок запуску сервісів.
Простий синтаксис depends_on очікує запуск контейнера, але не готовність програми.
healthcheck описує, як перевірити готовність сервісу.
Умова service_healthy дозволяє запускати залежний сервіс після успішної перевірки.
service_started відповідає очікуванню запуску контейнера.
service_completed_successfully підходить для одноразових успішних завдань.
Навіть із healthcheck застосунок має бути готовим до тимчасової недоступності залежностей.