This gist demonstrates how to build cross-architecture docker images in 2019. While go
has been awesome at cross compiling since ever, docker support really lacked behind.
This changed with the advent of buildkit
: Just by specifying --platform
, we can build one and the same Dockerfile for every supported architecture, as long as the buildkit executor is capable of this arch. However, qemu
is a great help here. By running sudo apt install binfmt-support
and sudo docker run --privileged linuxkit/binfmt:v0.6
, your amd64
PC is now capable of executing nearly every available linux binary like magic.
We can now use this to build this image using img or any other buildkit wrapper:
$ img build --platform=linux/arm/v7 --platform=linux/arm64 --platform=linux/amd64 -t shorez/multi .
$ img push shorez/multi
This leaves us with a perfect fat manifest v2
image, ready to be pulled using docker pull shorez/multi
. The correct version for the arch will be selected automatically.
This Dockerfile
is fairly different from traditional ones, because the new --platform
support from buildkit or docker 19.03+ is used. An short explanation:
Imagine this build is called using --platform=linux/arm64
. This means, buildkit is now going to pull golang:1.12-alpine
, but soon discovers it needs the arm version, so it pulls this one. It then saves GOARCH
and GOARM
to a file for later use. This is required, because the format of these two diverts from what docker uses to distinguish arch
.
The next stage is always going to run as amd64
. Here happens the actual go build
. It is amd64
, because it is not possible to compile go on qemu. No problem, go is capable of cross compiling itself.
The final stage is going to run as arm64
again. In this case this does not matter, as there is no RUN
. But there could certainly be one.