Docker Multi-Stage Builds for Smaller Images
A multi-stage build uses more than one FROM line in a Dockerfile. Earlier stages hold compilers and build tools, and only the final stage ships to production. The result is a smaller image with a smaller attack surface.
Here is a Go example that compiles in one stage and copies only the binary into a minimal base:
bash nano Dockerfile
dockerfile FROM golang:1.22 AS build WORKDIR /src COPY . . RUN CGOENABLED=0 go build -o /out/server .
FROM gcr.io/distroless/static COPY --from=build /out/server /server USER nonroot:nonroot ENTRYPOINT ["/server"]
Build and compare the sizes:
bash docker build -t shop-api:1.0 . docker images shop-api docker history shop-api:1.0
Some habits make builds faster and safer:
- Order instructions from least to most frequently changed, so dependency layers stay cached. - Add a .dockerignore file to keep .git and local secrets out of the build context. - Name the stage with AS build and reference it with --from=build. - Run as a non-root USER in the final image.
Use docker build --target build -t shop-api:debug . to stop at a named stage when you need to inspect the build environment.