Best Practices
Container Images
Container Image Best Practices
Optimizing container images for security, performance, and build speed.
Image Layers & Caching
Docker images are built from layers. To maximize build speed, you should maximize cache hits by ordering your instructions generally from least frequently changed to most frequently changed.
Order of Instructions
- Base Image: Always pin your base image tag (e.g.,
FROM python:3.9-slim@sha256:...). - Dependencies: Copy dependency files (
requirements.txt,package.json) and install them before copying your source code. - Source Code: Copy your application source code last.
Bad Pattern:
COPY . .
RUN pip install -r requirements.txt
# Any change to source code invalidates the cache for pip installGood Pattern:
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
# Source code changes do not invalidate dependency layerMulti-Stage Builds
Use multi-stage builds to keep your final image minimal. Build your artifact in a heavy "builder" stage, and copy only the binary/assets to a light "runtime" stage.
# Stage 1: Builder
FROM golang:1.21 as builder
WORKDIR /app
COPY . .
RUN go build -o myapp main.go
# Stage 2: Runtime
# Distroless images are minimal and contain only the application and its runtime dependencies
FROM gcr.io/distroless/static:nonroot
COPY --from=builder /app/myapp /
CMD ["/myapp"]Rootless Containers (Build Time)
By default, Docker containers run as root. This is a security risk. You should create a non-root user in your Dockerfile and switch to it.
FROM python:3.9-slim
# Create a group and user
RUN groupadd -r myuser && useradd -r -g myuser myuser
# Set ownership of application files
WORKDIR /app
COPY . .
RUN chown -R myuser:myuser /app
# Switch to non-root user
USER myuser
CMD ["python", "app.py"]