NatronTech Logo
Best Practices

Container Images

Stage
Experimental
Requires

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

  1. Base Image: Always pin your base image tag (e.g., FROM python:3.9-slim@sha256:...).
  2. Dependencies: Copy dependency files (requirements.txt, package.json) and install them before copying your source code.
  3. 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 install

Good Pattern:

COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
# Source code changes do not invalidate dependency layer

Multi-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"]

On this page