Docker Compose Control Container Order with depends_on
Learn how to control Docker container startup and shutdown order with the Docker Compose depends_on and healthcheck attributes. To demonstrate, we will connect a Node Docker container to a Postgres Docker container.
Table of Contents 📖
depends_on
When using Docker Compose, it is often important to control service startup and shutdown
order. For example, usually we want a database service to start before an application service, such as a
Node server. Docker Compose allows us to control container startup/shutdown order with the depends_on attribute.
To demonstrate this attribute, we will connect a Node server to a PostgreSQL database.
depends_on Short Syntax
As with most Docker Compose attributes, depends_on has two syntaxes: short and long. The short syntax allows us to specify the name of the service we want to depend on. For example, consider the following configuration of a Node server and Postgres database below.
server:
image: server:1.0.0
container_name: ${SERVER_HOST}
build:
context: ./server
dockerfile: Dockerfile
env_file: .env
ports:
- ${SERVER_PORT}:${SERVER_PORT}
volumes:
- ./server:/server
- server-v-node-modules:/server/node_modules
depends_on:
- database
database:
image: database:1.0.0
container_name: ${POSTGRES_HOST}
build:
context: ./database
dockerfile: Dockerfile
env_file: .env
ports:
- ${POSTGRES_PORT}:${POSTGRES_PORT}
volumes:
- database-v:/data/db
command: "-p ${POSTGRES_PORT}"
Here we are telling Docker Compose that the Node server depends on the Postgres database. Therefore, Docker Compose will create the database service before the server service and remove the server service before the database service. If we run the command docker compose up, we should expect our Node server to connect to our Postgres database without any issues. However, if we look at the console, this is not the case.
server-c | Error connecting to Postgres! Error: connect ECONNREFUSED 172.26.0.2:6778
server-c | at /server/node_modules/pg-pool/index.js:45:11
server-c | at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
server-c | at async main (file:///server/src/server.js:12:18) {
server-c | errno: -111,
server-c | code: 'ECONNREFUSED',
server-c | syscall: 'connect',
server-c | address: '172.26.0.2',
server-c | port: 6778
server-c | }
The error is refused because the database is not ready to accept connections yet. Later on in the console, we can see the following output.
postgres-c | 2024-04-12 15:12:32.055 UTC [1] LOG: database system is ready to accept connections
This line indicates that the database is ready to accept connections. However, it comes after the Node server has started. This is because the short hand depends_on syntax only tells Docker Compose to wait for the service to be up and running. The service could be up and running, but this doesn't mean the Postgres database inside the container is ready to accept connections.
depends_on Long Syntax
To fix this, we can use the long syntax for depends_on. This syntax allows us to add more configuration. For example, we can set the condition property.
depends_on:
database:
condition: service_healthy
By default, the condition property is set to service_started. Here we set it to service_healthy. This allows us to set a custom condition to determine if the service is ready. We can create this healthcheck inside the service we want to wait for.
healthcheck:
test: ["CMD-SHELL", "pg_isready -p ${POSTGRES_PORT} -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 5
The healthcheck attribute determines whether the service is healthy or not. Here, we are testing the health of the Postgres container every 5 seconds for 5 tries. We are testing the health by using the command supplied to test. This command is either a string or list. If it is a list the first item must be NONE, CMD, or CMD-SHELL. Setting it to CMD-SHELL runs a shell to call the command. The command we are running is the utility command pg_isready.
- pg_isready - A utility command to check the connection status of a PostgreSQL server.
- -p - Specifies the port number of the PostgreSQL server.
- -U - Specifies the username to connect to the server.
- -d - Specifies the name of the database to connect to.
Now when we re-run our services with docker compose up, we will have a successful connection.
postgres-c | 2024-04-12 15:57:38.741 UTC [1] LOG: database system is ready to accept connections
server-c |
server-c | > start
server-c | > nodemon .
server-c |
server-c |
server-c | [nodemon] 3.1.0
server-c | [nodemon] to restart at any time, enter `rs`
server-c | [nodemon] watching path(s): *.*
server-c | [nodemon] watching extensions: js,mjs,cjs,json
server-c | [nodemon] starting `node .`
server-c | [
server-c | {
server-c | subscriber_id: 1,
server-c | name: 'WittCepter',
server-c | email: 'the-best-chrome-extension@a.com'
server-c | }
server-c | ]
server-c | Connected to Postgres!