Skip to Content

Docker Compose

When to use

Orchestrate a multi-container app locally (web + db + cache + worker) with a single docker compose up.

Analogy

Compose is an orchestra conductor - each service is a musician who knows their part; the conductor reads the score and coordinates.

Data-flow diagram

  compose.yaml
    services:
      web:   { build: ., ports: [8000:8000] }
      db:    { image: postgres:16, volumes: [dbdata:/var/lib/postgresql/data] }
      cache: { image: redis:7 }
      worker:{ build: ., command: celery -A app worker }
  docker compose up -d   # starts them all
  docker compose down -v # stop + remove + delete volumes

Deep explanation

Compose v2 (the modern docker compose plugin) collapses the version: field and uses the Compose Specification. Each service has image: (pull existing) or build: (Dockerfile path), command, ports, env, volumes, networks, dependencies, health checks, resource limits. Networks: Compose creates a default network; services reach each other by service name (db, cache). Named volumes survive down but are removed by down -v.

Examples

Example 1

services:
  web:
    build: .
    ports: ["8000:8000"]
    environment:
      DATABASE_URL: postgres://app@db/app
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secretdev
    volumes: ["dbdata:/var/lib/postgresql/data"]
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
      interval: 5s
      retries: 5
volumes:
  dbdata:

canonical multi-service compose; depends_on condition: service_healthy waits for Postgres ready.

Example 2

docker compose up -d
docker compose logs -f web
docker compose exec web bash
docker compose down -v

starts everything in background; tails web logs; opens shell in web container; tears down with volumes.

Example 3

docker compose -f compose.yaml -f compose.prod.yaml up

Compose file layering: base service defs in compose.yaml, prod overrides in compose.prod.yaml.

Common mistake

version: '3' is obsolete - remove it. Missing condition: service_healthy - web crashes because DB isn’t ready. Storing prod secrets in plaintext compose file.

Key takeaway

Use health-check-based dependencies; pin image tags; named volumes for stateful data; —profile dev for optional services; security scan with docker scout cves.

Production Failure Playbook

Failure scenario 1: container-started-before-db

Failure scenario 2: compose-accidentally-deployed-to-prod