Course contentsShow
← Docker, Kubernetes & CI/CD
Lesson 114 of 8022. Docker Image LifecycleFree lesson

Implementing Multi-Stage Build Patterns

Separate build-time dependencies from the final runtime environment to ensure the production image contains only the necessary binaries and assets.

In this lesson, you will learn how to shrink your production images by separating the "construction site" from the "finished house."

The Problem: Heavy Baggage

When you build an application, you often need a suite of tools that are only useful during the build process. For example, to compile a C++ or Go application, you need compilers, build tools, and source code headers. However, once the binary is created, these tools are just dead weight. If you include them in your final image, you end up with a bloated container that is slower to push, pull, and potentially less secure due to the extra installed software.

The Solution: Multi-Stage Builds

Multi-stage builds allow you to use multiple FROM instructions in a single Dockerfile. Each FROM instruction begins a new stage of the build. You can perform your heavy lifting in an initial "build" stage and then simply copy the final artifact into a clean, minimal "runtime" stage.

Here is what that looks like in practice:

# Stage 1: The Builder (Install heavy compilers)
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o my-app main.go

# Stage 2: The Runtime (The final, slim image)
FROM alpine:latest
WORKDIR /root/
# Copy only the compiled binary from the builder stage
COPY --from=builder /app/my-app .
CMD ["./my-app"]

Why this matters

In this example, the first stage (golang:1.21) is several hundred megabytes, containing the full Go development environment. The second stage (alpine:latest) is a tiny Linux distribution. By using the COPY --from=builder instruction, we extract only the specific binary we need and discard everything else.

The final image will not contain the Go compiler, the source code, or the build cache. It will contain only your application and the bare minimum dependencies required to run it. This keeps your images lean, fast to deploy, and reduces the "attack surface" of your containers by removing unnecessary tools that an attacker could potentially use.

Key Takeaway: Multi-stage builds allow you to use heavy build environments to create your app, while ensuring only the essential runtime artifacts make it into your final production image.