Files
claude-skills-reference/engineering/docker-development/references/compose-patterns.md
Leo bf1473b1be feat(skills): add research-summarizer and docker-development agent skills
research-summarizer (product-team/):
- Structured research summarization for papers, articles, reports
- Slash commands: /research:summarize, /research:compare, /research:cite
- Python tools: extract_citations.py (5 citation formats), format_summary.py (6 templates)
- References: summary-templates.md, citation-formats.md

docker-development (engineering/):
- Dockerfile optimization, compose orchestration, container security
- Slash commands: /docker:optimize, /docker:compose, /docker:security
- Python tools: dockerfile_analyzer.py (15 rules), compose_validator.py (best practices)
- References: dockerfile-best-practices.md, compose-patterns.md

Both skills include .claude-plugin/plugin.json and follow POWERFUL tier conventions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 22:47:16 +01:00

5.7 KiB

Docker Compose Patterns Reference

Production-Ready Patterns

Web App + Database + Cache

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    env_file:
      - .env
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 10s
    restart: unless-stopped
    networks:
      - frontend
      - backend
    mem_limit: 512m
    cpus: 1.0

  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    env_file:
      - .env.db
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - backend
    mem_limit: 256m

  redis:
    image: redis:7-alpine
    command: redis-server --maxmemory 64mb --maxmemory-policy allkeys-lru
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 3
    restart: unless-stopped
    networks:
      - backend
    mem_limit: 128m

volumes:
  pgdata:

networks:
  frontend:
  backend:
    internal: true

Key Patterns

  • Healthchecks on every service — enables depends_on with condition
  • Named volumes — data persists across container recreation
  • Explicit networks — backend is internal (no external access)
  • env_file — secrets not in compose file
  • Resource limits — prevent runaway containers

Development Override Pattern

docker-compose.yml (base — production-like)

services:
  app:
    build: .
    ports:
      - "3000:3000"
    restart: unless-stopped

docker-compose.override.yml (dev — auto-loaded)

services:
  app:
    build:
      target: development
    volumes:
      - .:/app          # Bind mount for hot reload
      - /app/node_modules  # Preserve container node_modules
    environment:
      - NODE_ENV=development
      - DEBUG=true
    ports:
      - "9229:9229"     # Debug port
    restart: "no"

Usage

# Development (auto-loads override)
docker compose up

# Production (skip override)
docker compose -f docker-compose.yml up -d

# Explicit profiles
docker compose --profile dev up
docker compose --profile prod up -d

Network Isolation Pattern

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    networks:
      - frontend

  app:
    build: .
    networks:
      - frontend
      - backend

  db:
    image: postgres:16-alpine
    networks:
      - backend

  redis:
    image: redis:7-alpine
    networks:
      - backend

networks:
  frontend:
    # External traffic reaches nginx and app
  backend:
    internal: true
    # DB and Redis only reachable by app

Why This Matters

  • Database and cache are not accessible from outside
  • Only nginx and app handle external traffic
  • Lateral movement limited if one container is compromised

Worker + Queue Pattern

services:
  api:
    build:
      context: .
      target: runtime
    command: uvicorn main:app --host 0.0.0.0 --port 8000
    ports:
      - "8000:8000"
    depends_on:
      rabbitmq:
        condition: service_healthy

  worker:
    build:
      context: .
      target: runtime
    command: celery -A tasks worker --loglevel=info
    depends_on:
      rabbitmq:
        condition: service_healthy

  scheduler:
    build:
      context: .
      target: runtime
    command: celery -A tasks beat --loglevel=info
    depends_on:
      rabbitmq:
        condition: service_healthy

  rabbitmq:
    image: rabbitmq:3.13-management-alpine
    ports:
      - "15672:15672"  # Management UI (dev only)
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "check_running"]
      interval: 10s
      timeout: 5s
      retries: 5

Logging Configuration

services:
  app:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        tag: "{{.Name}}/{{.ID}}"

Why

  • max-size prevents disk exhaustion
  • max-file rotates logs automatically
  • Default Docker logging has NO size limit — production servers can run out of disk

Environment Variable Patterns

.env.example (committed to repo)

# Database
DATABASE_URL=postgres://user:password@db:5432/appname
POSTGRES_USER=user
POSTGRES_PASSWORD=changeme
POSTGRES_DB=appname

# Redis
REDIS_URL=redis://redis:6379/0

# Application
SECRET_KEY=changeme-generate-a-real-secret
NODE_ENV=production
LOG_LEVEL=info

# External Services (BYOK)
# SMTP_HOST=
# SMTP_PORT=587
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=

Variable Substitution in Compose

services:
  app:
    image: myapp:${APP_VERSION:-latest}
    environment:
      - LOG_LEVEL=${LOG_LEVEL:-info}
      - PORT=${PORT:-3000}

Troubleshooting Checklist

Symptom Likely Cause Fix
Container exits immediately CMD/ENTRYPOINT crashes, missing env vars Check logs: docker compose logs service
Port already in use Another service or host process on same port Change host port: "3001:3000"
Volume permissions denied Container user doesn't own mounted path Match UID/GID or use named volumes
Build cache not working COPY . . invalidates cache early Reorder: copy deps first, then source
depends_on doesn't wait No healthcheck condition Add condition: service_healthy
Container OOM killed No memory limit or limit too low Set appropriate mem_limit
Network connectivity issues Wrong network or service name Services communicate by service name within shared network