Multi-Stage Docker Builds for Creating Tiny Go Images

I’ve talked about how to make tiny Docker images a fair bit in the past, but now that Docker has multi-stage builds, it’s time to revisit the topic. In the past, we had to build the binary in one step, then take the results and build the docker image in another step. It was a bit annoying and confusing and required a bit of trickery. Let’s see if multi-stage builds make things better.

NOTE: this requires Docker 17.05 or later.

Let’s start with a simple Go program:

And build it using the golang:alpine image in a single-stage build. Here’s the Dockerfile:

Now let’s build it and run it:

docker build -t treeder/hello .
docker run --rm treeder/hello

Ok, works fine, but let’s look at the size with docker images | grep treeder/hello .

258 MB, just for our single little Go binary. Now let’s try a multi-stage build using this new Dockerfile:

Let’s build and run it again:

docker build -t treeder/hello .
docker run --rm treeder/hello

And check the size:

6.35 MB. Much better.

What does this mean? It means that multi-stage builds are awesome. And you should almost always use them!