How depends_on Works in Docker Compose
Learn how to use depends_on with health checks in Docker Compose. This tutorial demonstrates how to enhance service dependencies by integrating health checks, ensuring that dependent services are not just started but are also in a healthy state before others start.
Are you struggling to make some services start or stop in the right order? Well, then you have come to the right place! 💪
In this short Docker Compose tutorial, I will show you how depends_on
can help you in your compose files to specify the order of how your services are started and stopped when deploying a new Docker stack. 🐳
Imagine you have an API service that needs a database service to be ready before it can start. When we deploy services using infrastructure as code (IaC), we are not in control with the mouse for coordinating the startup of our services. This issue can easily be solved using depends_on
in the Docker Compose file describing your services.
Below is a classic Docker Compose example where depends_on
is used. I will continue my explanation below on how you can control services during startup.
version: '3'
services:
my_custom_app:
build: .
depends_on:
- custom_db_server
custom_db_server:
image: mongo
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
MONGO_INITDB_DATABASE: my_database
If you would like to know how you can launch a MongoDB server with Docker, you can check out the article below.
How To Control Services During Startup
Okay... before you implement depends_on
in your Docker Compose file, please note the following.
So Christian... How can I get around that annoying problem? Ohh I am glad you asked! Conditions are the answer - with conditions we can define a certain property to be satisfied before the depending services will start. Currently, we have the following options.
service_started
service_healthy
service_completed_successfully
Let's take a look at these three options, step-by-step.
Using service_started
in Docker Compose
When you use depends_on
this is the condition Compose is looking for during startup. As I mentioned before, it does not verify if the database or specific service is in a ready state and that can lead to issues.
Before we fix this, (I will show you the fix later in this tutorial) I would like to show you how to set a condition on the app for the database using service_started
. This will make sure that the database has started before launching the next service.
version: '3'
services:
my_custom_app:
build: .
depends_on:
custom_db_server:
condition: service_started
custom_db_server:
image: mongo
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
MONGO_INITDB_DATABASE: my_database
As you might have noticed we are now having a condition for the depends_on
where we would like the service to be started before the my_custom_app
is started. But that is not good, as we don't know if MongoDB is ready to accept connections.
Let's fix that issue by using health checks.
Using service_healthy
in Docker Compose
Compose also has a condition named service_healthy
, and that one is the perfect choice for making sure that our database/service is healthy and ready to work.
We can use this condition when a health check has been configured on the database/service we are depending on. This could be a ping, migrations, jobs, etc... We wan't to make sure this health check is successfully completed before staring other services depending on the failed service.
Let's see how that could be accomplished with a real-life example for MongoDB and our custom web app.
version: '3'
services:
my_custom_app:
build: .
depends_on:
custom_db_server:
condition: service_healthy
custom_db_server:
image: mongo
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
MONGO_INITDB_DATABASE: my_database
healthcheck:
test: ["CMD", "mongo", "--eval", "db.adminCommand('ping')"]
interval: 5s
timeout: 3s
retries: 5
In my example above, MongoDB/cutom_db_server
will start up the database service, then run a command to test if the database is ready. When it report itself with a healthy state we will start up the other services depending on it.
I have configured the health check to check every 5 seconds, allow the service to be up to 3 seconds to respond and only report an unhealthy state when it has tried 5 times.
On the my_custom_app
we have a condition on the depends_on
for the database service and that is to make sure that the healthcheck is reporting healthy before starting up the app service.
Here are a few other health checks you can use on MongoDB if you need that.
Check the database connection
healthcheck:
test:
- "CMD"
- "mongo"
- "--quiet"
- "127.0.0.1/test"
- "--eval"
- "'quit(db.runCommand({ ping: 1 }).ok ? 0 : 2)'"
interval: 10s
timeout: 10s
retries: 5
start_period: 40s
start_period
is used to specify the time to wait before starting to run health checks (40 seconds in this case). This allows the service some time to start before health checks commence.
Ref: https://github.com/rodrigobdz/docker-compose-healthchecks#mongo
Check for a specific collection
healthcheck:
test: ["CMD", "mongo", "--eval", "db.getCollectionNames()"]
interval: 5s
timeout: 3s
retries: 5
Using service_completed_successfully
in Docker Compose
We have a third option named service_completed_successfully
and that one is very usefull if we want something to start, run a job like migrating a database, etc...
If you want this condition to be satisfied you need to make sure that the service running this one-time-job exits/stops with a status code 0
as it's the criteria of success.
Here is an updated version of the compose file with a migration service and the my_custom_app
updated to have one more depends_on
condition.
version: '3'
services:
my_custom_app:
build: .
depends_on:
my_custom_db:
condition: service_healthy
my_custom_migration:
condition: service_completed_successfully
my_custom_db:
image: mongo
healthcheck:
test: ["CMD", "mongo", "--eval", "db.adminCommand('ping')"]
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example
MONGO_INITDB_DATABASE: my_database
my_custom_migration:
image: awesome-migration-job
This ensures that the my_custom_db
is started and that the migrations has been applied to the database before we launch our application.
Summary
I hope you learned something from this short tutorial on how to use depends_on
with Docker Compose.
In this tutorial, you have learned how to await dependent services based on different conditions and seen how you can utilize health checks to your advantage when starting services.
If you got any questions, please let me know in the comments below. Until next time happy Dockerizing stuff! ✌️