Automating multi-arch container images builds (we used Google Cloud Build but GitHub Actions would also work)

This is the last post in the series on how we prepared our application to run on M1 (Apple Silicon).

In the previous part we were talking about building multiple CPU architecture container images.

This post will guide you through how to implement a pipeline for building multi-architecture container images using Google Cloud Platform’s Cloud Build or GitHub Actions.

As you may know from the previous post, to build multi-arch container images we need to setup virtual environment and run docker buildx.

Let's configure such build pipelines for some popular CI/CD solutions.

Cloud Build

To run multi-arch container images builds let's use the following pipeline configuration:

steps:
  - name: gcr.io/cloud-builders/docker
    args:
      - run
      - '--privileged'
      - 'linuxkit/binfmt:v0.7'
    id: initialize-qemu
  - name: gcr.io/cloud-builders/docker
    args:
      - buildx
      - create
      - '--name'
      - mybuilder
    id: create-builder
  - name: gcr.io/cloud-builders/docker
    args:
      - buildx
      - use
      - mybuilder
    id: select-builder
  - name: gcr.io/cloud-builders/docker
    args:
      - buildx
      - inspect
      - '--bootstrap'
    id: show-target-build-platforms
  - name: gcr.io/cloud-builders/docker
    args:
      - buildx
      - build
      - '--platform'
      - $_DOCKER_BUILDX_PLATFORMS
      - '-t'
      - 'gcr.io/$PROJECT_ID/hello-world:latest'
      - '--push'
      - .
    id: build-multi-architecture-container-image
options:
  env:
    - DOCKER_CLI_EXPERIMENTAL=enabled
substitutions:
  _DOCKER_BUILDX_PLATFORMS: 'linux/amd64,linux/arm64'

The above configuration creates the pipeline to set up the build environment (initialize-qemu, create-builder, select-builder, and show-target-build-platforms steps), to build a multi-arch container image and to push it to the Container Registry on Google Cloud Platform (build-multi-architecture-container-image step).

To push to another container registry (e.g. Docker Hub) update the build-multi-architecture-container-image step accordingly.

Please consult the Cloud Build documentation to get the information on how to trigger builds (manually or automatically).

GitHub Actions

If you prefer to use GitHub Actions instead of Cloud Build, it is also possible.

The pipeline configuration to build multi-arch container images is the following:

name: ci
on:
  push:
jobs:
  buildx:
    runs-on: ubuntu-latest
    steps:
      - name: checkout code
        uses: actions/checkout@v2
      - name: setup qemu
        uses: docker/setup-qemu-action@v1
      - name: setup buildx
        id: buildx
        uses: docker/setup-buildx-action@v1
      - name: available platforms
        run: echo ${{ steps.buildx.outputs.platforms }}
      - name: login to docker hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}
      - name: build the image
        run: |
          docker buildx build \
          --push \
          --tag ${{ secrets.DOCKER_USERNAME }}/hello-world:latest \
          --platform linux/amd64,linux/arm64 .

To make it work you need to set up some secrets on GitHub:

  • DOCKER_USERNAME — your user name on Docker Hub
  • DOCKER_TOKEN — your Docker Hub access token

Conclusion

That was the last post in the series, and to sum up let's repeat the key points on how to prepare an application for M1 (Apple Silicon):

  1. Use Go to easily build applications for different operating systems
  2. Build multi-arch container images with docker buildx
  3. Utilize Cloud Build or GitHub Action to automate builds

35