Multi-Stage Docker build for Go
Dockerize your golang
app easily with the new multi-stage builds from Docker 17.05. Reduce deployment steps and produce smaller, optimized builds.
- You want to know how to Dockerize your
Golang
app - You want your Docker image to be as small as possible
- You want to know how multi-stage docker build works and the pros
- The example can be found in the Github repo here
- You will first build a docker image using only the
Docker
golang base image, and observe the outcome. For simplicity, our program will just output ”hello, go” - Then, you will learn how to build a more optimized docker image, but requires separate commands
- Finally, we will demonstrate how multi-stage build can simplify our process
You need to have golang
and a minimum version of docker 17.05
installed in order to run this demo. You can check the version of your dependencies as shown below:
Validating go version:
https://gist.github.com/5e74c2ee01840a350ef720e7db5346d5
Validating Docker version: https://gist.github.com/36417cafdeda115742b0fdde99361c0e
The main.go
contains our application logic. It does nothing but print Hello, go!
.
https://gist.github.com/f3f011ab9f1567f766c394d5812c3ac3
Now that we have our application, let’s dockerize it!
The steps in Dockerfile.00
is as follow:
- We select the
golang:1.9
image - We create a workdir called hello-world
- We copy the file into the following directory
- We get all the dependencies required by our application
- We compile our application to produce a static binary called
app
- We run our binary https://gist.github.com/e05ad186f077213da49b5253f00a32eb
Let’s build an image called alextanhongpin/hello-world-00
out of it. You can use your Github username instead when building the image.
https://gist.github.com/5257c56e80e3587806c36a7afb41c90b
We will run our docker image to validate that it is working: https://gist.github.com/04f18d7ebd5f32d5a9f3c5d61d8ccf8a
Let’s take a look at the image size that is produced: https://gist.github.com/aeae060a1d869dc74aa71e2374fdeb86
We have a 729MB
image for a simple Hello, go!
! What can we do to minimize it? That brings us to next step…
The reduce the size, we can try to compile our main.go
locally and copy the executable to an alpine image — the size should be smaller since it contains only our executable, but without the go runtime. Let’s compile our main.go
:
https://gist.github.com/b0a0887082b43d104b42164c6aca378d
Dockerfile.01
contains the step to build our second image:
https://gist.github.com/9bbd19a6dfb4f7bdf5e97d157142e38d
All it does is copy our compiled binary to an alpine image. We will build the image with the following command: https://gist.github.com/93ddcb0bfec31964a52e347f778e4d9b
Let’s validate it again as we did before and view the change in the size: https://gist.github.com/7bfdd2df17150aac0f79af12d8f28ced
Let’s take a look at the image size: https://gist.github.com/57b7a974f5650e4ae796b43d77aba22d
We can see that the size has reduced dramatically from 729MB
to 6.55MB
. This however, involves two different step — compiling the binary locally and create a docker image. The next section will demonstrate how you can reduce this to a single step.
Multi-stage buil is a new feature in Docker 17.05 and allows you to optimize your Dockerfiles. With it, we can reduce our build into a single step. This is how our Dockerfile
will look like:
https://gist.github.com/a730a9bc81d798de806b827191a14379
Let’s build and observe the magic: https://gist.github.com/7327de52ef39e5eeff4df0b73a0d4a36
https://gist.github.com/2a1285794fd911404692f187c3cb7156
You can now build your golang image in a single step. The output is shown below: https://gist.github.com/77dde3e92d1ad6a39ce2092881fa8e93