-
Docker images support multiple platforms. When you run an image with multi-platform support, Docker automatically selects the image that matches your OS and architecture.
-
About local images storage : The default image store in Docker Engine do not separate image by platform type. Each image:tag erase the previsous one, independently of its image type To solve that you can enable the containerd image store by modifing daemon.json (https://docs.docker.com/storage/containerd/)
-
About BuildKit : BuildKit is enabled by default on Docker Engine >= 23.0. If not enabled, you may activate BuildKit which is a better docker build engine, with
export DOCKER_BUILD=1
or by modifying/etc/docker/daemon.json
with"features": {"buildkit" : true}
. It is not a requirement for basic multi platform support, but it is a requirement when usingbuildx
. -
DOC : https://docs.docker.com/build/building/multi-platform/
Usage of tonistiigi/binfmt
allow to trigger qemu emulators when using --platform
option. tonistiigi/binfmt
image contains binfmt and qemu (see https://github.com/tonistiigi/binfmt)
If you do NOT init emulators : when you will use --platform
with an arch diffrent from the host, you will get an exec error. But if you specify the same arch than the host, everything will work fine without init any emulator.
-
List of
tonistiigi/binfmt
components versions :docker run --privileged --rm tonistiigi/binfmt -version
-
Install emulators :
docker run --privileged --rm tonistiigi/binfmt -install all
-
List supported platforms :
docker run --privileged --rm tonistiigi/binfmt
-
Github workflow : If needed to install emulators from inside a github workflow use setup-qemu-action
jobs: your-job-name: steps: - name: Set up QEMU arm emulator if we are on a x86 runner if: ${{ runner.arch == 'X86' || runner.arch == 'X64' }} id: qemu-arm64 uses: docker/setup-qemu-action@v3 with: image: tonistiigi/binfmt:latest platforms: linux/arm64 - name: Set up QEMU amd64 emulator if we are on an arm runner if: ${{ runner.arch == 'ARM64' }} id: qemu-x86_64 uses: docker/setup-qemu-action@v3 with: image: tonistiigi/binfmt:latest platforms: linux/amd64
-
These tests launch image for linux/amd64 and should print
x86_64
:docker run -it --rm --platform linux/amd64 alpine:latest uname -m docker run -it --rm --platform linux/amd64 ubuntu:latest uname -m DOCKER_DEFAULT_PLATFORM=linux/amd64 docker run -it --rm alpine:latest uname -m
-
These tests launch image for linux/arm64 and should print
aarch64
:docker run -it --rm --platform linux/arm64 alpine:latest uname -m docker run -it --rm --platform linux/arm64 ubuntu:latest uname -m DOCKER_DEFAULT_PLATFORM=linux/arm64 docker run -it --rm alpine:latest uname -m
-
First, do the INIT section about
tonistiigi/binfmt
above -
About local images storage : The default image store in Docker Engine do not separate image by platform type. So in theses tests, we use the tag of the image to separate platform type.
-
This test build an image for linux/amd64 and run it and should print
x86_64
:docker build --platform linux/amd64 --tag alpine:foo-amd64 - <<'EOT' FROM alpine:latest EOT docker run -it --rm --platform linux/amd64 alpine:foo-amd64 uname -m
-
This test build an image for linux/arm64 and run it and should print
aarch64
:docker build --platform linux/arm64 --tag alpine:foo-arm64 - <<'EOT' FROM alpine:latest EOT docker run -it --rm --platform linux/arm64 alpine:foo-arm64 uname -m
-
-
Create a new builder using the
docker-container
driver allow to more complex features like simultaneous multi-platform builds and the more advanced cache exporters.-
Create a builder with
docker-container
driver :docker buildx create --name buildx-container --driver docker-container --driver-opt network=host --bootstrap docker buildx ls
-
Build images with this builder :
docker buildx build --builder buildx-container --platform linux/arm64,linux/amd64 --tag alpine:multi - <<'EOT' FROM alpine:latest EOT
Note : those images does not automatically appear in docker images when using docker-container driver.
-
Set default / remove builder :
docker buildx use buildx-container docker buildx ls
docker buildx use default docker buildx ls
-
Remove builder :
docker buildx rm buildx-container
-
-
buildx build images in a cache and we have to publish image with a generated manifest to a registry that supports multi arch images, like DockerHub
-
Publish an image and its manifest - Need an account on DockerHub :
docker login -u studioetrange -p password docker buildx build --builder buildx-container --platform linux/arm64,linux/amd64 --tag studioetrange/alpine:multi --push - <<'EOT' FROM alpine:latest EOT
Note :
--push
will generate manifest AND push image to DockerHub -
Inspect multi arch published image :
docker manifest inspect studioetrange/alpine:multi docker buildx imagetools inspect studioetrange/alpine:multi
-
-
Alternative - How to build multi arch image with
docker build
anddocker manifest
instead ofbuildx
: -
Alternative - Use a strategy of cross compilation instead of emulator :