Contents

Docker Compose

Website Visitors:

What is Docker Compose?

Docker Compose is a tool for defining and running multi-container Docker applications. It allows you to create a YAML file that defines the services, networks, and volumes for your application, and then uses that file to create and manage the containers. Docker Compose is a great way to simplify the process of building, shipping, and running multi-container applications.

Version 1 vs Version 2 vs Version 3

Docker Compose has undergone several major version changes, each introducing new features and improvements. Here’s a brief overview of each version:

  • Version 1: The original version of Docker Compose, which introduced the basic concept of defining services and containers in a YAML file. In version 1 docker compose attaches all containers it runs to a default bridged network. Then it links them using links option.
  • Version 2: Introduced in 2016, Version 2 added support for Docker networks, volumes, and dependencies between services. Automatically creates a dedicated bridged network for this application and then attaches all containers to this new network. All containers are then communicated using each other’s service name. So you dont need to use links in version 2 of docker compose. Also introduces depends_on parameter so that you can start containers in a sequence, making sure a specific container is started before some other container is started.
  • Version 3: The latest version of Docker Compose, introduced in 2019, which adds support for Docker Swarm, Kubernetes, and other orchestration tools.

You should specify the docker version from version 2 and up at top of file. This is how docker knows which version of docker compose you’re using.

Writing a Docker Compose File

A Docker Compose file is a YAML file that defines the services, networks, and volumes for your application. The file typically has a .yml or .yaml extension. Here’s an example of a simple Docker Compose file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
version: '3'
services:
  web:
    build: .
    ports:
      - "80:80"
    depends_on:
      - db
    environment:
      - DATABASE_URL=postgres://user:password@db:5432/database
  db:
    image: postgres
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=database
    volumes:
      - db-data:/var/lib/postgresql/data

volumes:
  db-data:

Let’s break down the Docker Compose file syntax using the provided script:

Version

1
version: '3'

The first line specifies the version of the Docker Compose file format. In this case, it’s version 3.

Services

1
2
3
4
5
services:
  web:
    ...
  db:
    ...

The services keyword defines a list of services. In this case, we have two services: web and db.

Web Service

1
2
3
4
5
6
7
8
web:
  build: .
  ports:
    - "80:80"
  depends_on:
    - db
  environment:
    - DATABASE_URL=postgres://user:password@db:5432/database

The web service has four settings:

  • build: .: This tells Docker Compose to build the Docker image for the web service using the current directory (i.e., the directory containing the Dockerfile) as the build context.
  • ports: - "80:80": This maps port 80 on the host machine to port 80 in the container. This allows you to access the web service from outside the container.
  • depends_on: - db: This specifies that the web service depends on the db service. This means that the web service will only start once the db service is up and running.
  • environment: - DATABASE_URL=postgres://user:password@db:5432/database: This sets an environment variable DATABASE_URL inside the container with the specified value. This variable can be used by the application running inside the container.

DB Service

1
2
3
4
5
6
7
8
db:
  image: postgres
  environment:
    - POSTGRES_USER=user
    - POSTGRES_PASSWORD=password
    - POSTGRES_DB=database
  volumes:
    - db-data:/var/lib/postgresql/data

The db service has four settings:

  • image: postgres: This tells Docker Compose to use the official Postgres image for the db service.
  • environment: ...: This sets three environment variables inside the container: POSTGRES_USER, POSTGRES_PASSWORD, and POSTGRES_DB. These variables are used to configure the Postgres database.
  • volumes: - db-data:/var/lib/postgresql/data: This mounts a volume named db-data to the /var/lib/postgresql/data directory inside the container. This allows the database data to be persisted even if the container is restarted or deleted.

Volumes

1
2
volumes:
  db-data:

The volumes keyword defines a list of volumes. In this case, we have one volume named db-data. This volume is used by the db service to persist data.

In summary, this Docker Compose file defines two services: web and db. The web service depends on the db service and uses environment variables to connect to the database. The db service uses an official Postgres image and persists data using a volume named db-data.

Docker Compose File Syntax

Here is a breakdown of the Docker Compose file syntax:

Version

The first line of the file specifies the version of the Docker Compose file format:

1
version: '3'

Services

The services keyword defines a list of services:

1
2
3
4
5
services:
  service1:
    ...
  service2:
    ...

Each service is defined as a key-value pair, where the key is the service name and the value is a dictionary of service settings.

Service Settings

Here are some common service settings:

  • build: specifies the build context for the service:
1
build: .
  • image: specifies the Docker image to use for the service:
1
image: postgres
  • ports: maps host ports to container ports:
1
2
ports:
  - "80:80"
  • depends_on: specifies dependencies between services:
1
2
depends_on:
  - db
  • environment: sets environment variables for the service:
1
2
environment:
  - DATABASE_URL=postgres://user:password@db:5432/database
  • volumes: mounts volumes for persistent data storage:
1
2
volumes:
  - db-data:/var/lib/postgresql/data
  • command: specifies a command to run when the container starts:
1
command: ["bash", "-c", "echo 'Hello World!'"]
  • entrypoint: specifies the entry point for the service:
1
entrypoint: ["bash", "-c"]
  • expose: exposes ports from the service to other services:
1
2
expose:
  - "5432"
  • links: links containers together (older format):
1
2
links:
  - db
  • restart: specifies the restart policy for the service:
1
restart: always
  • networks: specifies the networks for the service:
1
2
networks:
  - mynet

Volumes

The volumes keyword defines a list of volumes:

1
2
3
4
5
6
7
volumes:
  db-data:
    driver: local
    driver_opts:
      type: none
      device: /var/lib/postgresql/data
      o: bind

Each volume is defined as a key-value pair, where the key is the volume name and the value is a dictionary of volume settings.

Networks

The networks keyword defines a list of networks:

1
2
3
networks:
  mynet:
    driver: bridge

Each network is defined as a key-value pair, where the key is the network name and the value is a dictionary of network settings.

Other Keywords

Here are some other keywords you can use in a Docker Compose file:

  • x-: used to define custom configuration options:
1
x-debug: true
  • extends: used to extend a service from another file:
1
2
3
extends:
  file: common.yml
  service: web

Note that this is not an exhaustive list, and you can find more information about each keyword in the Docker Compose documentation.

Docker Compose Keywords

The Docker Compose file syntax is based on YAML, with a few specific keywords and structures. Here are some of the most common keywords:

  • version: Specifies the version of the Docker Compose file format being used (e.g., ‘3’).
  • services: Defines the containers that make up your application. Each service can have its own configuration, including image, ports, environment variables, volumes, etc.
  • networks: Defines custom networks for your services to communicate with each other.
  • volumes: Defines named volumes for persisting data.
  • environment: Sets environment variables for a service.
  • ports: Maps container ports to host machine ports.
  • image: Specifies the Docker image to use for the service.
  • build: Specifies the build context for building a custom Docker image.
  • depends_on: Defines dependencies between services.
  • restart: Specifies the restart policy for the service.
  • links: (Deprecated) Establishes links between containers for networking.

Here are some additional keywords you can use in a Docker Compose file:

  • command: specifies a command to run when the container starts
  • entrypoint: specifies the entry point for a service
  • expose: exposes ports from a service to other services
  • links: links containers together
  • networks: specifies the networks for a service
  • restart: specifies the restart policy for a service

Docker Compose Commands

Here are some common Docker Compose commands:

docker-compose up

Starts the containers defined in the Docker Compose file:

1
2
3
4
5
6
7
$ docker-compose up
Creating network "myapp_default" with the default driver
Creating myapp_db_1 ... done
Creating myapp_web_1 ... done
Attaching to myapp_db_1, myapp_web_1
db_1  | PostgreSQL init process complete; ready for start up.
web_1 | Listening on port 80...

In this example, Docker Compose starts two containers: myapp_db_1 and myapp_web_1. The db container is started first, and then the web container is started once the db container is up and running.

docker-compose start

Starts the containers in detached mode:

1
2
3
$ docker-compose start
Starting myapp_db_1 ... done
Starting myapp_web_1 ... done

In this example, Docker Compose starts the containers in detached mode, which means that the containers run in the background and do not attach to the terminal.

docker-compose stop

Stops the containers:

1
2
3
$ docker-compose stop
Stopping myapp_web_1 ... done
Stopping myapp_db_1 ... done

In this example, Docker Compose stops both containers.

docker-compose restart

Restarts the containers:

1
2
3
$ docker-compose restart
Restarting myapp_web_1 ... done
Restarting myapp_db_1 ... done

In this example, Docker Compose restarts both containers.

docker-compose ps

Lists the running containers:

1
2
3
4
5
$ docker-compose ps
      Name                    Command               State          Ports
--------------------------------------------------------------------------------
myapp_db_1       docker-entrypoint.sh postgres    Up      5432/tcp
myapp_web_1    python app.py            Up      0.0.0.0:80->80/tcp

In this example, Docker Compose lists the running containers, including their names, commands, states, and ports.

docker-compose exec

Executes a command in a running container:

1
2
$ docker-compose exec web bash
root@myapp_web_1:/app#

In this example, Docker Compose executes the bash command in the web container, allowing you to interact with the container’s shell.

Note: You can also use docker-compose exec -it web bash to attach to the container’s terminal and interact with it.

Linking Containers

Linking containers allows you to connect containers together, so that they can communicate with each other. There are two ways to link containers in Docker Compose:

  • Links (older format): uses the links keyword to link containers together. For example:
1
2
3
4
5
6
7
8
version: '2'
services:
  web:
    build: .
    links:
      - db
  db:
    image: postgres
  • Depends On (newer format): uses the depends_on keyword to specify dependencies between services. For example:
1
2
3
4
5
6
7
8
version: '3'
services:
  web:
    build: .
    depends_on:
      - db
  db:
    image: postgres

In both cases, the web service is linked to the db service, allowing them to communicate with each other.

I hope this article has given you a good introduction to Docker Compose! Let me know if you have any questions or need further clarification on any of the topics.

Your inbox needs more DevOps articles.

Subscribe to get our latest content by email.