Build multi-architecture images in Azure DevOps

I am migrating everything to a new Raspberry Pi cluster and need to build multi-architecture images through an Azure DevOps pipeline. Here is how I did it.

I am migrating everything to a new Raspberry Pi cluster and need to build multi-architecture images through an Azure DevOps pipeline. Here is how I did it.

In Azure DevOps, the built-in tasks don't allow building multi-architecture images, like linux/arm64 for the Raspberry Pi (or other 64-bit ARM based processors) and linux/amd64 for regular x86 based computer.

Azure DevOps users

As it turns out, this was simple. Do not use the built-in Docker steps. They only support a subset of the Docker CLI. The ability to build multi-arch images is already built into Docker and the hosted agents run a new enough version so it is baked in.

First you will need to manually log in to your registry. You can use the built-in Docker step for that so you can use the nice service connection ability.

The next step, install in the arm64 QEMU emulator, docker run --privileged --rm tonistiigi/binfmt --install arm64.

Next, use a script task to call docker buildx create --use then call docker buildx --platform linux/amd64,linux/arm64 -t <imagename>:$(build.buildNumber) -t <imagename>:latest --push .

Here is a full working example of a yaml build pipeline that builds a multi-architecture image.

name: 1.0.$(rev:r)

trigger:
- master

pool:
  vmImage: 'ubuntu-latest'

steps:
- task: Docker@2
  displayName: Login
  inputs:
    containerRegistry: 'Harbor-Vecc-Docker'
    command: 'login'
- task: CmdLine@2
  displayName: Build
  inputs:
    script: |
      docker run --privileged --rm tonistiigi/binfmt --install arm64
      docker run --privileged --rm tonistiigi/binfmt
      docker buildx create --use
      docker buildx build --platform linux/amd64,linux/arm64 \
        -t harbor.example.com/vecc/fileserver:$(build.buildNumber) \
        -t harbor.example.com/vecc/fileserver:latest \
        --push \
        .

Non Azure DevOps users

To use the buildx extension in the Docker CLI you may need to enable it because it is an experimental feature. You can do this by using the following commands:

Bash:

DOCKER_CLI_EXPERIMENTAL=enabled

PowerShell:

$ENV:DOCKER_CLI_EXPERIMENTAL=enabled

You then need to run the following

Bash:

docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 \
    -t harbor.example.com/vecc/fileserver:1 \
    -t harbor.example.com/vecc/fileserver:latest \
    --push \
    .

PowerShell:

docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 `
    -t harbor.example.com/vecc/fileserver:1 `
    -t harbor.example.com/vecc/fileserver:latest `
    --push \
    .

Conclusion

I have spent the past few days trying to make this work, even gave up on Azure Pipelines and used GitHub Actions (puke). Note, I have determined I am not a fan of Actions in its current state. Maybe in a year or 2 after it has matured a bit, but right now it falls short of my expectations which was not very high, I did not need it to do much. Anyways, my venture into GitHub Actions is what led me to the buildx part of the Docker CLI. I did not know it existed until today and I could not find anything online about building a multi-architecture image in Azure DevOps.

The script above should allow you to build any number of additional architecture images on any number of machines.

Docker Buildx
Working with Docker Buildx
tonistiigi/binfmt
Contribute to tonistiigi/binfmt development by creating an account on GitHub.