Using Docker buildx for native multiarch builds.
I wanted to build multiarch images using multiple machines with different architectures instead of QEMU.
# add some amd64 machine that has docker docker context create bob --docker "host=ssh://email@example.com" # create a buildx builder with your local machine added to it docker buildx create \ --name multiarch --node arm64 \ --platform linux/arm64/v8 \ default # add the amd64 machine to it docker buildx create --append \ --name multiarch --node amd64 \ --platform linux/amd64,linux/amd64/v2,linux/386\ bob # build & push your image docker buildx build \ --builder multiarch \ --platform linux/amd64,linux/arm64/v8 \ --push --tag username/imagename . # the amd64 image will be build natively on the amd64 machine, # the arm64 machine will be build natively on the arm64 machine
I wanted to build a multiarch image for
linux/amd64, however the
x86 builds were really slow when running through QEMU on my Apple Silicon laptop. Turns out, you can tell Docker to use another machine (which happens to be
x86_64), to build the
linux/amd64 images, and use the local Docker Desktop instance for the ARM stuff.
Set up Docker on a machine (or many machines) that supports the architecture(s) you want to build for. Make sure you can SSH into it without using passwords (use SSH keys, and maybe ssh-agent if keys don’t work on their own).
Also, the user you’re SSH-ing into needs to be able to access Docker.
Create a Docker context for the remote machine.
docker context create <context_name> --docker "host=ssh://<USER>@<HOST>:<PORT>"
<USER>@can be omitted - your local username will be used.
:<PORT>can also be omitted if it’s
Let’s say we have an
amd64host on ip
10.0.0.2, and we want to call it bob (the builder).
docker context create bob --docker "host=ssh://firstname.lastname@example.org"
Create a buildx builder for your local computer.
In this case, my local machine supports
linux/arm64/v8natively, but it also can build
amd64images through QEMU, so I explicitly set
linux/arm64/v8. I might also add
linux/arm/v7for images meant to run on something like a Raspberry Pi here, because even though it will still run via QEMU, I don’t have anything better to build for
armv7anyway. (it’s comma separated)
docker buildx create \ --name multiarch --node arm64 \ --platform linux/arm64/v8 \ default
multiarchwill be the name of our builder,
--nodeis the name for the node we’re adding to the builder (it doesn’t have to contain the architecture, it can be anything, only the
--platformvalue is taken into consideration by Docker).
defaultis the name of the default context, which usually is your local machine. If not, replace it with whatever you use.
Now, the fun part - add additional nodes for other architectures! In our example, we want to add
bobwhich can build
docker buildx create --append \ --name multiarch --node amd64 bob
--append- it tells Docker to add the node to an existing builder.
--platformhere, because in my case,
bobonly supports x86 anyways, so I don’t have to limit it artificially. This was different for the local node, as Docker Desktop on MacOS comes with cross-platform build support preconfigured.
Set the builder as default (optional, you can use
docker buildx buildto set the builder manually)
docker buildx use multiarch
Finally, you can build your images:
docker buildx build \ --platform linux/amd64,linux/arm64/v8 \ --push --tag username/imagename .
Unfortunately, it’s not yet possible to load multiarch images into your local Docker daemon, which means you’re gonna have to tag and
--pushto the Docker registry.
You can still use
--push(to load into your local daemon) if you only specify a single
--platform. Idk, might be useful for testing or something.