How to reliably manage container dependencies at initialization time with Docker Compose

How to reliably manage container dependencies at initialization time with Docker Compose

In this article, we will explore how to reliably manage inter-container dependencies at initialization time with Docker Compose

Docker Compose is a powerful tool for managing Docker container orchestration. When working with a complex application composed of multiple services, it is essential to ensure that containers are started and initialized in a specific order, especially when dependencies exist between them. In this article, we will explore how to reliably manage inter-container dependencies at initialization time with Docker Compose.

Understanding dependencies

Before tackling dependency management, it is crucial to understand the relationships between the various services in your Docker Compose environment. For example, imagine you have a web application that depends on a database. In this case, the web service should expect the database service to be fully initialized before starting.

Using depends_on

Docker Compose offers the depends_on attribute that allows you to declare dependencies between services. However, it is important to note that depends_on does not guarantee that one service is fully started before another is started. In other words, just because a service is "started" does not mean it is ready to be used.

Here is an example of how to use depends_on in your docker-compose.yml file:


version: '3'
services:
   web:
     image: web-app
     depends_on:
       - db
   db:
     image: database

In this example, the web service depends on the db service, but there is no guarantee that the database will be ready for connections when the web service is started .

Advanced Options of depends_on

condition

The condition option allows you to specify a custom condition for the dependent service. For example, you can use this option to check whether a service is in a specific state before starting the dependent service. Here's an example:


version: '3'
services:
   web:
     image: web-app
     depends_on:
       db:
         condition: service_healthy
   db:
     image: database

In this case, the web service will have an additional delay if the db service is not reported as healthy.

max_retries

The max_retries option allows you to specify the maximum number of retries that Docker Compose should make before considering a service as ready. This can be useful in situations where a service may take a while to fully start.


version: '3'
services:
   web:
     image: web-app
     depends_on:
       db:
         max_retries: 10
   db:
     image: database

In this example, Docker Compose will make up to 10 attempts to connect to the db service before considering that the web service can be started.

timeout

The timeout option allows you to specify a time limit for how long Docker Compose should wait before considering a service to be ready. It can be useful to avoid indefinite waits.


version: '3'
services:
   web:
     image: web-app
     depends_on:
       db:
         timeout: 60 seconds
   db:
     image: database

In this example, Docker Compose waits a maximum of 60 seconds before considering the db service ready for the web service.

Wait for Service with wait-for-it

To ensure that a service is fully initialized before starting another, you can use the wait-for-it script. This script waits for a service to be available before continuing to run the startup script.

Download the script wait-for-it.sh:


curl -o wait-for-it.sh https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh
chmod +x wait-for-it.sh

Add the script in your services:


version: '3'
services:
   web:
     image: web-app
     command: ["./wait-for-it.sh", "db:5432", "--", "start-web.sh"]
     depends_on:
       - db
   db:
     image: database

In this example, the web service uses the wait-for-it.sh script before running the actual command (start-web.sh). This ensures that the web service waits for the db service to be available before continuing execution.

Using Orchestration Tools

Some situations may require a more advanced solution. Tools like Dockerize or Docker Compose and Wait are specifically designed to address dependency management issues and can be integrated into your container initialization process.


version: '3'
services:
   web:
     image: web-app
     command: ["dockerize", "-wait", "tcp://db:5432", "-timeout", "1m", "./start-web.sh"]
   db:
     image: database

This example uses Dockerize in the web service start command to wait for the database service to be available before running start-web.sh.

Conclusions

Reliably managing dependencies between containers at initialization time with Docker Compose requires a combination of dependency declarations (depends_on) and additional tools such as wait-for-it or Dockerize. Make sure you understand the specific needs of your application and carefully test your configuration to ensure proper dependency management in a complex Docker Compose environment.