Orchestrate a multi-container app locally (web + db + cache + worker) with a single docker compose up.
Compose is an orchestra conductor - each service is a musician who knows their part; the conductor reads the score and coordinates.
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
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.
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.
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.
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.
version: '3' is obsolete - remove it. Missing condition: service_healthy - web crashes because DB isn’t ready. Storing prod secrets in plaintext compose file.
Use health-check-based dependencies; pin image tags; named volumes for stateful data; —profile dev for optional services; security scan with docker scout cves.
could not connect to server: Connection refused.condition: service_healthy requiring healthcheck to pass.docker-compose.yml in repo root being used in prod.docker compose up directly on a prod box instead of using k8s/ECS.