Recently at work I have been struggling with building a small/minimized Docker container of a Go app I have been working on. I started with busybox
but it has a major short coming… CA certificates. It isn’t trivial to get CA Certs on a busybox
container. This problem effectively prevents you from using SSL or TLS with your app… This is a non-starter…
Enter Alpine
I was doing some reading and I have seen a couple articles mention Alpine, its effectively a slimmed down version of busybox
but it makes it trivially easy to install packages, in my case CA Certificates! At this point I was really excited but I ran into some issues trying to compile the binary.
Solution
The solution is actually pretty simple, you need to build your Go app inside of a container and then copy the built container to your “production” Alpine image.
My solution uses the Makefile
, there is different ways of doing this but this is the simplest.
The first addition to the Makefile
is the following.
|
|
The above is intended to be run inside of a container but you can run it anywhere. What it does is builds a binary that is statically linked with CGO disabled so it uses the statically linked cgo binary on in the container. This is important as Alpine uses a custom lightweight subset of glibc called libc
.
The next stanza you need for your Makefile
actually builds two containers. One is your build container based on the golang
image and then copies the binary to your Alpine
container.
|
|
To make the above work you need two Docker files. They are below…
Note the following is assuming your depencies are already downloaded, I do this with a make task, make deps
.
|
|
This is nice/elegant as you don’t have to run this in the container so if you have private repo’s you don’t need to copy in ssh keys or GitHub tokens to download source code. Just make sure your don’t have a .dockerignore
file as things in that file won’t be copied over…
Dockerfile.build
|
|
Dockerfile
|
|
The above assumes your binary is named the same as your project name.
The magic in Dockerfile
is the ability to install the CA certs with a single command.
Gotchas
The only issue with disabling CGO is that some functionality in go requires it, most notably is from the os/user
package, the function user.Current()
makes use of it to determine a user’s home directory. You might get an error like the following…
|
|
The Apache Mesos project ran into this, you can see their solution. Their solution does a shortcoming though with their looping… Check out my change in the Go library for IBM Softlayer. The pull PR is available here.
Please follow me on Twitter at @jsloyer and follow me on Youtube!