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.