Docker Compose

The basic idea behind Docker Compose is to save you a lot of typing when creating, configuring, stopping, rebuilding or inspecting your containers. We create a docker-compose,yml file to define our docker resources, such as containers (called services in this context), networks and volumes. Then we use a single command to spin everything up or tear it all down.

Using Docker Compose is good for development or maybe staging, but for production there are better alternatives.

Installing Docker Compose

If you installed Docker Desktop/Toolbox for either Windows or Mac, you already have Docker Compose. If you are on a Linux machine, you will need to install Docker Compose using the instructions here.

Creating docker-compose.yml

You can define all kinds of configurations for your services, such as builds, environments, images, networks, ports, volumes.

At the root of the app project, create a file named docker-compose.yml.

version: "3.8"

services:  # aka containers
  app:   # name of your container
    image: node:12-alpine
    command: sh -c "yarn install && yarn run dev"
    ports:
      - 3000:3000
    working_dir: /app
    volumes:
      - ./:/app
    environment:
      MYSQL_HOST: mysql   # we can use mysql as hostname here because we defined 'mysql' as a service
      MYSQL_USER: root
      MYSQL_PASSWORD: secret
      MYSQL_DB: todos

  mysql:
    image: mysql:5.7
    volumes:
      - todo-mysql-data:/var/lib/mysql
    environment: 
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: todos

volumes:
  todo-mysql-data:

We can pick any name for the service. The name will automatically become a network alias, which will be useful when defining our MySQL service: See how we use mysql as a value for MYSQL_HOST ? That’s possible because we defined mysql as service name.

By default, Docker Compose automatically creates a network specifically for the application stack, which is why we didn’t define one in the compose file explicitly.

You can use environment variables in docker-compose.yml and forward a environment file to your containers/services: If your are using Linux then you first have to export APP_ENV=development and then:

myservice:
  env_file:
    - ./path/to/app.${APP_ENV}.env

Building images

# Build or rebuild services defined in docker-compose.yml
docker-compose build

# Build specific service
docker-compose build my-service

Do I need a Dockerfile when I use docker-compose.yml?

Docker Compose lets you choose between the two options:

  • build the container from a specified image (without the need of a Dockerfile):
services:
  example:
    image: your/imagename
  • build the container out of a Dockerfile:
services:
  example:
    build: 
      context: path/to/Dockerfile/dir
      dockerfile: Dockerfile #here you specify the name of your Dockerfile file

Starting and stopping your services with Docker Compose

# Start services (detached)
docker-compose up -d

# Only rebuild 'node' image, not its dependencies
docker-compose up --no-deps node
# Stop and remove services
docker-compose down

# Stop but do not remove services
docker-compose stop

# Stop and remove services and remove images and volumes
docker-compose down --rmi all --volumes

# Remove services
docker-compose rm

By default, named volumes in your compose file are NOT removed when running docker-compose down. If you want to remove the volumes, you will need to add the --volumes flag.

Inspecting services

# show running services
docker-compose ps

# show all services
docker-compose ps -a

# You’ll see the logs from each of the services interleaved into a single stream
docker-compose logs -f

# To see the logs of a single service run
docker-compose logs -f my-service

Waiting for other containers to start up

When the app is starting up, it actually sits and waits for MySQL to be up and ready before trying to connect to it. Docker doesn’t have any built-in support to wait for another container to be fully up, running, and ready before starting another container. For Node-based projects, you can use the wait-port dependency. Similar projects exist for other languages/frameworks.

Migrating from Docker Compose to Kubernetes

Two options: Compose on Kubernetes (Part of Docker Desktop) and Kompose. After installation of Kompose you can simply run kompose convert in your project root folder and it will create Kubernetes YAML files for you.

About Author

Mathias Bothe Contact me

I am Mathias, born 38 years ago in Heidelberg, Germany. Today I am living in Munich and Stockholm. I am a passionate IT freelancer with more than 14 years experience in programming, especially in developing web based applications for companies that range from small startups to the big players out there. I am founder of bosy.com, creator of the security service platform BosyProtect© and initiator of several other software projects.