Claude-initial-setup dockerfile-best-practices
install
source · Clone the upstream repo
git clone https://github.com/VersoXBT/claude-initial-setup
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/VersoXBT/claude-initial-setup "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/docker/dockerfile-best-practices" ~/.claude/skills/versoxbt-claude-initial-setup-dockerfile-best-practices && rm -rf "$T"
manifest:
skills/docker/dockerfile-best-practices/SKILL.mdsource content
Dockerfile Best Practices
Write secure, efficient, and maintainable Dockerfiles that produce minimal production images with proper caching, non-root users, and health checks.
When to Use
- User creates or modifies a Dockerfile
- User asks about reducing Docker image size
- User mentions container security or hardening
- User has slow Docker builds or cache invalidation issues
- User asks about COPY vs ADD or layer ordering
Core Patterns
Multi-Stage Builds
Separate build dependencies from runtime to minimize final image size.
# Stage 1: Build FROM node:20-alpine AS builder WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci --ignore-scripts COPY src/ src/ COPY tsconfig.json ./ RUN npm run build # Stage 2: Production FROM node:20-alpine AS production WORKDIR /app RUN addgroup -g 1001 appgroup && \ adduser -u 1001 -G appgroup -s /bin/sh -D appuser COPY --from=builder --chown=appuser:appgroup /app/dist ./dist COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules COPY --from=builder --chown=appuser:appgroup /app/package.json ./ USER appuser EXPOSE 3000 HEALTHCHECK --interval=30s --timeout=3s --retries=3 \ CMD wget -qO- http://localhost:3000/health || exit 1 CMD ["node", "dist/index.js"]
Layer Caching Optimization
Order instructions from least to most frequently changed. Copy dependency manifests before source code so dependency installs are cached across builds.
FROM python:3.12-slim WORKDIR /app # System deps change rarely -- cache this layer RUN apt-get update && \ apt-get install -y --no-install-recommends libpq-dev && \ rm -rf /var/lib/apt/lists/* # Dependencies change occasionally -- cache this layer COPY requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt # Source code changes frequently -- last layer COPY . . CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0"]
Non-Root User
Never run containers as root in production. Create a dedicated user with minimal permissions.
FROM golang:1.22-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /server ./cmd/server FROM scratch COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=builder /server /server USER 65534:65534 ENTRYPOINT ["/server"]
.dockerignore
Always include a .dockerignore to prevent sending unnecessary files to the build context.
.git .github node_modules dist *.md .env* .vscode .idea docker-compose*.yml Dockerfile* coverage __pycache__ *.pyc .pytest_cache
Health Checks
Define health checks in the Dockerfile so orchestrators can monitor container health.
# HTTP health check HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD curl -f http://localhost:8080/healthz || exit 1 # TCP health check (when curl is unavailable) HEALTHCHECK --interval=30s --timeout=3s --retries=3 \ CMD nc -z localhost 8080 || exit 1
Anti-Patterns
- Using
tag: Always pin base image versions (latest
, notnode:20.11-alpine
). Unpinned tags cause non-reproducible builds.node:latest - Running as root: Never omit the
instruction. Root in a container is root on the host if the container escapes.USER - Using ADD instead of COPY: ADD auto-extracts archives and fetches URLs, which is unexpected. Use COPY for local files; use
orcurl
explicitly for remote files.wget - Installing dev dependencies in production: Use
ornpm ci --omit=dev
in the final stage.pip install --no-dev - Single-stage builds: Shipping compilers, build tools, and source code in production images wastes space and expands the attack surface.
- Not cleaning up apt/apk cache: Always add
afterrm -rf /var/lib/apt/lists/*
or useapt-get install
with--no-cache
.apk add
Quick Reference
| Practice | Do | Don't |
|---|---|---|
| Base image | | |
| Copy files | | |
| User | | (run as root) |
| Install deps | | |
| Layer order | deps before source | source before deps |
| Secrets | | |
| Health | | (no health check) |
| Cache | | (leave cache) |