Smaller images using multi-stage builds in Docker


Context

When building docker images, it is desirable to produce images as a smaller as possible. That brings a lot of different benefits, among others:

  • Less space used in the Container Registry and your local cache.
  • Less traffic network and wait time when deploying the image.

But the languages and frameworks usually require a lot of development dependencies, which increases the overall size of the image. A neat alternative then, is to take advantage of multi-stage builds

Implementation

For this example, let’s assume you are a building a golang project that produces a binary and that you have a standard Makefile that invokes the go build command under the hood, as shown below:

FROM golang:1.16 as builder

WORKDIR /app

COPY . .

RUN make build


FROM alpine:latest

COPY --from=builder /public/<binary_name> /usr/local/bin/

CMD ["<binary_name>"]

What makes this works is the COPY command, through the use of the --from option that allows to specify the source location to a previous build stage instead of the docker context sent by the user.

The above Dockerfile can be build as follows:

docker build -t binary:latest .

References

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer’s view in any way.