
How to Use
About
Implement zero-downtime deployments with blue-green, canary, rolling updates, and feature flag strategies.
name: docker-ops description: "Docker containerization patterns, Dockerfile best practices, multi-stage builds, and Docker Compose. Use for: docker, Dockerfile, docker-compose, container, image, multi-stage build, docker build, docker run, .dockerignore, health check, distroless, scratch image, BuildKit, layer caching, container security." license: MIT allowed-tools: "Read Write Bash" metadata: author: claude-mods related-skills: container-orchestration, go-ops, rust-ops, ci-cd-ops
Docker Operations
Comprehensive Docker patterns for building, running, and composing containerized applications.
Dockerfile Best Practices
| Practice | Do | Don't |
|----------|------|-------|
| Base image | FROM node:20-slim | FROM node:latest |
| Layer caching | Copy dependency files first, then source | COPY . . before RUN install |
| Package install | apt-get update && apt-get install -y ... && rm -rf /var/lib/apt/lists/* | Separate RUN for update and install |
| User | USER nonroot (create if needed) | Run as root in production |
| Multi-stage | Separate build and runtime stages | Ship compiler toolchains |
| Secrets | --mount=type=secret (BuildKit) | COPY .env . or ARG PASSWORD |
| ENTRYPOINT vs CMD | ENTRYPOINT for fixed binary, CMD for defaults | Relying on shell form for signal handling |
| WORKDIR | WORKDIR /app | RUN cd /app && ... |
| .dockerignore | Include .git, node_modules, __pycache__ | No .dockerignore at all |
| Labels | LABEL org.opencontainers.image.* | No metadata |
Multi-Stage Build Decision Tree
Choose your runtime base image by language:
Go ──────────── CGO disabled? ──── Yes ──► scratch or distroless/static
No ───► distroless/base or alpine
Rust ─────────── Static musl? ──── Yes ──► scratch or distroless/static
No ───► distroless/cc or debian-slim
Node.js ──────── Need native? ──── Yes ──► node:20-slim
No ───► node:20-alpine (smaller)
Python ────────── Need C libs? ─── Yes ──► python:3.12-slim
No ───► python:3.12-slim (still slim)
Java ──────────── JRE only ──────────────► eclipse-temurin:21-jre-alpine
See:
references/multi-stage-builds.mdfor complete annotated examples per language.
Layer Caching Rules
Docker caches each layer. A cache miss at layer N invalidates all subsequent layers.
What Invalidates Cache
| Trigger | Effect |
|---------|--------|
| Changed file in COPY/ADD | Invalidates this layer + all below |
| Changed RUN command text | Invalidates this layer + all below |
| Changed ARG value | Invalidates from the ARG declaration down |
| --no-cache flag | Invalidates everything |
| Base image update | Invalidates everything |
Optimal Layer Order
# 1. Base image (changes rarely)
FROM python:3.12-slim
# 2. System dependencies (changes rarely)
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# 3. Dependency files (changes occasionally)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 4. Application code (changes frequently)
COPY src/ ./src/
# 5. Runtime config (changes frequently)
CMD ["python", "-m", "app"]
Rule of thumb: Order layers from least-frequently-changed to most-frequently-changed.
.dockerignore Essentials
# Version control
.git
.gitignore
# Dependencies (rebuilt in container)
node_modules
__pycache__
*.pyc
.venv
vendor/
# Build artifacts
dist/
build/
target/
*.egg-info
# IDE and editor
.vscode
.idea
*.swp
*.swo
# Docker files (prevent recursive context)
Dockerfile*
docker-compose*
.dockerignore
# Environment and secrets
.env
.env.*
*.pem
*.key
# Documentation and tests (unless needed)
docs/
tests/
*.md
LICENSE
Why it matters: Without .dockerignore, docker build sends the entire context directory to the daemon. A .git folder alone can add hundreds of megabytes.
Docker Compose Quick Reference
Service Definition
services:
web:
build:
context: .
dockerfile: Dockerfile
target: production # Multi-stage target
image: myapp:latest
ports:
- "8080:8000"
environment:
DATABASE_URL: postgres://db:5432/app
env_file:
- .env
volumes:
- ./src:/app/src # Bind mount (dev)
- app-data:/app/data # Named volume (persistent)
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
restart: unless-stopped
networks:
- backend
Volumes and Networks
volumes:
app-data: # Named volume (Docker-managed)
db-data:
driver: local
networks:
backend:
driver: bridge
frontend:
dr


