docker-patterns

Docker and Docker Compose patterns for local development, multi-service orchestration, and container security. Covers multi-stage Dockerfiles with dev, build, and production targets; Docker Compose configuration for web app stacks with PostgreSQL, Redis, and Mailpit; and override files for environment-specific settings Includes service discovery via container networking, custom network isolation, and volume strategies (named volumes, bind mounts, anonymous volumes) for data persistence and hot reload Provides container hardening practices: non-root users, capability dropping, read-only filesystems, and secret management via environment variables and Docker secrets Offers debugging commands for logs, container inspection, network troubleshooting, and resource monitoring; documents anti-patterns like running as root, using latest tags, and storing data without volumes

INSTALLATION
npx skills add https://github.com/affaan-m/everything-claude-code --skill docker-patterns
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

Docker Patterns

Docker and Docker Compose best practices for containerized development.

When to Activate

  • Setting up Docker Compose for local development
  • Designing multi-container architectures
  • Troubleshooting container networking or volume issues
  • Reviewing Dockerfiles for security and size
  • Migrating from local dev to containerized workflow

Docker Compose for Local Development

Standard Web App Stack

# docker-compose.yml

services:

  app:

    build:

      context: .

      target: dev                     # Use dev stage of multi-stage Dockerfile

    ports:

      - "3000:3000"

    volumes:

      - .:/app                        # Bind mount for hot reload

      - /app/node_modules             # Anonymous volume -- preserves container deps

    environment:

      - DATABASE_URL=postgres://postgres:postgres@db:5432/app_dev

      - REDIS_URL=redis://redis:6379/0

      - NODE_ENV=development

    depends_on:

      db:

        condition: service_healthy

      redis:

        condition: service_started

    command: npm run dev

  db:

    image: postgres:16-alpine

    ports:

      - "5432:5432"

    environment:

      POSTGRES_USER: postgres

      POSTGRES_PASSWORD: postgres

      POSTGRES_DB: app_dev

    volumes:

      - pgdata:/var/lib/postgresql/data

      - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql

    healthcheck:

      test: ["CMD-SHELL", "pg_isready -U postgres"]

      interval: 5s

      timeout: 3s

      retries: 5

  redis:

    image: redis:7-alpine

    ports:

      - "6379:6379"

    volumes:

      - redisdata:/data

  mailpit:                            # Local email testing

    image: axllent/mailpit

    ports:

      - "8025:8025"                   # Web UI

      - "1025:1025"                   # SMTP

volumes:

  pgdata:

  redisdata:

Development vs Production Dockerfile

# Stage: dependencies

FROM node:22-alpine AS deps

WORKDIR /app

COPY package.json package-lock.json ./

RUN npm ci

# Stage: dev (hot reload, debug tools)

FROM node:22-alpine AS dev

WORKDIR /app

COPY --from=deps /app/node_modules ./node_modules

COPY . .

EXPOSE 3000

CMD ["npm", "run", "dev"]

# Stage: build

FROM node:22-alpine AS build

WORKDIR /app

COPY --from=deps /app/node_modules ./node_modules

COPY . .

RUN npm run build && npm prune --production

# Stage: production (minimal image)

FROM node:22-alpine AS production

WORKDIR /app

RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001

USER appuser

COPY --from=build --chown=appuser:appgroup /app/dist ./dist

COPY --from=build --chown=appuser:appgroup /app/node_modules ./node_modules

COPY --from=build --chown=appuser:appgroup /app/package.json ./

ENV NODE_ENV=production

EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/health || exit 1

CMD ["node", "dist/server.js"]

Override Files

# docker-compose.override.yml (auto-loaded, dev-only settings)

services:

  app:

    environment:

      - DEBUG=app:*

      - LOG_LEVEL=debug

    ports:

      - "9229:9229"                   # Node.js debugger

# docker-compose.prod.yml (explicit for production)

services:

  app:

    build:

      target: production

    restart: always

    deploy:

      resources:

        limits:

          cpus: "1.0"

          memory: 512M
# Development (auto-loads override)

docker compose up

# Production

docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Networking

Service Discovery

Services in the same Compose network resolve by service name:

# From "app" container:

postgres://postgres:postgres@db:5432/app_dev    # "db" resolves to the db container

redis://redis:6379/0                             # "redis" resolves to the redis container

Custom Networks

services:

  frontend:

    networks:

      - frontend-net

  api:

    networks:

      - frontend-net

      - backend-net

  db:

    networks:

      - backend-net              # Only reachable from api, not frontend

networks:

  frontend-net:

  backend-net:

Exposing Only What's Needed

services:

  db:

    ports:

      - "127.0.0.1:5432:5432"   # Only accessible from host, not network

    # Omit ports entirely in production -- accessible only within Docker network

Volume Strategies

volumes:

  # Named volume: persists across container restarts, managed by Docker

  pgdata:

  # Bind mount: maps host directory into container (for development)

  # - ./src:/app/src

  # Anonymous volume: preserves container-generated content from bind mount override

  # - /app/node_modules

Common Patterns

services:

  app:

    volumes:

      - .:/app                   # Source code (bind mount for hot reload)

      - /app/node_modules        # Protect container's node_modules from host

      - /app/.next               # Protect build cache

  db:

    volumes:

      - pgdata:/var/lib/postgresql/data          # Persistent data

      - ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql  # Init scripts

Container Security

Dockerfile Hardening

# 1. Use specific tags (never :latest)

FROM node:22.12-alpine3.20

# 2. Run as non-root

RUN addgroup -g 1001 -S app && adduser -S app -u 1001

USER app

# 3. Drop capabilities (in compose)

# 4. Read-only root filesystem where possible

# 5. No secrets in image layers

Compose Security

services:

  app:

    security_opt:

      - no-new-privileges:true

    read_only: true

    tmpfs:

      - /tmp

      - /app/.cache

    cap_drop:

      - ALL

    cap_add:

      - NET_BIND_SERVICE          # Only if binding to ports < 1024

Secret Management

# GOOD: Use environment variables (injected at runtime)

services:

  app:

    env_file:

      - .env                     # Never commit .env to git

    environment:

      - API_KEY                  # Inherits from host environment

# GOOD: Docker secrets (Swarm mode)

secrets:

  db_password:

    file: ./secrets/db_password.txt

services:

  db:

    secrets:

      - db_password

# BAD: Hardcoded in image

# ENV API_KEY=sk-proj-xxxxx      # NEVER DO THIS

.dockerignore

node_modules

.git

.env

.env.*

dist

coverage

*.log

.next

.cache

docker-compose*.yml

Dockerfile*

README.md

tests/

Debugging

Common Commands

# View logs

docker compose logs -f app           # Follow app logs

docker compose logs --tail=50 db     # Last 50 lines from db

# Execute commands in running container

docker compose exec app sh           # Shell into app

docker compose exec db psql -U postgres  # Connect to postgres

# Inspect

docker compose ps                     # Running services

docker compose top                    # Processes in each container

docker stats                          # Resource usage

# Rebuild

docker compose up --build             # Rebuild images

docker compose build --no-cache app   # Force full rebuild

# Clean up

docker compose down                   # Stop and remove containers

docker compose down -v                # Also remove volumes (DESTRUCTIVE)

docker system prune                   # Remove unused images/containers

Debugging Network Issues

# Check DNS resolution inside container

docker compose exec app nslookup db

# Check connectivity

docker compose exec app wget -qO- http://api:3000/health

# Inspect network

docker network ls

docker network inspect <project>_default

Anti-Patterns

# BAD: Using docker compose in production without orchestration

# Use Kubernetes, ECS, or Docker Swarm for production multi-container workloads

# BAD: Storing data in containers without volumes

# Containers are ephemeral -- all data lost on restart without volumes

# BAD: Running as root

# Always create and use a non-root user

# BAD: Using :latest tag

# Pin to specific versions for reproducible builds

# BAD: One giant container with all services

# Separate concerns: one process per container

# BAD: Putting secrets in docker-compose.yml

# Use .env files (gitignored) or Docker secrets
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card