TL;DR
Dockerize your golang
app easily with the new multi-stage builds from Docker 17.05. Reduce deployment steps and produce smaller, optimized builds.
Audience:
- 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
References:
- The example can be found in the Github repo here
Highlights
- 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
Guide
Setup
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 golang program
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!
Method 1: Using the Golang image
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…
Method 2: Build locally
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.
Method 3: Using multi-stage build
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
Originally published at gist.github.com.