DevOps Intermediate
Docker Multi-stage Builds¶
DockerContainerizationOptimization 6 min read
Optimizing Docker images with multi-stage builds. Smaller images, faster deploys, more secure containers.
Why Multi-stage¶
A classic Dockerfile includes build tools even in the production image. Multi-stage builds separate the build and runtime phases.
- Smaller final image (100 MB vs 1 GB)
- No build tools in production
- Faster pull and deploy
- Smaller attack surface
Example: Go Application¶
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server ./cmd/server
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /app/server /server
USER nonroot:nonroot
EXPOSE 8080
ENTRYPOINT ["/server"]
Resulting image: ~10 MB instead of ~800 MB with the full Go SDK.
Example: Node.js¶
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
RUN addgroup -g 1001 -S nodejs && adduser -S nextjs -u 1001
COPY --from=deps /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
USER nextjs
EXPOSE 3000
CMD ["node", "dist/main.js"]
Best Practices¶
- Use
.dockerignore— exclude node_modules, .git, docs - Order COPY commands from least to most frequently changed
- Use
--mount=type=cachefor caching build dependencies - Pin base image versions (not
:latest) - Scan the final image:
trivy image myapp:latest
Summary¶
Multi-stage builds are the foundation of modern containerization. Separating the build and runtime phases dramatically reduces image size and improves security.
Need Help with Implementation?¶
Our team has experience designing and implementing modern architectures. We’re happy to help.