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/multiThis 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.