Skip to main content
Welcome to this comprehensive guide on Docker Compose. In this article, you’ll learn how to configure and run multi-container Docker applications using YAML configuration files. A solid understanding of YAML is essential since Compose files are entirely written in this format.

Running Individual Containers with Docker Run

Before diving into Docker Compose, let’s review how to run individual Docker containers using the docker run command. For simple containers, you may execute commands like the following:
When your application consists of multiple services, managing each container separately can become cumbersome. Docker Compose streamlines this process by allowing you to define all required services in a single YAML file (commonly named docker-compose.yml). You can then launch the complete stack with the docker-compose up command.

Example: Basic Docker Compose Configuration

Below is an example Docker Compose file that defines multiple services:
Start your multi-container application with:
These instructions assume that you are running containers on a single Docker host. We’ll explore more details about YAML file structures further in this guide.

Sample Application: Voting App Architecture

To illustrate Docker Compose in practice, consider a sample voting application. This application demonstrates how Docker can integrate services built with different programming languages and frameworks.

Voting Application Components

  • Python Front-End: A web interface that lets users vote between options (e.g., cat or dog). Votes are stored in a Redis instance, serving as an in-memory database.
  • .NET Worker: A background service that processes votes and updates a PostgreSQL database with the vote counts.
  • Node.js Back-End: A web application that displays voting results by reading data from PostgreSQL.
Below is the diagram that outlines the voting application’s architecture and data flow:
The image shows a sample voting application architecture with components using Python, Redis, .NET, and PostgreSQL, displaying a vote count for cats and dogs.
This architecture clearly demonstrates Docker’s versatility in handling services developed in languages such as Python, Node.js, and .NET.

Deploying the Application Using Docker Run

To get started, let’s deploy each layer of the voting application using individual Docker run commands. This example assumes that all necessary images are available in your Docker repository.
  1. Start a Redis Container:
  2. Deploy the PostgreSQL Database:
  3. Deploy the Voting Application (Front-End): Map the container’s port 80 to host port 5000.
  4. Deploy the Results Web Application (Back-End): Map the container’s port 80 to host port 5001.
  5. Deploy the Worker Container:
At this point, all containers are running. However, they are isolated—meaning the voting app does not know where to locate the associated Redis or PostgreSQL service.

Linking Containers

To enable communication between containers, use the --link option. This option creates an entry in the container’s /etc/hosts file for resolving the linked service by name. For example, link the voting app container to Redis as follows:
Similarly, link the results app to PostgreSQL:
For the worker container that requires access to both Redis and PostgreSQL, run:

Accessing Linked Containers in Code

Below is an example of how the voting application might access Redis:
And here’s how the worker application might connect to PostgreSQL:
Linking containers using the --link option is deprecated. Modern Docker networking features, like those in Docker Swarm, provide more robust solutions.

Transitioning to Docker Compose

After verifying the Docker run commands, it’s straightforward to transition to a Docker Compose configuration. By combining all container definitions into a single YAML file, you can simplify multi-container deployments.

Docker Run Commands Recap

Equivalent Docker Compose File

For services that have not yet been built, you can use the build option. For example, if the voting app source code resides in a folder named vote, update your Compose file like this:

Understanding Docker Compose File Versions

Docker Compose file formats have evolved from version 1 to version 3, each introducing new features and improvements.

Version 1

Version 1 files define services at the root level and rely on links for networking:

Version 2

Version 2 introduces a services section and improvements such as depends_on for defining container dependencies:

Version 3

Version 3 retains a similar structure to version 2 but adds support for Docker Swarm along with enhanced networking capabilities:
For more details, consult the Docker Documentation.

Configuring Networks in Docker Compose

Docker Compose lets you define custom networks to control traffic between services. For instance, you might separate external (user-facing) traffic from internal (service-to-service) communication.

Example: Defining Separate Networks

This example configuration connects the voting and results applications to both the front-end (user traffic) and back-end (internal services) networks, while Redis and PostgreSQL are only accessible on the back-end network.
This configuration ensures that internal data remains secure while still allowing user access to essential services.

Conclusion

Now that you have a comprehensive understanding of Docker Compose, it’s time to put this knowledge into practice. Whether you’re managing simple multi-container applications or complex microservices architectures, Docker Compose empowers you to streamline deployments and manage configurations efficiently. Happy coding and containerizing!

Watch Video