Docker Compose: A Master Guide with Real-Time Examples

Docker Compose: A Master Guide with Real-Time Examples

Introduction

Docker Compose is a powerful tool that simplifies the management of multi-container Docker applications. It allows developers and DevOps engineers to define, configure, and run multiple services using a single YAML file. In this blog, we'll cover Docker Compose in an easy-to-understand way, with real-world examples that you can apply in your DevOps journey.

What is Docker Compose?

Docker Compose is a tool used to define and run multi-container applications. Instead of managing individual docker run commands, you can use a docker-compose.yml file to configure and start your entire application stack with a single command.

Why Use Docker Compose?

  • Simplifies Multi-Container Applications: Manage multiple services using a single file.

  • Improves Development Workflow: Easily set up and tear down environments.

  • Supports Networking and Dependencies: Automatically links services together.

  • Compatible with Different Environments: Use the same configuration for local development and production.

Components of compose file:

  • version - specifies the version of the Compose file.

  • services - it the services in your application.

  • networks - you can define the networking set-up of your application.

  • volumes - you can define the volumes used by your application.

  • configs - configs lets you add external configuration to your containers. Keeping configurations external will make your containers more generic.

Installing Docker Compose

Docker Compose is included by default in Docker Desktop for Windows and macOS. For Linux, install it using:

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
ls /usr/local/bin/
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose version

Basic compose commands:

  • To execute the compose file:

      docker-compose up -d
    
  • To build the Dockerfile:

      docker-compose build
    
  • To remove the containers

      docker-compose down
    
  • To show the configurations of the compose file

      docker-compose config
    
  • To show the images of the file

      docker-compose images
    
  • To stop the containers

      docker-compose stop
    
  • To show the log details of the file

      docker-compose logs
    
  • To pause the containers

      docker-compose pause
    
  • To unpause the containers

      docker-compose unpause
    
  • To see the containers of the compose file

      docker-compose ps
    

Lets write the basic compose file to understand how it works:

Create a file with docker-compose.yaml name

version: "3"
services:
  webapp1:
    container_name: container_name
    build: <your-Dockerfile-Path>
    ports:
      - "host_port:container_port"

  webapp2:
    container_name: container_name
    build: <your-Dockerfile-Path>
    ports:
      - "host_port:container_port"

In the above compose, i am creating 2 services (webapp1, webapp2). For each service we have to provide container_name, path of your Dockerfile and ports to access the application.

Example compose file to create multiple services:

Clone the repo to get the source code

git clone https://github.com/devops0014/compose.git

Now go to folder

cd compose/paytm

you will find 3 folder [“bus-tickets”, “movie-tickets”, “train-tickets”]

lets write the compose file with docker-compose.yml

---
version: "3"
services:
  movie:
    container_name: movie-container
    build: ./movie-tickets
    ports:
      - "8081:80"

  bus:
    container_name: bus-container
    build: ./bus-tickets
    ports:
      - "8082:80"

  train:
    container_name: train-container
    build: ./train-tickets
    ports:
      - "8083:80"

Here is the basic compose file for deploying those 3 services.

lets build the Dockerfiles

docker-compose build

To create the services

docker-compose up -d

Lets check the containers:

docker-compose ps

Now lets check the output for 3 services:

output-1:

output-2:

output-3:


Volumes in Compose File:

In the above example we just used containers and images on our compose file, now lets use volumes for our compose file:

---
version: "3"
services:
  movie:
    container_name: movie-container
    build: ./movie-tickets
    ports:
      - "8081:80"
    volumes:
      - movie_volume:/usr/share/nginx/html:ro

  bus:
    container_name: bus-container
    build: ./bus-tickets
    ports:
      - "8082:80"
    volumes:
      - bus_volume:/usr/share/nginx/html:ro

  train:
    container_name: train-container
    build: ./train-tickets
    ports:
      - "8083:80"
    volumes:
      - train_volume:/usr/share/nginx/html:ro

volumes:
  movie_volume:
  bus_volume:
  train_volume:

Now lets use docker-compose up -d command to create a docker containers, so the containers will recreate with volumes

Now lets check the containers and volumes

docker-compose ps

docker volume ls

Now if you make any changes in volume it will replicated in the output. So lets change the code on docker volumes:

in my output-1: i have Hollywood movie like avengers, now i am changing to Tollywood movies like RRR, PUSHPA & KGF

vim /var/lib/docker/volumes/paytm_movie_volume/_data/index.html

change the menu

I have modified the code on volumes, now we can see the changes on production.


Networks in Compose File:

When we execute the compose file, it will create a network by default for our services.But if you wish to restrict the connection between the services we have to maintain each network for each services individually.

---
version: "3"
services:
  movie:
    container_name: movie-container
    build: ./movie-tickets
    ports:
      - "8081:80"
    volumes:
      - movie_volume:/usr/share/nginx/html:ro
    networks:
      - movie_network

  bus:
    container_name: bus-container
    build: ./bus-tickets
    ports:
      - "8082:80"
    volumes:
      - bus_volume:/usr/share/nginx/html:ro
    networks:
      - bus_network

  train:
    container_name: train-container
    build: ./train-tickets
    ports:
      - "8083:80"
    volumes:
      - train_volume:/usr/share/nginx/html:ro
    networks:
      - train_network

#declare the volumes that you want to create here        
volumes:
  movie_volume:
  bus_volume:
  train_volume:

#declare the networks that you want to create here
networks:
  movie_network:
    driver: bridge
  bus_network:
    driver: bridge
  train_network:
    driver: bridge

Lets use docker-compose up -d command to recreate the containers with their own networks.

By using the above command, old containers will gets deleted and new containers will be created with networks.

lets check the networks

docker network ls

you can inspect each container to check the networking configurations.


ENV values in Compose File:

There are several ways you can use environment variables in a Docker Compose file, allowing for flexibility in configuration. Here are some common methods:

1. Using .env File

create a hidden file called .env and pass the variables inside the file, now compose fill will automatically get the variables from this .env file

vim .env

add this data

DB_HOST=mysqldb
DB_PORT=3306

Now lets add the values from .env file to compose file

---
version: "3"
services:
  movie:
    container_name: movie-container
    build: ./movie-tickets
    ports:
      - "8081:80"
    volumes:
      - movie_volume:/usr/share/nginx/html:ro
    networks:
      - movie_network
    environment:
      - DB_SERVER=${DB_HOST}
      - DATABASE_PORT=${DB_PORT}

Lets use docker-compose up -d command to recreate the container

Now go to movie-container and check the environment variables inside the container

docker exec -it movie-container bash

use printenv command to see the environment variables

we can see the DATABASE_PORT=3306 and DB_SERVER=localhost. compose file automatically fetch the values from .env file and assign the values into the container.

2. Defining Environment Variables Directly in the docker-compose.yml

You can specify environment variables directly in the environment section of the docker-compose.yml file.

open your compose file and add the variables

---
version: "3"
services:
  movie:
    container_name: movie-container
    build: ./movie-tickets
    ports:
      - "8081:80"
    volumes:
      - movie_volume:/usr/share/nginx/html:ro
    networks:
      - movie_network
    environment:
      - DB_ENDPOINT=https://mysqldb..com
      - DB_USER=root

In the above file i directly assigned the values on compose file.

3. Using Shell Environment Variables

If you have environment variables set in your shell (e.g., in your terminal session), you can reference those in the docker-compose.yml file.

To use this, you need to have the environment variables already set in your docker host:

on your docker host perform this commands to export variables

export DB_NAME=mustafa
export DB_PORT=3306
---
version: "3"
services:
  movie:
    container_name: movie-container
    build: ./movie-tickets
    ports:
      - "8081:80"
    volumes:
      - movie_volume:/usr/share/nginx/html:ro
    networks:
      - movie_network
    environment:
      - DB_NAME=${DB_NAME}
      - DB_PORT=${DB_PORT}

Lets use docker-compose up -d command to recreate the container.

containers inside will hold the values DB_NAME=mustafa & DB_PORT=3306 . Now this time compose file get the values from docker host which we export.

In my next blog i am going to revel with real time application deployments using docker compose and also nginx reverse proxy and scaling using docker compose.

Conclusion

Docker Compose simplifies managing multi-container applications with declarative configuration, automated networking, and easy scaling. It is an essential tool for DevOps engineers, helping streamline deployments in development and test environments.

By mastering Docker Compose, you can efficiently manage containerized applications and prepare for real-world DevOps challenges.

Give me your heart 💖

If you found this blog helpful for your interviews or in learning Docker troubleshooting, please hit a heart for 10 times and drop a comment! Your support motivates me to create more content on DevOps and related topics. ❤️

If you'd like to connect or discuss more on this topic, feel free to reach out on LinkedIn.
Linkedin: linkedin.com/in/musta-shaik