Multiarch docker builds
April 30, 2019
A quick look at the new docker tool set that makes building multiarch docker files simple.
Why build multiarch docker images?
Amazon Web Services announced their new A1 instance type re:Invent in 2018, which are based on 64bit arm architecture powered by the Graviton processor. Since then customers have been using A1 instances as a cheaper way to run work loads in EC2. There are now even more options to use the A1 instance as AWS has just announced support for the instance type with EKS, its Kubernetes service as a public preview. But in order for you to run docker workloads on the A1’s you needed to build docker images specifically for that architecture. It was possible to then have x86_64 and arm64 images in the same repo but you had to role manifest files by hand in order to to allow end users to pull the right version for their architecture. Things just go a lot easier with Dockers edge version of the docker desktop which takes advantage of cross compilation in QEMU.
How is this possible?
So let’s look at the new features in docker desktop, QEMU comes with a tool set binfmt_misc to run and build binaries of any supported architecture via emulation. In our case we want arm support, and specifically the arm64 version to run on the A1 instances. The tool chain will however support builds for, arm/v6, arm/v7 and arm64. Which means you can build containers for arm/v7 that will run on your raspberry pi at home. Docker desktop comes equipped with a new CLI command called buildx which allows you to build multi-arch images, link them together with a manifest file, and push it all to a registry, simply, efficiently and all from one command. So far I’m aware of this working on the edge docker desktop builds for OSX and Windows, I’m hoping to try linux support asap!
Putting this to work!
So we’ll dive a little deeper with the build process and workflow, the video below will show you how to use buildx and I’ve included some instructions to get you up and running.
Now let’s look at those commands, buildx has a few commands so let’s dive into some of them here:
docker buildx
Usage: docker buildx COMMAND
Build with BuildKit
Management Commands:
imagetools Commands to work on images in registry
Commands:
bake Build from a file
build Start a build
create Create a new builder instance
inspect Inspect current builder instance
ls List builder instances
rm Remove a builder instance
stop Stop builder instance
use Set the current builder instance
I’ve included a Dockerfile and some code here to get you started
If you are looking to just build for one particular platform the following commands will get you started, and you can see that QEMU will run it in emulation for you also!
docker buildx build .
docker buildx build --platform linux/arm64 --load .
docker images
docker inspect <SHA>
docker run <SHA> uname -m
Now if you are looking to use the full power of buildx and build a multiarch docker image then push to a docker hub repository this is where buildx really comes into its own.
Lets setup the environment and check we can compile for different architectures:
docker buildx create --name mybuilder
docker buildx use mybuilder
If you want to see what the environment can do run the following:
docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS
mybuilder docker-container
mybuilder0 unix:///var/run/docker.sock stopped
default * docker
default default running linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6
Now for the fun bit, let’s build for multiple architectures at the same time and push to docker hub. First create yourself a new docker hub repo that we can use as the target. The run the following commands on the cloned code I provided earlier.
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t <USER/REPO:TAG> --push .
docker buildx imagetools inspect docker.io/<USER/REPO:TAG>
You’ll see that buildx uses QEMU to build the images simultaneously and then automatically creates a manifest and pushes it to docker hub. This saves so much time to doing all these bits manually. To take a look at the manifest run the following and you’ll see three images in the manifest for different architectures.
docker buildx imagetools inspect richarvey/nginx-demo:latest
Name: docker.io/richarvey/nginx-demo:latest
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest: sha256:8b914bd551ea48016cb353a13d47f63d12317047a1b6f8565a4ca120aa7cb1f7
Manifests:
Name: docker.io/richarvey/nginx-demo:latest@sha256:59e1f33757604a84c637b9409cad7b692a3700f9426eec9a5918bed69b2ede6d
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/amd64
Name: docker.io/richarvey/nginx-demo:latest@sha256:9285415479bfe945cb77bec9a86638874be6d4aa860cc0392941a05b7a94affa
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/arm64
Name: docker.io/richarvey/nginx-demo:latest@sha256:4984cb8c605b94cb4087868563aa60e3df7f352b3daa3f51643f2be472fa6aa9
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/arm/v7
Now all thats left to do is spin up some A1 and x86_64 instances and use your normal work flow,
docker run -d -p 80:80 <USER/REPO:TAG>
If you exec into those containers you can even run uname -a to see that docker automatically pulls the right architecture type for what you are running on, making it super simple for end users no matter the platform. If you already have existing workloads in AWS take a look at the A1 instances to see how you can start saving now!