Larry Myers

Cover Image for Multi-Platform Docker Images

Multi-Platform Docker Images

I recently replaced my 16” i7 MacBook Pro with the 14” M1 Pro model. It’s instantly become one of my favorite laptops I’ve ever owned (the 2nd being my iBook G4 from almost 20 years ago). I vaguely knew I’d have to do some different things for a development environment on an arm64 architecture, the main issue being running Docker containers.

Docker supports Docker Desktop for Apple Silicon, but if you rely on Docker images that only have a linux/amd64 (i.e. x86) build you’ll quickly notice that everything runs significantly slower than you’re used to. Being able to build and publish multi-platform images allows running Docker containers on M1 Macs without any emulation required.

You’d be surprised how many public images on Docker Hub don’t have a multi-platform build, so being able to build your own is necessary if you don’t want to suffer the performance penalty imposed by x86 emulation.

The instructions below are a distilled verison of the multi-platform documentation provided by Docker.

Setup Docker buildx

If you intend to publish docker images you’ll need to setup buildx, which allows the docker engine to build multi-platform images.

> docker buildx create --name multi-platform --driver docker-container --bootstrap --use
> docker buildx ls

NAME/NODE         DRIVER/ENDPOINT             STATUS  BUILDKIT PLATFORMS
multi-platform *  docker-container
  multi-platform0 unix:///var/run/docker.sock running v0.10.5  linux/arm64, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
default           docker
  default         default                     running 20.10.20 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
desktop-linux     docker
  desktop-linux   desktop-linux               running 20.10.20 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

Updating your Dockerfile

You’ll also need to update any Dockerfile that installs software without a package manager (i.e. without using apt or yum). If you look at the Dockerfile for popular images on Docker Hub you’ll notice the same pattern, which is to use a bash case statement to set the current architecture for the build.

A simple example for building a Go image:

arch="$(dpkg --print-architecture)"
case "$arch" in
  'amd64')
    url="https://dl.google.com/go/go1.19.3.linux-amd64.tar.gz";
    sha256="74b9640724fd4e6bb0ed2a1bc44ae813a03f1e72a4c76253e2d5c015494430ba";
    ;;
  'arm64')
    url="https://dl.google.com/go/go1.19.3.linux-arm64.tar.gz";
    sha256="99de2fe112a52ab748fb175edea64b313a0c8d51d6157dba683a6be163fd5eab";
    ;;
  *) echo >&2 "error: unsupported architecture: $arch"; exit 1 ;;
esac

Create Multi-Platform Images

Finally use buildx to build and publish multi-platform images. You can inspect the published image afterwards and see the support architectures in the manifest for the image.

docker buildx build \
--platform=linux/amd64,linux/arm64 \
-t my-image:latest \
--push \
.

docker buildx imagetools inspect my-image:latest

The end result is a docker image that you can use on your Mac locally, as well as for deployment on Linux hosts using x86 processors.