Skip to content

Docker multi-architecture builds

If you download an image from the Docker Hub library, it’s likely to be available for multiple architectures. If you pull it from an AMD / Intel 64 bit machine, you’ll get the amd64 architecture image. If you pull it from an ARM based machine (including Apple Silicon), you’ll get the arm64 based image. Typically when you build a custom image, you’ll build for your own architecture only. Docker multi-architecture builds however allow you to build for multiple target architectures.

Image manifest

Docker images have a manifest detailing (among other things) the target architecture for the image:

docker manifest inspect --verbose hotblac/uname_arch_x86:latest 
{
	"Ref": "docker.io/hotblac/uname_arch_x86:latest",
	"Descriptor": {
		"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
		"digest": "sha256:17937994d8c47e9b630c19923f818dd1086a47fb76e36960a001c9b7a48fa9cf",
		"size": 734,
		"platform": {
			"architecture": "amd64",
			"os": "linux"
		}
	},

Multi-architecture images on the other hand contain a list of manifests. When you pull the image, your client selects the manifest and image matching your architecture.

docker manifest inspect --verbose alpine:latest 
[
	{
		"Ref": "docker.io/library/alpine:latest@sha256:1c4eef651f65e2f7daee7ee785882ac164b02b78fb74503052a26dc061c90474",
		"Descriptor": {
			"mediaType": "application/vnd.oci.image.manifest.v1+json",
			"digest": "sha256:1c4eef651f65e2f7daee7ee785882ac164b02b78fb74503052a26dc061c90474",
			"size": 1022,
			"platform": {
				"architecture": "amd64",
				"os": "linux"
			}
		},
		...
	
{
		"Ref": "docker.io/library/alpine:latest@sha256:757d680068d77be46fd1ea20fb21db16f150468c5e7079a08a2e4705aec096ac",
		"Descriptor": {
			"mediaType": "application/vnd.oci.image.manifest.v1+json",
			"digest": "sha256:757d680068d77be46fd1ea20fb21db16f150468c5e7079a08a2e4705aec096ac",
			"size": 1025,
			"platform": {
				"architecture": "arm64",
				"os": "linux",
				"variant": "v8"
			}
		},

If we want to create Docker multi-architecture builds, we’ll need to create this manifest list and push to our repository.

docker manifest command

The docker manifest command supports manual creation of manifest lists. You can create a manifest list with docker manifest create and then push it to your repository with docker manifest push:

docker manifest create \
your-username/multiarch-example:manifest-latest \
--amend your-username/multiarch-example:manifest-amd64 \
--amend your-username/multiarch-example:manifest-arm32v7 \
--amend your-username/multiarch-example:manifest-arm64v8
docker manifest push your-username/multiarch-example:manifest-latest

This assumes that you’ve already built images for every architecture you support. Building for each architecture is still your responsibility. You’ll likely need a build server for each architecture. Unless you’ve got a sophisticated managed build environment, this will likely be difficult. You’ll certainly find it difficult to create Docker multi-architecture builds from your laptop in this way.

Build with docker buildx

If you want to create Docker multi-architecture builds from a single build server (or an ordinary laptop), you’ll need docker buildx. docker buildx virtualises your build environment so that you can create Docker builds for architectures different from the build server / laptop architecture. docker buildx also takes care of manifest creation so this is usually the easiest way to create Docker multi-architecture builds.

It requires very specific environment setup though. There’s an excellent tutorial on Eddies in Entropy detailing what you need and why. I’ll skip the detail and show you how I set this up on my Ubuntu 22.04 (Jammy) laptop. I’ve tried this on other Linux distros and had difficulty. I ended up creating an Ubuntu 22.04 VM just as a build server for my Docker multi-architecture builds.

You’ll need a recent version of Docker (19.03 or later is fine).

sudo apt-get remove containerd.io docker-buildx-plugin
sudo apt-get install -y docker.io

You’ll also need to install buildx, qemu (for virtualisation) and binfmt (for non-native architecture support):

sudo apt-get install -y docker-buildx qemu-user-static binfmt-support

After buildx is installed, tell Docker to use it for builds:

docker buildx create --name multiarch-builder
docker buildx use multiarch-builder

All being well, you can now create and push Docker multi-architecture builds like so:

docker login -u hotblac
docker buildx build --push --platform linux/amd64,linux/arm64 --tag hotblac/uname_arch:latest .

Here, hotblac is my username on hub.docker.com, linux/amd64 and linux/arm64 are the architectures I want to target and uname_arch:latest is the name of the image I want to build.

If you’re using buildx, you must push to a repository. You cannot just build to your local machine. That’s because buildx builds in a buildkit container, not directly on your laptop. You can of course pull the image back to your laptop after building.

After pushing to hub.docker.com, I can see it in my repo with both architectures listed:

hotblac/uname_arch image on hub.docker.com showing Architecture: amd64, arm64

I can pull it and run from my AMD laptop:

docker pull hotblac/uname_arch
docker run --rm hotblac/uname_arch cat /arch

Shows container running on a AMD / x86_64 architecture

I can also run it from a ARM machine:

sudo docker run --rm hotblac/uname_arch cat /arch
Running on ARM architecture

As you can see, the multi-architecture image is completely transparent to the user. They just use the regular docker pull / docker run command and the Docker engine takes care of selecting the right image.

Published inDocker

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *