Docker Community Forums

Share and learn in the Docker community.

How does docker engine pick the right image from multi-arch?

Hi,

I create my own multi-arch oci images via the yocto project.
This works pretty well for x86/64 and armv7 images.

e.g. I have here[1] an x86/64 and armv7 container which works for me both on various arm32 boards and on an x86/64 with docker.

[1] https://hub.docker.com/repository/docker/reliableembeddedsystems/oci-telegraf-prebuilt/tags?page=1

Please note that for my armv7 images I use those compiler tunes (I know it’s only SW floating point, but that runs on many boars).

TUNE_FEATURES        = "arm armv7a vfp neon"
TARGET_FPU           = "softfp"

On aarch64 things look differently:

for an i.mx8:

TUNE_FEATURES        = "aarch64 cortexa53 crc crypto"
TARGET_FPU           = ""

for a raspberrypi 64:

TUNE_FEATURES        = "aarch64 cortexa72 crc crypto"
TARGET_FPU           = ""

I would like to avoid building the same container for each aarch64 target and also I am not sure whether the docker engine would pick the right one.

  • *)How do you currently manage to build one container image which runs on multiple aarch64 boards?

  • *)How does the docker engine pick out the proper image in case of multi-arch images? Let’s say for performance reasons I would like to build optimized images per architecture some time in the future.

Download the latest version of Docker Desktop.

Follow the on-screen instructions to complete the installation process. After you have successfully installed Docker Desktop, you will see the Docker icon in your task tray.

Click About Docker Desktop from the Docker menu and ensure you have installed Docker Desktop version 2.0.4.0 (33772) or higher.

about-docker-desktop-buildx

Build and run multi-architecture images
Run the command docker buildx ls to list the existing builders. This displays the default builder, which is our old builder.

$ docker buildx ls

NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS
default * docker
default default running linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6
Create a new builder which gives access to the new multi-architecture features.

$ docker buildx create --name mybuilder

mybuilder
Alternatively, run docker buildx create --name mybuilder --use to create a new builder and switch to it using a single command.

Switch to the new builder and inspect it.

$ docker buildx use mybuilder

$ docker buildx inspect --bootstrap

[+] Building 2.5s (1/1) FINISHED
=> [internal] booting buildkit 2.5s
=> => pulling image moby/buildkit:master 1.3s
=> => creating container buildx_buildkit_mybuilder0 1.2s
Name: mybuilder
Driver: docker-container

Nodes:
Name: mybuilder0
Endpoint: unix:///var/run/docker.sock
Status: running

Platforms: linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6
Test the workflow to ensure you can build, push, and run multi-architecture images. Create a simple example Dockerfile, build a couple of image variants, and push them to Docker Hub.

$ mkdir test && cd test && cat < Dockerfile

FROM ubuntu
RUN apt-get update && apt-get install -y curl
WORKDIR /src
COPY . .
EOF
$ docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t username/demo:latest --push .

[+] Building 6.9s (19/19) FINISHED

=> => pushing layers 2.7s
=> => pushing manifest for docker.io/username/demo:latest 2.2
Where, username is a valid Docker username.

This explains the steps how to build multi arch containers with “docker buildx create” - as a black box. I saw this, but don’t like to use black boxes for many reasons.
There is the open container initiative (oci) which is supported by docker, and I find it more generic.

Can you please explain what happens behind the scenes of “docker buildx create”?

Say you have a hello-world.c and not ready made packages and would like to put this into a container. What compiler tune options are used to compile it?

I can build (in a totally different way) multi arch images like this one[1] mentioned above. I use oci images, which don’t depend on the docker infrastructure to be built and happen to use docker engine to run them (but could use something else as well).

[1] https://hub.docker.com/repository/docker/reliableembeddedsystems/oci-telegraf-prebuilt/tags?page=1

What are the compiler tune flags used?

As you see you have only one option for linux/arm64 and linux/arm/v7 with this approach.

I built different linux/arm64 images for imx8 and raspberrypi 4.

Also I can potentially build for each armv7 a different image with different compiler tune flags.

What’s the mechanism of the docker engine to pick the right one up?