Skip to main content

Step 2

Step 2 — docker-compose patterns

7 views

Table of contents

Real services aren't single containers. App + DB + Redis + queue — docker-compose brings them up together.

First docker-compose.yml

services:
  postgres:
    image: postgres:17-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: secret
    volumes:
      - pg-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
      interval: 5s

  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redis-data:/data

  app:
    build: .
    depends_on:
      postgres: { condition: service_healthy }
      redis:    { condition: service_started }
    environment:
      DB_URL: postgresql://user:secret@postgres:5432/myapp
      REDIS_URL: redis://redis:6379
    ports:
      - "127.0.0.1:3000:3000"
    restart: unless-stopped

volumes:
  pg-data:
  redis-data:
docker compose up -d
docker compose ps
docker compose logs -f app
docker compose down

Seven patterns

  1. healthcheck — gate depends_on with condition: service_healthy
  2. 127.0.0.1 binding — only Caddy reaches the app port
  3. named volumespg-data for production
  4. env_file — secrets out of YAML
  5. depends_on — startup order
  6. restart: unless-stopped — survive reboots
  7. logging driver cap — the default json-file driver grows without limit. Define it once via an anchor and attach to every service:
    x-logging: &default-logging
      driver: json-file
      options: { max-size: "10m", max-file: "3" }
    
    services:
      postgres:
        logging: *default-logging
      app:
        logging: *default-logging
    
    A large monorepo: several compose files × dozens of services with a single anchor → a 30MB cap per container.

.env split

services:
  app:
    env_file: [.env.prod]

DEV vs PROD split

infra/
├── dev/docker-compose.yml
└── prod/docker-compose.yml

DEV: hot-reload + direct exposure. PROD: behind Caddy + loopback only.

Try it

Bring up Postgres + Redis + app from the YAML above. docker compose ps should show all healthy.

Going deeper

Next

Step 3 — Caddy.

Terms in this content