Difficulty: intermediate
Estimated Time: 60-75 minutes

BoxBoat Logo

Docker Compose

Docker Compose is an extremely important tool for local development. It lets you easily bring up your application with a single file providing specification.

The docker-compose.yaml file is also used with Docker Swarm, which lets you deploy your applications across a distributed cluster with ease.

Please email feedback to: [email protected]

Docker Compose is one of the most valuable tools we have in our Docker toolkit. It lets us easily define a multi-container application and specify configuration, in a more repeatable fashion than with pure docker container run on the CLI.

Next, we'll go through a series of debugging challenges.

Docker Compose

Step 1 of 4

YAML Refresher

YAML Refresher

YAML - YAML Ain't Markup Language, is the primary specification we'll use for Docker Compose. In particular, our docker-compose.yaml files will be written in YAML.

YAML is very easy to read, but extremely difficult to write without errors. Case in point, I will make errors during this training, and I've been using it since 2014.

Types

YAML has 2 types of objects: Maps and Lists

Maps

Maps let you associate name-value pairs

version: "3.2"

In this example, we have a single map. The key for our map is version, and its value is 3.2.

Here is what our YAML maps look like in JSON:

{
    "version": "3.2"
}

We can also have "values" in a Map be another Map:

version: "3.2"

services:
  web:
    image: nginx

Here, services is a key, and its value is a map. That other map has a key called web, with a value that is another map. That final map has a key of image, and a value of nginx.

In summary, this YAML specifies a Docker Service called web, that is based off the image nginx.

Here's what it looks like in JSON:

{
    "version": "3.2",
    "services": {
        "web": {
            "image": "nginx"
        }
    }
}

Spacing is important, and you cannot use tabs.

Lists

YAML Lists are a sequence of objects

ports:
  - "6443:443"
  - "10080:80"

In JSON, our data would look like:

{
    "ports": [
        "6443:443",
        "10080:80"
    ]
}

The general structure of Docker-compose files typically contains a bunch of maps, with specific configuration options defined by additional maps or lists.

version: "3.2"

services:
  web:
    image: nginx
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "8080:80"
    command: ["nginx-debug", "-g", "daemon off;"]

  backend:
    image: httpd
    ports:
      - "80"
      - "443"

Here's what it looks like when converted to JSON:

{
    "version": "3.2",
    "services": {
        "web": {
            "image": "nginx",
            "volumes": [
                "./nginx.conf:/etc/nginx/nginx.conf:ro"
            ],
            "ports": [
                "8080:80"
            ],
            "command": [
                "nginx-debug",
                "-g",
                "daemon off;"
            ]
        },
        "backend": {
            "image": "httpd",
            "ports": [
                "80",
                "443"
            ]
        }
    }
}

We can do things a bit more complex. Let's move to an actual application.