Docker Compose is a tool that helps you manage your docker containers. It lets you create and manage multiple containers, each with its own set of dependencies. Docker Compose can also wait for dependent containers to be completed before starting the next one. This makes it easy to keep your applications running while you work on another one. To use Docker Compose, you first need to create a compose file in your project’s root directory. This file contains the following: -A list of all the containers that will be run together -A list of all the files that will be shared between them -A list of all the ports that will be open between them -A list of all the environment variables that will be set for each container The first line in our compose file is a list of all our containers. We’ll use this information to determine which ones we want to run first. The second line sets up our environment for each container. We’ll use these variables to control how each container behaves: NAME=foo BAR=bar . The third line tells Docker Compose which files we want to share between our containers and which ones we want to run first. We’ll use this information later on when we start our applications. The fourth line tells Docker Compose which ports should be open between our containers and which ones should run first. Finally, we add some basic configuration information for each container: NAME=foo BAR=bar . This tells Docker Compose how to start and stop these containers, as well as how to access their files and environment variables.
This isn’t always good enough though. Some of your containers might have dependencies on each other that break the application if they can’t be fulfilled. In this guide, we’ll show how you can configure your Compose services to accommodate these dependencies, making it possible to start containers in order.
The Basics
Docker Compose supports a depends_on field in docker.compose.yml files. Services can include the names of their siblings in depends_on. This prevents the container from starting until the depended-on services are up.
In this example, the depends_on fields cause the services to start in the following order:
db api web-app
Each service’s dependencies are resolved recursively. The service that defines each depends_on field is started last, at the very end of the chain. When a service depends on multiple other containers, they’ll be started in the order they’re listed in the depends_on field.
The chain of services is used in reverse when you stop a stack with docker-compose stop. With the example above, the web-app container will be deleted first, then api and db. This prevents requests to the web-app container from failing as a tear-down operation commences.
Waiting for Readiness
The default depends_on configuration only waits for dependent containers to start. In the example above, Compose can create the api container as soon as db is running, even if the database server inside the container isn’t ready to receive connections. This means depends_on is rarely sufficient on its own.
You can combine the feature with healthchecks to prevent containers from starting until their dependencies are actually ready. To use this capability, nest a condition field under depends_on with service_healthy as its value:
Now the api container has a healthcheck command attached. The web-app service is instructed not to start until api has been created with a successful healthcheck result. This will be once the API starts responding to requests and the curl command exits with a zero status code.
Waiting for a Successful Container Exit
In some cases your dependency might be a single-use container that you want to run to completion. You can wait on this kind of dependency by setting the condition field to service_completed_successfully. This is useful when you’ve got a first-run setup script that executes in another container.
This example shows how a dependent image could run a command that writes a config file to a volume shared by app. After the data’s been written, the config_builder container stops with a zero exit code. Compose then automatically starts the app service as its dependency condition has been met.
More Control With Other Tools
In some situations depends_on with a condition might still not be enough to accommodate your use case. You can add external tools to manually implement health checks and handle links between containers.
Wait-for-It is a utility script which wraps another process. It’ll run the command you specify after a certain condition is met. This can be used to define healthcheck procedures independently of Docker’s built-in support.
Here’s how to use healthcheck to wait for a linked container port to become accessible:
Here we’ve reverted to only making Docker Compose wait for the api container to start. The web-app service accepts responsibility for checking whether api is healthy. It uses the Wait-for-It script to detect when the container is accessible on port 8080. Wait-for-It will then launch the web app container’s real command, defined as node app.js.
This approach is best reserved for specific situations where you can’t set up a proper healthcheck with Docker. It might be necessary when you’re using a third-party image that can’t be configured to run a healthcheck command. Wait-for-It provides a way of detecting whether a port’s serving traffic as a stand-in replacement. While not infallible, this is often a good indicator of a container’s healthiness.
Summary
Docker Compose defaults to simultaneously starting all the services in your stack. This is often undesirable when links between the services create parent-child dependency relationships.
The depends_on field lets you define a startup sequence for your services. Compose will create each new container in order, guaranteeing the previous one has started before the next container is added.
You can wait for the previous container to exit or report a positive healthcheck by adding a condition to the dependency definition. In situations where healthchecks can’t be used, you can defer to tools like Wait-for-It to have parent containers detect when their dependencies are ready.