Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Docker Compose Cheatsheet

This is a work in progress and as more things come up, I will add them.

Related Posts

Commands

Start all the containers/services using docker-compose

docker-compose up

Specify a custom filepath for your docker-compose file (it assumes docker-compose.yml in your current directory by default)

docker-compose -f custom-docker-compose.yml up

Apply multiple compose files (changes in latter)

docker-compose -f docker-compose.yml docker-compose-production.yml

Re-deploy just one service. Particularly useful after a rebuild.

docker-compose up $SERVICE_NAME

Sample Configuration File

This is a sample docker-compose.yml configuration that should hopefully help get you started. It is easier to remove things than to find what to add.

version: "3"

networks:
  backend:
    driver: bridge

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: app
    image: ${REGISTRY}/my-project-name
    restart: always
    ports:
      - "80:80"
      - "443:443"
    depends_on:
        - db
    networks:
      - backend
    env_file:
      - ./.env

  db:
    image: mariadb:10.5
    container_name: db
    restart: always
    networks:
        backend
    volumes:
      - mysql-data:/var/lib/mysql
    env_file:
      - ./.env

volumes:
  mysql-data:
    driver: local

Environment Variables

There are many ways to pass environment variables to your container through the use of docker-compose.

Individually Inside The Docker Compose File

Firstly, you can manually specify them individually like so:

version: "3"

services:
  app:
    image: my-docker-image
    environment:
      - MY_VARIABLE_NAME="bob"
    ports:
      - "80:80"

This is a pretty safe route, but means that everyone will be using the same environment variables, which is probably not what you want if you are tracking the docker-compose.yml file as part of your source control.

Implicit .env File

You can have a .env file at the same location as your docker-compose file. All variables within this .env file will automatically be used by docker-compose.

I need to check/confirm if it is same location as docker-compose.yml file, or path of where we are calling docker-compose from which may be different). E.g If one was to run docker-compose -f /path/to/docker-compose.yml up.

Values in the shell take precedence over those specified in the .env file.

Specify a .env File When Calling Docker Compose

docker-compose --env-file ./config/.env up

Values in the shell take precedence over those specified in the .env file.

Specify .env File In Compose File

Use the .env_file declaration as part of your configuration to specify where the .env file is that you wish to use.

version: "3"

services:
  app:
    container_name: app
    image: my-image-name
    env_file:
      - ./path/to/.env
    ports:
      - "80:80"

This is the route I most commonly use:

Values in the shell take precedence over those specified in the .env file.

Build Arguments (ARG)

Before going into build arguments, it is worth clarifying the difference between arguments and environment variables as they overlap quite a lot.

Build arguments are variables for the sole purpose of building your image. Environment variables may be used to in various ways to help you in building your image, but their main purpose is to pass information through to your container when it is deployed/run.

This diagram from a post on vsupalov.com explains it best:

Dockerfile

You can specify ARG as part of your Dockerfile at the start (above the FROM statement). These can then be used later as part of the build. E.g.

ARG ACCOUNT_ID

FROM ubuntu:latest
RUN echo $ACCOUNT_ID

... and then the argument can be passed in through the docker-compose file like so:

version: '3'
services:
  app:
    build:
       context: .
       args:                                                                     
         - ACCOUNT_ID=abcd

Default Value

In the previous example, we required the ACCOUNT_ID to be provided, but we could specify a default value that would be overridden, like so:

ARG ACCOUNT_ID="def"

FROM ubuntu:latest
RUN echo $ACCOUNT_ID

Specifying Build Arguments In Docker Build

If using docker build instead of docker-compose build, then you can provide the build arguments like so:

#!/bin/sh
docker build \
  --build-arg ACCOUNT_ID=abc \
  --build-arg SECOND_BUILD_ARG=admin \
...

Specifying Build Arguments In Docker-compose Command

We showed you earlier how to provide arguments within the docker-compose declaration file, but you can also provide them when calling the docker-compose command like so:

docker-compose build \
  --build-arg ACCOUNT_ID=abc \
  --build-arg SECOND_BUILD_ARG=admin

Variables In Compose File

If you need to use a variable in the docker-compose file, use the ${VARIABLE_NAME} syntax and provide the VARIABLE_NAME through either an environment variable, or an ARG (details of the many various ways of providing environment variables and arguments detailed above).

For example, the configuration below will use environment or ARG variables to build the image declaration using the DOCKER_REGISTRY, PROJECT_NAME, AND TAG_VERSION variables.

version: "3"

services:
  app:
    build:
      context: .
      dockerfile: ./Dockerfile
    container_name: app
    image: ${DOCKER_REGISTRY}/${PROJECT_NAME}:${TAG_VERSION}
    restart: always
    ports:
      - "80:80"

Compose Project Name

It's worth setting the COMPOSE_PROJECT_NAME environment variable for specifying what I call the "namespace" of your project. This will add prefixes, to try and prevent generic names for things like your volumes, clashing with other projects. E.g. if you have two projects that use a MySQL volume called "mysql-data", you wouldn't want them to both reference the same volume.

If you don't set this variable, prefixes will be based on the folder name of where your docker-compose.yml file is.

You can also manually specify the project name as a parameter when calling docker-compose like so:

docker-compose --project-name "my-project-name` up

...or:

docker-compose -p "my-project-name` up

Official documentation.

Volumes

Named Volumes

If your container just needs to persistently store state that it generates, then named volumes are great. You can use named volumes like so:

version: "3"

services:
  db:
    image: mariadb:10.5
    container_name: db
    volumes:
      - my-volume-name:/var/lib/mysql

volumes:
  my-volume-name:
    driver: local

Misc

Specifying Hosts

If you need to manually pass DNS records to your containers (becuase updating your local server's /etc/hosts file won't work), then you can do that like so:

    extra_hosts:
      - "subdomain.mydomain.org:192.168.1.123"

e.g.

services:
  kibana:
    image: docker.elastic.co/kibana/kibana:7.9.0
    extra_hosts:
      - "elastic-search.programster.org:192.168.1.123"

Restart Choices

If you specify no for your restart (which you don't actually need to do because it's the default), then be aware that it is the only value you need to wrap in quotation marks. The choices are:

  • "no"
  • always
  • on-failure
  • unless-stopped

Relevant docs area.

References

Last updated: 29th September 2021
First published: 23rd August 2020