What is Docker Compose? Installation and Volumes with Examples

By Sruthy

By Sruthy

Sruthy, with her 10+ years of experience, is a dynamic professional who seamlessly blends her creative soul with technical prowess. With a Technical Degree in Graphics Design and Communications and a Bachelor’s Degree in Electronics and Communication, she brings a unique combination of artistic flair…

Learn about our editorial policies.
Updated April 1, 2024

Get to know what is docker compose and explore all about Docker Compose Volumes to learn how to manage multiple containers on a single host with examples:

Docker is an open-source platform used to build, test, and deploy applications. Docker helps to package the software into units called containers which contain everything that software needs like the code, OS libraries, runtimes, etc. Docker can deploy applications to any environment.

Docker Image is a read-only template that contains instructions to create a Docker container. You can use Docker images for yourself or publicly share them with other users using Docker. Dockerfile is a basic building block to create images.

Getting Started With Docker Compose

Introduction to Docker Compose

Docker Container is a run-time image instance. Docker images are only templates and cannot be started or run. A container is a running image. Think of containers as an object and images as a class.

DockerHub is a cloud-based repository that helps to create, store, and deploy images. It also provides access to thousands of open-source public images. It is also called an open-source container registry.

Docker Compose: While Docker is used to manage individual containers, Docker Compose is used to manage and run multi-container applications. Usually, an application may have many containers comprising a single service (Container Configuration), it can be tedious and manage these containers individually.

With Docker Compose, you can speed up and centrally manage the deployment of many containers. If an application needs to be microservice-based, then Docker Compose is the tool wherein each service is managed in separate containers.

So rather than managing multiple services in one large container, Docker Compose helps to split the services into individual containers that can be managed. The configuration for managing all the containers is defined in one single YAML file docker-compose.yml and starts all the containers using one single command.

Docker Compose

In this article, we will look at the usage of Docker Compose and examples of managing multiple containers on a single host.

Docker Compose Use Case and Benefits

Docker Compose, as we have seen in the introduction section, is a tool that helps in running multiple services simultaneously. All the services in compose are defined in a YAML file, wherein we can spin them up and bring them down with one command.

To illustrate, let’s consider any e-commerce site today. As a user, you normally do multiple activities like login/logout of your account, browsing the product catalog, adding to the cart, checkout, etc. In the backend, there would be different databases for these different services.

So, each of these here can be considered as a microservice. Each of these services runs in a different container and you should be able to connect them. Docker Compose helps to connect these different containers into a single service.

Benefits:

  • Deployment on a single host: Run the application on a single piece of hardware
  • Simple configuration: Using YAML files
  • Secured internal communication: Through the creation of networks that are shared by all services
  • Reduce time: To perform tasks
  • Highly secured: As all containers are isolated, reducing the threat
  • Efficient CI/CD support

Installation of Docker-Compose on Ubuntu

Pre-Requisites: Docker compose needs a docker engine to be installed so the docker engine will have to be installed on your OS. In this case, it would be Ubuntu.

Further Reading => Podman – Best Alternative to Docker

Follow the steps as shown below to install Docker Compose v2.18.1 which is as of now the latest version.

#1) Download Docker Compose

sudo curl -L https://github.com/docker/compose/releases/download/v2.18.1/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose

#2) Apply Permission to the Binary

sudo chmod +x /usr/local/bin/docker-compose

Note: Every compose command starts with docker-compose

#3) Test the Installation

docker-compose –version

Test the installation

You can download and install the latest version from Releases · docker/compose (github.com).

#4) Usage of Docker Compose

Once you’ve downloaded and installed Docker Compose using the steps mentioned above, you can start using it as follows:

  • Create a Dockerfile to define the application environment so it can be reused.
  • Define the services for your application in the docker-compose.yml file.
  • Use the command docker-compose up to start all services.
  • Use the command docker-compose down to stop all services.

Use the ‘docker-compose <Command> –help ‘ to get more information on the arguments.

Also Read =>> Use the MySQL Docker container with example

First Docker-Compose Files and Commands

Let’s start by creating our first Docker Compose YAML file. The YAML files are normally stored in a GitHub repository.

version: '3.8'

services:
  web:
    image: httpd
    ports:
      - 8080:80

  database:
    image: redis

Let’s understand this step by step. Also, note in the above YAML file indentation is very important.

  • version: This specifies the version of Docker Compose. At this point in writing the document, the current version is 3.8. All the versions of the Docker Compose that support the specific docker releases can be found @ Compose file version 3 reference | Docker Documentation
  • services: This section specifies the multiple containers that will be created. In the above example there are 2 services, web and database
  • ports: To map the container port to the host machine. Ensure ports are opened in the security group of your EC2 VM
  • image: If there is no Dockerfile, we can specify to run the service from a pre-built image

#1) Check the validity of the docker-compose.yml file

Run the command

docker-compose config

Check validity of the docker-compose.yml

#2) Start the services (up Command)

We will need to use the below command to start or restart all the services as defined in the docker-compose.yml file. The command will help to create the containers specified in the docker-compose.yml file. To run the command, you should be in the directory where the docker-compose.yml file is present.

docker-compose up -d

The -d option will run the containers in the background. ‘docker ps’ command will show the newly created containers.

Start the services (up Command)

Since httpd image is running in a container, we can check using the EC2 VM public IP.

It Works

docker-compose ps

Start the services (up Command)

This command will list all containers as defined in the docker-compose.yml file. They will either be running or stopped. In the above example, if your application requires httpd server and redis database, then both the containers can be run as a single service instead of starting them separately.

#3) Shutdown the Services

The below command will stop and clean up the containers and networks.

docker-compose down

#4) Stop the Services

The below command will only stop the running containers from the specified services but will not remove the containers

docker-compose stop

#5) Start the Services

The below command will restart the containers of the specified services which were stopped previously

docker-compose start

#6) Build the Images

The below command will build the images or even rebuild the images as mentioned in the docker-compose.yml file. Once the image is built, you can then create containers for each service mentioned in the compose file using the docker-compose up command

#7) Create and run the containers

The below command will create the containers from the images built for the services as mentioned in the docker compose file. It will run on-off tasks and requires a service name that needs to be started.

docker-compose run database

docker-compose run web

The above command is similar to the ‘docker run’ command.

Docker-Compose Build

In this section, we will look at an example of Docker Compose Build. The Docker Compose provides a sub-command to build the images, which is ‘docker-compose build’. The command will go through all the services and build the images which are in the ‘build’ section.

Example #1: Create a Dockerfile in a webapp directory and add the content as shown.

vi webapp/Dockerfile

FROM httpd

COPY index.html /var/www/html

Create a Dockerfile in a webapp directory

docker-compose.yml file in the current directory

version: "3.8"
services:
  web:
    build: ./webapp
    ports:
            - "9000:80"

  redis:
    image: redis

build section above refers to the location of Dockerfile.

build section above refers to the location of Dockerfile

Build the webapp image: Build the image using the ‘docker-compose build’ command. For the web app, it will use the webapp/Dockerfile

docker-compose build

Build the webapp image

Start the containers: Start the containers using the ‘docker-compose up -d’ command

docker-compose up -d

Start the containers

Update content in the HTML file

echo “Bangalore, Karnataka” >> webapp/index.html

Update content in the HTML file

Rebuild the web container and restart the containers.

docker-compose build

docker-compose up -d

Rebuild the web container and restart the containers

If you see the output, the web container alone has been recreated and started as there was a new build for the image. The database container is unchanged.

Example #2: In this section, we will look at creating two docker containers. One will be the web container and the other will be the database container. The below-mentioned service uses an image built from Dockerfile which will deploy a Java Maven WAR file to Tomcat.

Dockerfile

FROM tomcat:latest

MAINTAINER Niranjan V

ADD SampleWebApp.war /usr/local/tomcat/webapps/

EXPOSE 8080

CMD [“catalina.sh”, “run”]

docker-compose.yml file

version: '3.8'
services:
   web:
       build:  .
       ports:
                -  9000:8080
    database: 
  image: redis

build: specifies the path to Dockerfile which represents the current directory in which the docker-compose.yml file is present.

List Images: The below command will list images built using the docker-compose.yml file

docker-compose images

List images

Let’s start the containers now

docker-compose up -d

start the containers now

Running ‘docker-compose ps ‘ will now show both the containers running as per the services defined in the ‘docker-compose.yml’ file

Running ‘docker-compose ps'

The application can be tested by using the URL http://<EC2VM-IP>:9000/SampleWebApp

Docker Compose Volumes

As we know that in Docker data is stored inside the container. Once the container is removed, data will also be lost. So, volumes in docker help to preserve the data even if containers are removed. The volumes can also be shared across different containers.

If you want to save your data locally on your host machine or want to share data from your Docker host to the Docker container e.g., conf files or any other source code, then this type of volume is called a Bind mount.

If you want Docker to manage the data and the mount points, then this type of volume is called Volume mount.

Docker compose allows you to configure both types of mount.

E.g., Bind mount volume

volumes:

./website /usr/local/apache2/htdocs

In the above the absolute path (./website sub-folder in the current folder) is mounted in to the container.

E.g. Volume mount

services
   db: 
         image: mysql
         volumes:
-	My_SQL_Data:/var/lib/mysql
volumes:
          My_SQL_Data

If a source is present before the (COLON): and it’s not an absolute path, then Docker Compose assumes you’re referring to a named volume. This volume needs to be declared in the top-level volume’s key declaration. Docker manages this volume.

The top-level volumes key always declares volumes, they never are bind mount. Bind mounts don’t have a name and they cannot be named. In docker you normally use the ‘docker volume create’ command.

Example #1: Bind Mount – Docker Compose Example

In the example let’s mount the websites folder to /usr/local/apache2/htdocs folder in the container.

Bind Mount example with docker compose

docker-compose.yml

version: "3.8"
services:
  web:
    image: httpd
    ports:
        -  9000:80
    volumes:
        - ./websites:/usr/local/apache2/htdocs

Start the services and check inside the container

docker-compose up -d

docker exec -it <Container-Name> bash

Start the services and check inside the container

Example #2: Bind mount with MySQL data

In this example, we will use the mysql image with bind mount where the DB data will persist even if the container is removed.

Bind mount with MySQL data

docker-compose.yml file

version: '3.8'
services:
  DB:
    image: mysql
    environment:
      - MYSQL_ROOT_PASSWORD=alpha123
      - MYSQL_USER=niranjan
      - MYSQL_PASSWORD=niranjan
    volumes:
      -  ./db_vol:/var/lib/mysql
    ports:
      - 3306:3306

Start the services, log in to MySQL, and create a database

docker-compose up -d

docker exec -it <Container-Name> bash

Login to MySQL using the below command:

mysql -u root -p

Start the services, login to mysql and create a database

Create a database inside the MySQL container

Create database inside the mysql container

Shutdown the services

Exit the container and shut the services

docker-compose down

Shutdown the services

The container is removed but the data is persisted. Let’s now start the services again and check in the NEW container created.

docker-compose up -d

NEW container

Get inside the container and login to mysql

The database created earlier ‘niranjandb’ is listed in this new container as well.

login to mysql

Networking in Docker Compose

Networks are configured for complete isolation of containers. So, applications that work together can be secure. Once Docker is installed, it configures 3 types of networks: None, Host, and Bridge. The none and host network cannot be removed. They are part of the network stack and have no external interfaces.

Suggested Read =>> Jenkins Integration with Docker, Docker-Compose, and Docker Swarm

Bridge network can be configured and this type of network creates its IP Subnet and gateway. All of the containers belonging to this network are part of the subnet and communication between the containers part of this network happens through IP address. This is also a private network.

Networking in Docker Compose

Create Bridge Network in Docker

Let’s create a new docker custom bridge network and check connectivity between containers of the same bridge.

docker network create –driver bridge ctr-bridge1

Run 2 containers as part of the same bridge network ctr-bridge1.

docker run -it –network ctr-bridge1 –name ctr-c1 busybox

docker run -it –network ctr-bridge1 –name ctr-c2 busybox

Attach terminal’s std input, output to running container 2

docker attach ctr-c2

ping ctr-c1

Create Bridge Network in Docker

Since both containers are part of the same subnet in the bridge network created, I can ping container 1 from within container 2.

Let’s now create the same in Docker Compose.

docker-compose.yml file

You can specify our custom networks with the network key as shown below in the docker-compose.yml file. Each service can specify which network to connect to.

version: "3.8"
services:
  app:
    image: httpd
    networks:
      - ctr-bridge1

  db:
    image: redis
    networks:
      - ctr-bridge1

networks:
    ctr-bridge1:
      name: ctr-bridge1

Both services are part of the same bridge network.

Let’s start the services.

docker-compose up -d

start the services

Look at the subnet details of the bridge and containers.

Look at the subnet details of the bridge and containers

docker inspect dcnetexample-app-1

Look at the IPV4 address which is part of the same subnet

Look at the IPV4 address which is part of the same subnet

Docker Compose Environment Variables

In this section, we will look at how to use environment variables to define configuration values which will help to be organized.

Environments should not be used to pass sensitive information such as passwords into the containers.

We will look at how environment variables can be set through the compose file and CLI.

Create a .env file

The .env file would be useful if there are multiple environment variables to be stored. Create the .env and the docker-compose.yml file in the same directory.

Create a .env file
Create a .env file - Docker Compose

Validate the docker-compose file

docker-compose config

Validate the docker-compose file

If the .env file is not in the same directory as with docker-compose.yml file then you can specify the –file or –env-file option in the CLI.

docker-compose –env-file ./envfile/.env up

specify the file - Docker Compose

docker-compose –env-file ./envfile/.env config

specify the --file  or --env-file  option in the CLI.

Use environment attribute

web:

environment:

– VERSION=20-alpine3.17

Use env_file attribute

web:

env_file:

– variables.env

Docker Compose and Angular Example with NGINX Image

In this section, we will look at creating and running an Angular example on NGNIX web server using Docker Compose.

Step #1: As a pre-requisite, we will need to install nodejs, npm, and angular cli. Use the commands as shown below to install the same.

sudo apt install nodejs

sudo apt install npm

sudo npm install -g @angular/cli@latest

Step #2: Create a new angular application

ng new angular-demo-app

Create a new angular application  - Docker Compose

Dockerfile

FROM node:18.16.0 as build
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app/package.json
COPY . /usr/src/app
RUN npm install -g @angular/cli
RUN npm install --force
RUN ng build
FROM nginx
COPY --from=build /usr/src/app/dist/angular-demo-app/.   /usr/share/nginx/html

docker-compose.yml file

version: "3.8"
services:
  client:
     build: .
     ports:
       -  9000:80

Start the services:

docker-compose up -d

Start the Services

Test the application by entering the URL http://<EC2VM-IP>:9000

Test the application - Docker Compose

Also Read =>> Docker Selenium Tutorial

Docker Compose and MySQL Using phpMyAdmin Example

In this section we will look to launch mysql container along with phpMyAdmin container which is a web interface for managing databases. I am extending the docker-compose.yml file created in the previous section to add the phpMyAdmin service.

docker-compose.yml file

version: '3.8'
services:
  DB:
    image: mysql
    environment:
      - MYSQL_ROOT_PASSWORD=alpha123
      - MYSQL_DATABASE=niranjandb
      - MYSQL_USER=niranjan
      - MYSQL_PASSWORD=niranjan
    volumes:
      - ./db_vol:/var/lib/mysql
    ports:
      - 3306:3306

  phpmyadmin:
    depends_on:
      - DB
    image: phpmyadmin/phpmyadmin
    ports:
      - 9000:80
    environment:
      PMA_HOST: DB
      MYSQL_ROOT_PASSWORD: alpha123

Start the Services:

docker-compose up -d

Start the services - Docker Compose

Launch phpMyAdmin in web browser:

Launch using the URL http://<EC2VM-IP>:9000 and login as root

Launch phpMyAdmin - Docker Compose

Once you log in you can then create databases, tables, columns, etc.

create databases, table, columns etc

JSON File With Docker Compose

JSON file can be used with Docker Compose and is valid. However, the YAML file is a superset of JSON format and is preferred as it is more readable. Use the JSON file with the following command in Docker Compose.

Examples of JSON format with Docker Compose can be found @ Lab #24: Use JSON instead of YAML compose file in Docker? | dockerlabs (collabnix.com)

docker-compose -f docker-compose.json up -d

Frequently Asked Questions

1. What is Docker Compose?

Docker Compose is a tool for defining and running multi-container applications of Docker. It uses a YAML file to configure the services of the applications.

2. What are 3 main steps of Docker Compose?

The 3 main steps are as below
Define the apps environment in Dockerfile
Define the services of your application in docker-compose.yml file
Run docker-compose up to start and run the entire application

3. What is the difference between Up, Run, and Start?

These 3 commands in docker compose have different purposes:
docker-compose up: This command builds, start/restart all services and attaches a container for each service defined in the YAML file.
docker-compose run: This command will create the containers from the images built for the services as mentioned in the docker compose file. It will run on-off tasks and requires a service name which needs to be started.
docker-compose start: This command is used to restart the containers that were created previously but was stopped.

4. What is a docker compose file used for?

A docker compose file defines the services, networks, and volumes needed for your application

5. Can I use a JSON file instead of YAML?

Yes JSON files can be used

6. Can I control the startup order?

By using the “depends_on” command in docker compose file, it is possible to change the startup order of the containers and give priority to the containers that are needed to start.

Conclusion

In this article, we have seen how Docker Compose can be used to run your entire application or multiple containers on a single host which is possible using a single docker-compose.yml file. It helps to orchestrate multiple containers that work together.

Docker Compose reduces time to perform tasks and security wise all the containers are isolated from each other.

To move on to the next level of Docker knowledge to run multiple containers on multiple hosts and manage them in a cluster you will use Docker Swarm.

Was this helpful?

Thanks for your feedback!

Leave a Comment