Docker Day 5: Multi‑Stage Builds and Build Caching for Smaller, Faster Images
This article shows how to shrink Docker images and speed up builds by using multi‑stage builds, ordering instructions for layer caching, fine‑tuning .dockerignore, merging RUN commands, picking lightweight base images, and running containers as a non‑root user, with concrete code examples and build‑time measurements.
Multi‑Stage Build
Problem: Front‑end project built with Node, production only needs Nginx.
Solution: Use a multi‑stage Dockerfile so the final image contains only the built assets.
FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/htmlRefactored version:
# Stage 1: build
FROM node:24-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: runtime
FROM nginxinc/nginx-unprivileged:alpine3.23-perl
COPY --from=builder --chown=nginx:nginx /app/dist /usr/share/nginx/html
USER nginx
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]Final image contains only Nginx, no Node.js.
Image size drops from ~1 GB to ~50 MB.
Runs as a non‑root user for improved security.
Build Cache Ordering
Docker caches each layer; unchanged instructions reuse the cache.
Correct order (low‑change instructions first):
# Copy rarely‑changed dependencies first
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Then copy source code which changes often
COPY . .Incorrect order (code changes invalidate dependency cache):
COPY . .
RUN pip install -r requirements.txtAdvanced .dockerignore
# Version control
.git
.gitignore
# Dependencies already installed in the image
node_modules/
__pycache__/
*.pyc
# Sensitive files
.env
*.pem
credentials.json
# Docs and large files
*.md
*.log
video/
# If using multi‑stage, you can also ignore the built dist folder
dist/Common Optimization Commands
Merge RUN statements to reduce layers
# Bad: many layers
RUN pip install fastapi
RUN pip install uvicorn
RUN pip install httpx
# Good: single command
RUN pip install fastapi uvicorn httpx
# Best: use a requirements file
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txtUse lightweight base images
python:3.12-slim– ~150 MB – production. python:3.12-alpine – ~50 MB – smaller & faster (compatibility trade‑off). node:24-alpine – ~50 MB – front‑end builds.
Real‑World Python Production Dockerfile
# syntax=docker/dockerfile:1
# Build stage
FROM python:3.12-slim AS builder
WORKDIR /app
# Cache dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
# Copy source
COPY . .
# Runtime stage
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
ENV PATH=/root/.local/bin:$PATH
# Create non‑root user
RUN addgroup -S app && adduser -S app -G app
# Copy code with correct ownership
COPY --chown=app:app . .
USER app
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]Build‑Time Comparison
No optimization – first build 3 min, rebuild 3 min.
Cache ordering – first build 3 min, rebuild 10 s.
Multi‑stage – first build 3 min, rebuild 10 s.
Alpine base image – first build 3 min, rebuild 10 s.
Day 5 Summary
Multi‑stage builds let you compile with a large image and ship a tiny runtime image.
Place low‑frequency instructions early to maximise layer caching.
Use a .dockerignore file to exclude irrelevant files from the build context.
Lightweight base images combined with a non‑root user produce production‑grade containers. nginxinc/nginx-unprivileged is the official non‑root Nginx image, listening on port 8080.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tech Ocean
Focused on AI programming, sharing ready-to-use development efficiency solutions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
