DevOps Peach

Docker & Kubernetes · Docker in Real Projects – Operations and Docker Compose · Lesson 3 of 4

Introduction to Docker Compose

Declare every service of an app in one YAML file and manage its whole lifecycle with docker compose.

Practice interactively →

Three steps

  1. Write a Dockerfile for the app.
  2. Declare the services in compose.yaml (the old name docker-compose.yml is still read).
  3. docker compose up -d.
services:
  api:
    build: .
    ports: ["3000:3000"]
    environment:
      DB_HOST: db
    depends_on: [db]
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: changeme-example
    volumes: [db-data:/var/lib/postgresql/data]
volumes:
  db-data:
flowchart LR
  Y["compose.yaml"] -- "docker compose up -d" --> N["network node-app_default"]
  N --- A["node-app-api-1"]
  N --- D["node-app-db-1"]
  D --- V[("volume node-app_db-data")]

Use docker compose (Compose v2, a Docker CLI plugin). The Python docker-compose v1 has been unsupported since 2023, and the top-level version: key is now obsolete.

Compose manages the whole lifecycle

Command Meaning
docker compose up -d Create/start every service; only recreates containers whose config changed
docker compose ps Service status
docker compose logs -f api Stream the logs of service api
docker compose down Stop and remove containers and the network; keeps volumes
docker compose down -v Also removes named volumes — database data is lost
docker compose -f compose.yaml -f compose.prod.yaml up -d Merge several files; later files override earlier ones

Common traps

More service keys

services:
  api:
    build:
      context: .
      target: runtime
      args: { NODE_VERSION: "20" }
    image: registry.example.com/node-app:1.2.0
    command: ["node", "server.js", "--port", "3000"]
    restart: unless-stopped
    depends_on:
      db: { condition: service_healthy }
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      retries: 10

build and image together build the image and tag it with that name, ready for docker compose push. restart follows the same policies as docker run --restart.

Everyday commands

Command Meaning
docker compose build Build or rebuild images
docker compose pull Pull newer versions of images
docker compose exec db psql -U postgres Run a command in a running service
docker compose restart api Restart one service
docker compose config Show the merged, resolved configuration
docker compose watch Sync or rebuild automatically when files change (with develop.watch rules)

Fast inner loop with watch

    develop:
      watch:
        - action: sync
          path: ./src
          target: /app/src
        - action: rebuild
          path: package.json

Source edits are copied into the running container, and a dependency change triggers a rebuild, without hand-written bind mounts.

Where Compose fits

The Compose file format is an open Compose Specification, also read by other tools. Compose is excellent for development, CI test environments, and small single-host deployments. For several hosts, self-healing across machines, and rolling updates at scale, the same ideas continue in Swarm and Kubernetes later in this track.

Practice interactively →