Skip to main content

Understanding the depends_on condition in Docker compose files

ยท 3 min read
Christophe
Markdown, WSL and Docker lover ~ PHP developer ~ Insatiable curious.

Understanding the depends_on condition in Docker compose files

It's only been ten days or so since I learned the trick, even though it was well documented: managing service startups and, above all, blocking one if the other isn't ready (official documentation).

Imagine a two services applications like Joomla (see my Create your Joomla website using Docker), WordPress, LimeSurvey, Laravel and many, many more use cases: you've an application and that application requires a database.

You've, roughly speaking, a docker-compose.yml file like this:

services:
joomla:
image: joomla
[...]

joomladb:
image: mysql:8.0.13
[...]

And, yeah, it works. You can execute docker compose up --detach and wait until the two services are up and soon or later, you'll got your application ready.

But you have the intuition that something isn't quite right here... What happens if the database service is slow to load? You'd have the application (Joomla here, but it doesn't really matter) which, in its initialization process, is going to want to connect to the database, and wham! This will not work and you will receive Error when connecting to the database errors. With a bit of luck, the application will try several times before stopping in error. Without chance, the application will just crash.

How to solve this? The answer is in two parts.

  1. You need to instruct Docker how he can know that the service is ready,
  2. You need to pause the application service until the database is ready.

The healthcheck propertyโ€‹

The idea is to ask Docker to run a given command each xxx seconds until he got a Success status (in term of Linux, it's a command that return an exitcode equal to 0).

By searching on the Internet using docker healthcheck followed by the name of a service (MySQL, PostgreSQL, Apache, Redis, ...), you'll find a lot of possibilities.

For MySQL, we'll use the next one:

services:
joomla:
image: joomla
[...]

joomladb:
image: mysql:8.0.13
[...]
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
timeout: 20s
retries: 10

The four lines here above informs Docker to check each 20 seconds and max 10 times the command defined by the test property. While that command didn't return 0, the container will be considered as unhealthy. Then, hopefully, the command will return 0 and Docker will consider the service as healthy.

The depends_on propertyโ€‹

Now, the second part is to create a dependency in our application. Back to the Joomla service (in our example), we'll add a depends_on property like below.

services:
joomla:
image: joomla
[...]
depends_on:
joomladb:
condition: service_healthy

joomladb:
image: mysql:8.0.13
[...]
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
timeout: 20s
retries: 10

It's pretty self-explanatory, I think. Docker will pause the creation of the Joomla container (just the creation, not downloading the image or any previous step) while the depends_on service isn't healthy.

And do you know what? I'm mad I didn't know about this sooner, because I've already set up a script like the one below in my applications:

Very simplified script
while [[ ! "$exitCode"  = "0" ]]; do
echo "Waiting MySQL to launch on 3306..."
exitCode="$(nc joomladb 3306)"
done