Lesson 21: Advanced Dockerfile: Multi-Stage Builds
One common problem is that compiling code (e.g., Java, Go, React) requires large tooling images (SDKs, compilers, npm packages), but these tools are not needed in the final runtime environment.
The Problem: Bloated Images
If you compile a Go application in a standard Go image, the final resulting image will include the entire compiler toolchain and dependencies, making the image unnecessarily large.
The Solution: Multi-Stage Builds
Multi-stage builds allow you to define multiple FROM statements in a single Dockerfile. You copy only the necessary artifacts (the compiled binary or final static files) from the 'builder' stage to the final, lightweight 'runtime' stage.
Example: Building a Go Application
dockerfile
--- STAGE 1: Builder Stage ---
FROM golang:1.21-alpine AS builder
WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . .
Compile the static binary
RUN CGO_ENABLED=0 go build -o /app/my_app .
--- STAGE 2: Final Runtime Stage ---
Use a minimal image (alpine) which doesn't include the compiler
FROM alpine:latest
WORKDIR /root/
Copy only the compiled binary from the 'builder' stage
COPY --from=builder /app/my_app .
Define the final executable command
CMD ["./my_app"]
Benefits:
- Smaller Images: The final image is dramatically smaller because it only contains the executable and necessary OS libraries.
- Improved Security: Less attack surface because development tools are absent from the production image.