How to build a Multi-Architecture Docker Image in Github Actions using multiple runners without QEMU
Created by SREDevOps.org | @sredevopsorg | @ngeorger
By following these steps and reviewing the workflow file, you can customize and use this multi-architecture build process in your own projects. Happy building!
This repository demonstrates how to build multi-architecture Docker images (for example, linux/amd64 and linux/arm64) using native GitHub runners instead of QEMU emulation. By leveraging separate native runners for each architecture, you get faster builds and higher fidelity (no emulation quirks) while still producing a single multi-arch image that you can push to GitHub Container Registry (GHCR).
Note: This workflow requires access to both an AMD64 runner (using
ubuntu-latest) and an ARM64 runner (for example,ubuntu-24.04-arm). Make sure your GitHub organization or repository has access to these runners.
The workflow is divided into two main jobs:
- 
Build Job:
- Uses a matrix strategy to build images for each platform separately.
 - Sets up a Docker context and configures Buildx to build images natively.
 - Logs into GHCR and builds & pushes the image by digest.
 - Exports the digest as an artifact for later use.
 
 - 
Merge Job:
- Downloads the digests from the build job.
 - Generates Docker image metadata (tags, labels, and annotations).
 - Uses Buildx to create a multi-architecture manifest list from the individual images.
 - Pushes the merged manifest (which tells Docker which image to pull based on the host architecture).
 
 
This two-step process creates a “fat” image that automatically delivers the correct binary for the user’s architecture.
- Native Builds: Uses GitHub’s native runners for each platform (no QEMU).
 - Multi-Arch Manifest: Automatically merges per-architecture images into one multi-arch image.
 - Build Caching: Implements caching to speed up subsequent builds.
 - OCI Metadata: Adds labels and annotations for better image provenance.
 - Concurrency Control: Uses GitHub Actions concurrency to cancel outdated builds.
 
- A GitHub repository with this workflow set up.
 - Access to GitHub-hosted runners for both linux/amd64 and linux/arm64.
 - A GitHub token (automatically provided as 
GITHUB_TOKEN) with permission to push to GHCR. - A valid Dockerfile in the repository root (or modify the workflow’s context as needed).
 
- 
Clone the Repository:
git clone https://github.com/sredevopsorg/multi-arch-docker-github-workflow.git cd multi-arch-docker-github-workflow - 
Review and Customize:
- 
Dockerfile:
The provided Dockerfile is a simple example. Customize it as needed for your application or replace it with your own. - 
Workflow File:
The GitHub Actions workflow is defined in.github/workflows/multi-build.yaml. You can adjust parameters (e.g., caching options, labels, annotations) if needed. 
 - 
 - 
Configure Secrets (if applicable):
- By default, the workflow uses the built-in 
GITHUB_TOKENfor authentication to GHCR. If you need to change registry credentials or add additional secrets, set them in your repository’s Settings > Secrets and Variables. 
 - By default, the workflow uses the built-in 
 
- 
Prepare Environment:
The first step in the build job sets an environment variable (PLATFORM_PAIR) by replacing any/characters in the platform name with-. This ensures artifact names are valid. - 
Checkout Code:
The repository is checked out using actions/checkout. - 
Generate Docker Metadata:
The docker/metadata-action creates metadata (tags, labels, annotations) based on repository information. - 
Setup Docker Context and Buildx:
- A new Docker context (named 
builders) is created. - The docker/setup-buildx-action is configured to use that context and the specific platform from the matrix (either 
linux/amd64orlinux/arm64). 
 - A new Docker context (named 
 - 
Login to GHCR:
The workflow logs in to GitHub Container Registry using theGITHUB_TOKEN. - 
Build and Push:
Using docker/build-push-action, the image is built with the specified platform, labels, and caching options. The image is pushed by digest and the resulting digest is exported. - 
Artifact Upload:
The digest file is uploaded as an artifact (named with the platform pair) for use in the next job. 
- 
Download Digests:
The merge job downloads all the digest artifacts from the build job. - 
Re-generate Docker Metadata:
Metadata is generated again to ensure consistency with the built images. - 
Setup Buildx and Login:
The job sets up Buildx (this time without a custom context) and logs in to GHCR. - 
Create Multi-Arch Manifest:
The workflow runsdocker buildx imagetools createto merge the images (using the digest files) into a single multi-architecture manifest list. Annotations such as description, creation timestamp, and source URL are added. - 
Manifest Inspection:
Finally, the merged image is inspected to verify that it contains the proper platform-specific entries. 
- 
Automatic Trigger:
Pushing changes to theDockerfileor the workflow file (.github/workflows/multi-build.yaml) on themainbranch will automatically trigger the workflow. - 
Manual Trigger:
You can also trigger the workflow manually using theworkflow_dispatchevent. 
Once the workflow completes, your multi-architecture image is available in GHCR. For example, if your repository is ghcr.io/your-org/your-repo, you can pull the image as follows:
docker pull ghcr.io/your-org/your-repo:latestDocker will automatically select the correct image based on your host’s CPU architecture.
Contributions, issues, and feature requests are welcome! Feel free to check Issues or submit a pull request.
This project is licensed under the MIT License.