Docker Tip #94: Docker Compose v2 and Profiles Are the Best Thing Ever
I switched to v2 because it's faster and profiles let you easily start specific services in different environments.
Prefer video? Here’s a recorded version of this tip on YouTube which demonstrates using profiles and more.
Docker Compose v2 was marked generally available in April 2022, its timeline is:
- October 2022: v2 will be on by default and you can opt-out of it in Docker Desktop
- April 2023: v2 will be the only option with Docker Desktop
The 3 biggest reasons on why I’ve switched to it are:
- Containers start and stop faster than Docker Compose v1
- Docker Compose profiles support with seamless optional
depends_on
to make it easy to control running specific containers in different environments (it’s a pure upgrade to the override file pattern) - v2 is a Docker plugin written in Go, there’s no need for a Python environment anymore (btw even the curl version of Docker Compose v1 uses PyInstaller to bundle it up)
I’ve updated all of my example Docker web apps to use Docker Compose v2 with profiles and also updated my Ansible role to install Docker Compose v2 by default. It works nicely on native Linux without Docker Desktop since it’s just a system package to install.
With profiles imagine having a docker-compose.yml
such as this (simplified to
demo profiles):
services:
postgres:
profiles: ["postgres"]
redis:
profiles: ["redis"]
web:
profiles: ["web"]
depends_on: ["postgres", "redis"]
worker:
profiles: ["worker"]
depends_on: ["postgres", "redis"]
assets:
profiles: ["assets"]
In development you can set this environment variable in an .env
file to start
everything:
export COMPOSE_PROFILES=postgres,redis,assets,web,worker
In production you can set this instead:
export COMPOSE_PROFILES=web,worker
You can also use the docker compose --profile web,worker up
flag instead of
an environment variable but I prefer using the environment variable approach to
avoid needing to run custom commands on different servers.
The above expects your assets would be built beforehand in production instead
of running various asset watcher containers like esbuild
or tailwind
in
development.
The above also expects you may want to run managed versions of Postgres and
Redis on your cloud provider of choice, but you don’t have to do this. Even
with depends_on
defined on your web
and worker
services it doesn’t
matter. Docker Compose v2 is smart enough to know to ignore the dependent
services because you didn’t specify the postgres
or redis
profiles to run.
You could even choose to run your web
and worker
on separate servers by
only specifying each one individually such as export COMPOSE_PROFILES=web
and
export COMPOSE_PROFILES=worker
on each server.
Update: Docker Compose v2.19 broke this behavior but v2.20.2+ addressed it
by allowing you to set required: true
or required: false
on a depends_on
service. This post goes into more
details.
Profiles are very flexible, they’re great! I switched over to this combo for both development and production in August 2022.