how to build the smallest docker image as fast as you can
I’ll use an example to introduce how to build the smallest docker image to your best, a light image will accelerate image rollout and the fast build process will speed up your development cycle.
A Golang sample
It’s quite common that we use golang to implement microservice, for example tens of golang service docker images are deployed to the Kubernetes.
Consider we need to make our first golang service image, it runs the following code as an HTTP server.
1 | package main |
Docker it!
The intuitive solution is to run go run main.go
in the docker, so let’s use golang image as a base image.
1 | FROM golang:1.14.0-alpine |
Run docker build .
and it shows
1 | Sending build context to Docker daemon 3.072kB |
It’s 369193951 bytes near 370MB.
Reduce the unnecessary files
Golang is a compilation language which can be packed into a binary, we can reduce the size by only putting the binary into the image.
We know that the latest docker supports multi-stage builds which can eliminate the intermediate layers effectively, the revised dockerfile looks like this:
1 | FROM golang:1.14.0-alpine |
Let’s see the layers it generates.
1 | $ docker build . |
We could notice there are several intermediate containers removed, they’re layers from the first stage and prepare the executable for the second stage.
Most importantly, the docker image size is below 12MB.
The most important factor is we changed the FROM image to alpine which is only 4.2MB, so the extra size is almost the size of the golang process.
From scratch?
Yeah, the base image could be smaller, FROM scratch
is a base image that will make the next command to be the first layer in your image.
I changed the FROM alpine:latest
to FROM scratch
, the image size is 7MB now, but I would suggest using alpine because it’ll be hard for you in scratch if you want to debug within the container. So you’ll need a balance between the image size and functionality :)
Some pitfalls you may face
Unnecessary large build context
Docker build will send the build context to docker daemon at first, the context is default to the current directory, so please be sure the files in the current directory is necessary or is small enough. If the file size is big, it will affect docker build speed terribly.
Wrong command order
Just remember to put the stable layers before the changeable layers, because docker will cache the layers if they are not changed, it’s calculated by the hash value of their content.
1 | FROM ubuntu |
In the above example, every time the changeable.txt is changed, it will rerun every commands after it and waste time doing the things it could prevent. Just turn to the following form.
1 | FROM ubuntu |