Image for post
Image for post

Create the smallest and secured golang docker image based on scratch

C H
C H
Mar 1, 2018 · 7 min read

When we are building a docker Image, the first idea is using the default official image.

Dockerfile begin with :

There is an official Docker image for Go.

Ouch 803MB just for an empty image … this is crazy 😾

There is lightweight Alpine Docker image for Go.

Check the Alpine linux page for more informations.

This is smaller but too large for a production image with nothing

Use Multi-stage builds

Thanks to docker multi-stage builds, we can build our application in a docker alpine image an produce a small image with only a binary in a scratch image.

OK, it’s time to build a smaller image with multi-stage build

Before that we gonna see docker scratch image, a Zero Bytes image. Perfect for embedding our go static binary.

Oh cool only 21.2MB with everything i need for my go app.

But we can optimize it, by removing debug informations and compile only for linux target and disabling cross compilation.

With go < 1.10

With go ≥1.10

Now we have a small image only 13.6MB, almost ready for production

Let’s build a more secure docker image

Just some reminders :

OK, let’s do that with scratch image.

We have to create a new user on the builder image and copy the /etc/passwd and /etc/group file from the builder to te scratch image. Finally we can use unprivileged user “appuser” to launch the binary.

You can find a working example on github

Always pull image by digest

Using a trusted docker image like golang:alpine is not always enough for security. People can intercept your request to provide a modified docker image. The best solution : using digest (thks Patrik Iselind for this advice)

Always pull trusted image

Using a trusted docker image like golang:alpine is necessary.

Always export with port > 1024 as possible

OK, now we have a more secure image. But if we expose our docker with a port < 1024, we need some privileges for that.

OK so let’s expose always our binary with a port > 1024

Add SSL ca certificates

Perfect, but to be secure we need to expose our services with SSL isn’t it ?

By default scratch image is not provided with SSL CA certificates. But with multi-step we can provide it.

You can find a working example on github

Add zoneinfo for timezones

By default scratch image is not provided with zoneinfo for timezones. But with multi-step we can provide it.

You can find a working example on github

Go 1.11 Fetch dependencies with go mod

Go 1.11 includes preliminary support for versioned modules. If you want to know more about go mod you can see the doc.

GoogleContainer distroless

This is a very interesting base container named “distroless” from Google, there is a version for statically compiled applications like Go that do not require libc and contains :

  • ca-certificates
  • A /etc/passwd entry for a root user
  • A /tmp directory
  • tzdata

If you need to debug, the :debug image provides a shell “busybox”.

If you have any advice about security, please let me know :)

You can find a working example on github

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store