Skip to content

Instantly share code, notes, and snippets.

@StudioEtrange
Last active April 28, 2024 22:43
Show Gist options
  • Save StudioEtrange/ab9b118b778fac8e815c872826ed2cd8 to your computer and use it in GitHub Desktop.
Save StudioEtrange/ab9b118b778fac8e815c872826ed2cd8 to your computer and use it in GitHub Desktop.
Docker multi platform

Docker multi platform support

  • 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 using buildx.

  • DOC : https://docs.docker.com/build/building/multi-platform/

RUN multiplatorm images

INIT

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

    image

  • Install emulators :

    docker run --privileged --rm tonistiigi/binfmt -install all

  • List supported platforms :

    docker run --privileged --rm tonistiigi/binfmt

    image

  • 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
    

RUN

  • 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
    

BUILD multiplatorm images

BUILD using qemu

  • 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
      

BUILD using buildx builders

  • 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
      

      image

    • Build images with this builder :

      docker buildx build --builder buildx-container --platform linux/arm64,linux/amd64 --tag alpine:multi - <<'EOT'
      FROM alpine:latest
      EOT
      

      image

      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
      

      image

      docker buildx use default
      docker buildx ls
      

      image

    • 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 image

    • Inspect multi arch published image :

      docker manifest inspect studioetrange/alpine:multi
      docker buildx imagetools inspect studioetrange/alpine:multi
      

      image

  • Alternative - How to build multi arch image with docker build and docker manifest instead of buildx :

  • Alternative - Use a strategy of cross compilation instead of emulator :

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment