This repository contains reusable GitHub Actions workflows for building Docker images across different architectures using self-hosted runners.
Builds a Docker image specifically for ARM64 architecture (linux/arm64) on self-hosted ARM64 runners.
Builds a Docker image specifically for AMD64 architecture (linux/amd64) on self-hosted X64 runners.
Builds ARM64 and AMD64 images in parallel using the ARM and AMD workflows, then creates a multiarch manifest combining both architectures.
- ARM64: Self-hosted runners tagged with
ARM64label for ARM64 builds - X64: Self-hosted runners tagged with
X64label for AMD64 builds
Make sure your self-hosted runners have Docker installed and properly configured before using these workflows.
To use these reusable workflows in your repository, reference them in your workflow files:
name: Build My Docker Image
on:
push:
branches: [main]
jobs:
build-multiarch:
uses: fricker-studios/github-actions/.github/workflows/build-multiarch-image.yml@main
with:
image_name: myorganization/myapp
push: true
tags: |
latest
v1.0.0
secrets:
registry_username: ${{ secrets.DOCKER_USERNAME }}
registry_password: ${{ secrets.DOCKER_PASSWORD }}All three workflows share the following common inputs:
| Input | Description | Required | Default |
|---|---|---|---|
image_name |
Name of the Docker image to build (e.g., myorg/myapp) |
Yes | - |
dockerfile_path |
Path to the Dockerfile | No | ./Dockerfile |
context |
Build context path | No | . |
build_args |
Build arguments (comma-separated KEY=VALUE pairs) | No | '' |
push |
Whether to push the image to registry | No | false |
tags |
Additional tags for the image (newline-separated) | No | '' |
The multiarch workflow supports optional architecture-specific parameters that override the common parameters for each architecture:
| Input | Description | Required | Default |
|---|---|---|---|
arm_dockerfile_path |
Path to the Dockerfile for ARM build (overrides dockerfile_path) |
No | '' |
arm_context |
Build context path for ARM build (overrides context) |
No | '' |
arm_build_args |
Build arguments for ARM build (overrides build_args) |
No | '' |
amd_dockerfile_path |
Path to the Dockerfile for AMD build (overrides dockerfile_path) |
No | '' |
amd_context |
Build context path for AMD build (overrides context) |
No | '' |
amd_build_args |
Build arguments for AMD build (overrides build_args) |
No | '' |
Note: If architecture-specific parameters are not provided (empty string), the workflow will use the common parameters (dockerfile_path, context, build_args) for both architectures.
| Secret | Description | Required |
|---|---|---|
registry_username |
Docker registry username | No* |
registry_password |
Docker registry password | No* |
*Required only if push: true is set.
All workflows provide the following outputs:
| Output | Description |
|---|---|
image_tag |
Full image tag that was built |
digest |
Image digest |
name: Build ARM Image
on:
push:
branches: [main]
jobs:
build-arm:
uses: fricker-studios/github-actions/.github/workflows/build-arm-image.yml@main
with:
image_name: myorg/myapp
dockerfile_path: ./docker/Dockerfile
context: .
push: falsename: Build AMD Image
on:
release:
types: [published]
jobs:
build-amd:
uses: fricker-studios/github-actions/.github/workflows/build-amd-image.yml@main
with:
image_name: myorg/myapp
push: true
tags: |
latest
${{ github.ref_name }}
secrets:
registry_username: ${{ secrets.DOCKER_USERNAME }}
registry_password: ${{ secrets.DOCKER_PASSWORD }}name: Build Multiarch Image
on:
workflow_dispatch:
inputs:
version:
description: 'Version tag'
required: true
jobs:
build-multiarch:
uses: fricker-studios/github-actions/.github/workflows/build-multiarch-image.yml@main
with:
image_name: myorg/myapp
build_args: VERSION=${{ github.event.inputs.version }},BUILD_DATE=${{ github.run_number }}
push: true
tags: |
latest
${{ github.event.inputs.version }}
secrets:
registry_username: ${{ secrets.DOCKER_USERNAME }}
registry_password: ${{ secrets.DOCKER_PASSWORD }}Note: The multiarch workflow automatically builds for both AMD64 and ARM64 architectures using separate self-hosted runners in parallel.
If you need different Dockerfiles or build contexts for ARM and AMD:
name: Build Multiarch Image with Different Dockerfiles
on:
push:
branches: [main]
jobs:
build-multiarch:
uses: fricker-studios/github-actions/.github/workflows/build-multiarch-image.yml@main
with:
image_name: myorg/myapp
# Common parameters (used if architecture-specific ones aren't provided)
dockerfile_path: ./Dockerfile
context: .
# ARM-specific overrides
arm_dockerfile_path: ./Dockerfile.arm64
arm_context: ./arm
arm_build_args: ARCH=arm64,OPTIMIZATION=neon
# AMD-specific overrides
amd_dockerfile_path: ./Dockerfile.amd64
amd_context: ./amd
amd_build_args: ARCH=amd64,OPTIMIZATION=avx2
push: true
tags: |
latest
v1.0.0
secrets:
registry_username: ${{ secrets.DOCKER_USERNAME }}
registry_password: ${{ secrets.DOCKER_PASSWORD }}This allows you to optimize each architecture build separately, for example:
- Using architecture-specific optimizations in build arguments
- Different Dockerfiles that install architecture-specific dependencies
- Separate build contexts with architecture-specific files
If you need to manually control individual architecture builds:
name: Build All Architectures
on:
push:
branches: [main]
jobs:
build-arm:
uses: fricker-studios/github-actions/.github/workflows/build-arm-image.yml@main
with:
image_name: myorg/myapp
push: true
tags: latest
secrets:
registry_username: ${{ secrets.DOCKER_USERNAME }}
registry_password: ${{ secrets.DOCKER_PASSWORD }}
build-amd:
uses: fricker-studios/github-actions/.github/workflows/build-amd-image.yml@main
with:
image_name: myorg/myapp
push: true
tags: latest
secrets:
registry_username: ${{ secrets.DOCKER_USERNAME }}
registry_password: ${{ secrets.DOCKER_PASSWORD }}name: Build and Deploy
on:
push:
branches: [main]
jobs:
build:
uses: fricker-studios/github-actions/.github/workflows/build-multiarch-image.yml@main
with:
image_name: myorg/myapp
push: true
tags: latest
secrets:
registry_username: ${{ secrets.DOCKER_USERNAME }}
registry_password: ${{ secrets.DOCKER_PASSWORD }}
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Deploy with built image
run: |
echo "Deploying image: ${{ needs.build.outputs.image_tag }}"
echo "Image digest: ${{ needs.build.outputs.digest }}"
# Add your deployment commands herename: Build from Subdirectory
on:
push:
branches: [main]
jobs:
build:
uses: fricker-studios/github-actions/.github/workflows/build-multiarch-image.yml@main
with:
image_name: myorg/myapp
dockerfile_path: ./services/api/Dockerfile
context: ./services/api
push: true
secrets:
registry_username: ${{ secrets.DOCKER_USERNAME }}
registry_password: ${{ secrets.DOCKER_PASSWORD }}These workflows support any Docker registry that uses standard authentication:
- Docker Hub: Use your Docker Hub username and personal access token
- GitHub Container Registry (ghcr.io): Use
${{ github.actor }}and${{ secrets.GITHUB_TOKEN }} - AWS ECR: Use AWS credentials configured for ECR
- Google Container Registry (GCR): Use service account credentials
- Azure Container Registry (ACR): Use service principal credentials
jobs:
build:
uses: fricker-studios/github-actions/.github/workflows/build-multiarch-image.yml@main
with:
image_name: ghcr.io/${{ github.repository }}
push: true
tags: |
latest
${{ github.sha }}
secrets:
registry_username: ${{ github.actor }}
registry_password: ${{ secrets.GITHUB_TOKEN }}- ✅ Multi-architecture support: Build for ARM64, AMD64, or both
- ✅ Native architecture builds: Uses self-hosted runners (no QEMU emulation overhead)
- ✅ Parallel builds: ARM and AMD builds run simultaneously for faster execution
- ✅ Caching: Automatic GitHub Actions cache for faster builds
- ✅ Flexible tagging: Support for multiple tags per build
- ✅ Build arguments: Pass custom build arguments to Docker
- ✅ Registry agnostic: Works with any Docker registry
- ✅ Output support: Access image tags and digests in dependent jobs
- ✅ Manifest creation: Multiarch workflow automatically creates and pushes Docker manifests
To use these workflows, you need:
- Self-hosted runners with the following labels:
ARM64label for ARM64 buildsX64label for AMD64 builds- Docker installed and properly configured on all runners
- A valid
Dockerfilein your repository - Docker registry credentials configured as GitHub secrets (if pushing images)
- Appropriate permissions for the GitHub token (if using GHCR)
- Ensure you have self-hosted runners configured with
ARM64andX64labels - Verify the runners are online and available
- Check that Docker is installed on the runners
- Verify your registry credentials are correct
- Check that the secrets are properly configured in your repository settings
- Ensure the
pushinput is set totrueif you want to push images
- Consider using build caching more effectively
- Ensure your self-hosted runners have adequate resources
- Optimize your Dockerfile for layer caching
- Ensure both ARM and AMD builds completed successfully
- Verify the images were pushed to the registry (push must be true)
- Check that the registry supports Docker manifests
To contribute to these reusable workflows:
- Fork this repository
- Create a feature branch
- Make your changes
- Test the workflows in your fork
- Submit a pull request
This project is open source and available under the MIT License.
For issues, questions, or contributions, please open an issue in this repository.