cosmicstack-labs/docker-patterns
Master Dockerfile optimization, multi-stage builds, docker-compose patterns, security hardening, and image size reduction techniques for production-grade containerization.
npx skills add https://github.com/cosmicstack-labs/mercury-agent-skills --skill docker-patterns
Docker patterns encompass the art and science of building efficient, secure, and maintainable container images. This skill covers the entire lifecycle — from writing optimized Dockerfiles and orchestrating multi-service environments with docker-compose to hardening images against vulnerabilities and minimizing attack surface. Mastery of these patterns is essential for any DevOps practitioner aiming to ship reliable, fast, and secure software.
FROM statement in Dockerfilesroot by default.dockerignore file:latest base image tagsdocker commit for ad-hoc image creationTypical Beginner Dockerfile (anti-pattern):
FROM node:latest
RUN apt-get update && apt-get install -y build-essential
COPY . /app
WORKDIR /app
RUN npm install
RUN npm run build
CMD ["npm", "start"]
node:20-slim).dockerignore filesnode:20-slim@sha256:...)docker scan or trivy for vulnerability scanningProficient Dockerfile:
# Stage 1: Build
FROM node:20-slim AS builder
WORKDIR /build
COPY package.json package-lock.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# Stage 2: Runtime
FROM node:20-slim AS runtime
RUN groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR /app
COPY --from=builder /build/dist ./dist
COPY --from=builder /build/node_modules ./node_modules
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s \
CMD node healthcheck.js
CMD ["node", "dist/server.js"]
--mount=type=cache for zero-copy dependency installsdocker sbom or syfthadolint integrated into CIExpert Dockerfile:
# syntax=docker/dockerfile:1.7
# Stage 1: Build with cache mounts
FROM golang:1.22-alpine AS builder
RUN apk add --no-cache ca-certificates
WORKDIR /src
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
go mod download
COPY . .
RUN --mount=type=cache,target=/go/pkg/mod \
CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app .
# Stage 2: Distroless runtime
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /app /app
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
USER nonroot:nonroot
EXPOSE 8080
ENTRYPOINT ["/app"]
Multi-stage builds use multiple FROM statements in a single Dockerfile. Each stage can use a different base image. Only the final stage is saved in the image — intermediate stages are discarded.
Why they matter:
Pattern — Build and Copy Artifacts:
# Build stage
FROM python:3.12-slim AS builder
COPY requirements.txt .
RUN pip install --user -r requirements.txt
# Runtime stage
FROM python:3.12-slim
COPY --from=builder /root/.local /root/.local
COPY app/ ./app
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app/main.py"]
Pattern — Conditional Stages with Build Args:
ARG BUILD_ENV=production
FROM node:20-alpine AS base
WORKDIR /app
COPY package*.json ./
FROM base AS development
RUN npm install --include=dev
COPY . .
FROM base AS production
RUN npm ci --only=production
COPY . .
RUN npm run build
FROM ${BUILD_ENV}
CMD ["node", "dist/server.js"]
Layer Caching Strategy:
package.json / requirements.txt before source code — dependency install layers only invalidate when dependencies changeRUN apt-get update with apt-get install in the same layer to avoid stale cache issues--no-cache or --no-install-recommends flags to reduce size# GOOD: Dependencies before source
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# BAD: Source before dependencies — invalidates cache on every code change
COPY . .
RUN pip install -r requirements.txt
.dockerignore File:
Always create a .dockerignore to exclude files from the build context:
node_modules
.git
.env
*.md
coverage
.gitignore
Dockerfile
.dockerignore
dist
.cache
npm-debug.log
Image Size Optimization:
-slim variants over full images-alpine for even smaller sizes when compatibility allows RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
Health Checks:
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
Service Composition:
version: "3.9"
services:
api:
build:
context: .
target: production
cache_from:
- myapp/api:latest
ports:
- "8080:8080"
environment:
- DB_HOST=db
- REDIS_HOST=redis
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
- type: volume
source: app_data
target: /app/data
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: myapp
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U myapp"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
command: redis-server --appendonly yes
volumes:
pgdata:
redis_data:
app_data:
secrets:
db_password:
file: ./secrets/db_password.txt
Development vs Production Profiles:
services:
app:
build: .
profiles: ["dev", "prod"]
mailhog:
image: mailhog/mailhog
profiles: ["dev"]
ports: ["8025:8025"]
prometheus:
image: prom/prometheus
profiles: ["prod"]
Start dev: docker compose --profile dev up
Docker Compose Health Check Wait Pattern:
services:
app:
depends_on:
db:
condition: service_healthy
Never Run as Root:
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
Read-Only Root Filesystem:
services:
app:
read_only: true
tmpfs:
- /tmp
Drop Capabilities:
services:
app:
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
Security Scanning with Trivy:
# Scan image
trivy image --severity HIGH,CRITICAL myapp:latest
# Scan Dockerfile for misconfigurations
trivy config --severity HIGH,CRITICAL Dockerfile
# CI integration
trivy image --exit-code 1 --severity CRITICAL myapp:latest
Docker Bench Security:
docker run --privileged --pid=host \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /etc:/etc:ro \
docker/docker-bench-security
Use Specific Image Digests:
FROM node:20-slim@sha256:abc123def456...
:latest — Unpinned tags cause unpredictable builds. Always pin to a specific version or digest.COPY . /app sends the entire directory including node_modules, .git, and secrets. Use .dockerignore and specific COPY paths.--no-install-recommends and prefer distroless images.10. Overly permissive compose volumes — .:/app bind mounts expose the host filesystem. Use named volumes or specific host paths instead.
Take cosmicstack-labs/docker-patterns from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference pip, npm, apt, docker.
Without those the skill loads but fails at the first command.