C.W.K.
Stream
Lesson 02 of 08 · published

Docker Compose — services, networks, volumes

~12 min · yaml, docker, compose

Level 0Plaintext
0 XP0/64 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

Multi-container apps as one YAML file

compose.yaml (or docker-compose.yaml, both valid) describes a stack — multiple containers, their networks, their volumes, their dependencies. docker compose up brings the whole stack online. Same YAML grammar as Kubernetes; very different semantics (single host, no reconciliation).

The three top-level sections you'll touch

  • services — the containers. Each named, with image or build, ports, environment, volumes, depends_on.
  • volumes — named persistent disks (Postgres data, ML model cache).
  • networks — usually one default; declare extras for cross-stack wiring.

The depends_on nuance

By default, depends_on means 'start in this order' — not 'wait until ready.' For real readiness, use condition: service_healthy and define a healthcheck on the depended-on service. The plain form is a foot-gun: your app starts before Postgres accepts connections.

The version: "3.8" line is dead. Compose Spec v2 (2020+) ignores the version: field. New files should omit it. Old files with version: "3.8" still work but the field is decorative. Don't copy it from old tutorials thinking it does something.

Code

Three-service stack with a real healthcheck·yaml
services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: dev
      POSTGRES_DB: pippa
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 10

  api:
    build: .
    ports:
      - "8000:8000"
    environment:
      DATABASE_URL: postgresql://postgres:dev@postgres:5432/pippa
    depends_on:
      postgres:
        condition: service_healthy

  worker:
    build: .
    command: ["python", "worker.py"]
    depends_on:
      postgres:
        condition: service_healthy

volumes:
  pgdata:
Profiles for opt-in services·yaml
services:
  api:
    image: ghcr.io/cwk/api
    # always runs

  observability:
    image: grafana/grafana
    profiles: ["obs"]
    # only runs with: docker compose --profile obs up

  loadtest:
    image: locustio/locust
    profiles: ["perf"]
    # only runs with: docker compose --profile perf up
Validate (and expand anchors)·bash
# Resolve all variables, expand anchors, show normalized form
docker compose config

# Quick syntax check
docker compose config --quiet && echo OK

# View the resolved env per service
docker compose config --format json | jq '.services.api.environment'

External links

Exercise

Take a compose.yaml you wrote that has multiple services. Add a real healthcheck to the bottom-most dependency (db, redis, whatever). Switch every dependent service's depends_on from the bare form to the healthy-condition form. Run docker compose down && docker compose up — confirm dependents wait until the dep is healthy. Reliability for free.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.