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.
- You need to instruct Docker how he can know that the service is ready,
- 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:
while [[ ! "$exitCode" = "0" ]]; do
echo "Waiting MySQL to launch on 3306..."
exitCode="$(nc joomladb 3306)"
done