All skills
Skillintermediate

Dockerfile Best Practices

| Practice | Why | |----------|-----| | Order by change frequency | Rarely-changing layers first (base, system packages), frequently-changing last | | Combine related RUN commands | Reduces layers and ensures cache coherence | | Clean up in same layer | Don't leave apt cache in a layer | | Use multi-stage builds | Separate build dependencies from runtime, reduce final image size | | Pin versions w

Claude Code Knowledge Pack7/10/2026

Overview

Dockerfile Best Practices

Quick Reference

PracticeWhy
Order by change frequencyRarely-changing layers first (base, system packages), frequently-changing last
Combine related RUN commandsReduces layers and ensures cache coherence
Clean up in same layerDon't leave apt cache in a layer
Use multi-stage buildsSeparate build dependencies from runtime, reduce final image size
Pin versions with digestsSupply chain security: FROM alpine:3.21@sha256:abc123...
Switch to non-root user lastDo root operations first, then USER vscode
Use COPY over ADDADD has extra features you usually don't need
Use .dockerignoreExclude build-irrelevant files to reduce context size

Base Image Selection

Choose minimal, trusted base images:

  • Docker Official Images - curated, documented, regularly updated
  • Alpine Linux - under 6 MB, tightly controlled
  • Verified Publisher or Docker-Sponsored Open Source images

Pin images to specific digests for reproducible builds:

FROM alpine:3.21@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c

Avoid latest tag - it can change unexpectedly and cause breaking builds.

apt-get Best Practices

Always combine update with install in the same RUN statement:

RUN apt-get update && apt-get install -y --no-install-recommends \\
    curl \\
    git \\
    vim \\
    && rm -rf /var/lib/apt/lists/*

Why combine? Keeping them separate causes Docker to cache the update layer, potentially installing outdated packages on subsequent builds.

Best practices:

  • Use --no-install-recommends to minimize installed packages
  • Sort packages alphabetically within each section for easier maintenance and PR reviews
  • Clean up with rm -rf /var/lib/apt/lists/* in the same layer

Pipe Safety

When using pipes, prepend set -o pipefail && to fail if any command fails:

RUN set -o pipefail && curl -fsSL https://example.com/install.sh | bash

Without this, a failed curl would be masked by a successful bash.

Environment Variables

Use ENV for paths, versions, and configuration:

ENV PYTHON_VERSION=3.13
ENV PATH=/home/vscode/.local/bin:$PATH

Note: ENV instructions add metadata, not filesystem layers like RUN. Multiple separate ENV lines are fine and often more readable than combining them.

WORKDIR

Always use absolute paths. Avoid RUN cd ... && command patterns:

# Good
WORKDIR /app
RUN make install

# Bad
RUN cd /app && make install

Architecture Support

The templates support both AMD64 and ARM64 (Apple Silicon) automatically. Use TARGETARCH build arg for architecture-specific downloads:

ARG TARGETARCH
RUN curl -fsSL "https://example.com/tool-${TARGETARCH}.tar.gz" | tar xz

Devcontainer-Specific Tips

Resource allocation: Docker Desktop has limited defaults. Increase CPU/Memory in Docker settings for resource-intensive builds. Windows/WSL2: Use Docker Desktop's WSL 2 backend for better file sharing performance.

Sources