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.