How to Build Multi-Arch Docker Images for MacBook M1

At work, I currently use a MacBook Pro with an Intel chipset and some of my colleagues have upgraded to ones with M1 chipset which is of arm64 or aarch64 architecture. Then expectedly I need to build some Docker images for both architectures.

I’ve done some multi-arch Docker stuff before so this is not really a challenge. But there’s still something learned in the process.

There are some useful Docker environment variables for multi-arch purposes:

  • BUILDPLATFORM as the name suggests it has the platform name of the host. So if I build stuff with an Intel or AMD platform this variable will be set to linux/amd64
  • TARGETPLATFORM is a combination of TARGETOS, TARGETARCH and TARGETVARIANT, and is set from the --platform=linux/amd64 switch such as docker buildx build --platform=linux/amd64 .
  • TARGETOS usually is just linux. I won’t touch Windows containers 🙂
  • TARGETARCH can be amd64 or arm64. For M1 MacBook this should be arm64
  • TARGETVARIANT could be v7 or v8 but I don’t think this is as useful as the first 2.

The environment variables above are very useful in a multi-arch Dockerfile, for example, to install a platform specific JDK version:

# example from Dockerfile for Elasticsearch
FROM centos:8 AS builder
ENV PATH /usr/share/elasticsearch/bin:$PATH
ENV JAVA_HOME /opt/jdk-15.0.1+9

# install platform specfic openJDK
         "linux/amd64")  JDK_ARCH=x64  ;; \
         "linux/arm64")  JDK_ARCH=aarch64  ;; \
    esac && \
    for iter in {1..10}; do curl -L -s -S${JDK_ARCH}_linux_hotspot_15.0.1_9.tar.gz | tar -C /opt -zx && \
    exit_code=0 && break || exit_code=\$? && echo "download error: retry $iter in 10s" && sleep 10; done; \
    (exit $exit_code)

Then the Dockerfile can be used in a docker buildx command such as

docker buildx build --platform linux/amd64,linux/arm64 -t my.registry/image-name:tag --push .

The result docker image should be able to run as native architecture (arm64) on a M1 MacBook. 🙂