From github-actions-container-build
Build multi-architecture container images in GitHub Actions. Matrix builds (public repos with native ARM64), QEMU emulation (private repos), or ARM64 larger runners (Team/Enterprise). Uses Podman rootless builds with push-by-digest pattern
npx claudepluginhub pigfoot/claude-code-hubs --plugin github-actions-container-buildThis skill uses the workspace's default tool permissions.
Build multi-architecture container images in GitHub Actions using Podman and native ARM64 runners.
Provides standard GitHub Actions workflows for multi-platform Docker container builds to GHCR, release-please automation, and optional ArgoCD PR auto-merges. Use for CI/CD configuration and compliance checks.
Configures container registries like GHCR, Docker Hub, Harbor with scanning, tagging, retention policies, and CI/CD. Use for private setups, Docker Hub migrations, vuln scanning, multi-arch images, signing, cleanup.
Configures Docker environments for act to test GitHub Actions locally, selects runner images like catthehacker/ubuntu or language-specific ones, manages .actrc settings, container reuse, and resources.
Share bugs, ideas, or general feedback.
Build multi-architecture container images in GitHub Actions using Podman and native ARM64 runners.
CRITICAL: Ask these questions before generating any workflow.
Question 1: Is your GitHub repository public?
github-actions-workflow-matrix-build.yml (free standard ARM64 runners, 10-50x faster)Question 2: Do you have GitHub Team/Enterprise + willing to pay for ARM64 builds?
github-actions-workflow-qemu.yml (free QEMU emulation, slower but works on free tier)Matrix builds use push-by-digest pattern:
:amd64/:arm64 tags--platform flag# Build job
- name: Push by digest
run: |
podman push \
--digestfile /tmp/digest \
localhost/build:${{ matrix.arch }} \
docker://${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# Merge job
- name: Create manifest from digests
run: |
podman manifest create "$IMAGE:latest"
podman manifest add "$IMAGE:latest" "docker://$IMAGE@${AMD64_DIGEST}"
podman manifest add "$IMAGE:latest" "docker://$IMAGE@${ARM64_DIGEST}"
podman manifest push --all "$IMAGE:latest" "docker://$IMAGE:latest"
Debug specific architecture:
podman pull --platform linux/arm64 ghcr.io/OWNER/REPO:latest
For public repositories - use GitHub-hosted standard ARM64 runners:
strategy:
matrix:
include:
- arch: amd64
runner: ubuntu-24.04
- arch: arm64
runner: ubuntu-24.04-arm # Standard ARM64 runner (public repos only)
For private repositories on free tier - use QEMU emulation:
docker/setup-qemu-action for ARM64 emulation--platform linux/amd64,linux/arm64runs-on: ubuntu-latest
steps:
- uses: docker/setup-qemu-action@v3
- run: podman build --platform linux/amd64,linux/arm64 --manifest ...
Use Podman for container builds:
podman manifest push --all (not podman push)--format v2s2 only for Quay.io or cross-registry (see
references for details)--network=host flag for builds to avoid container networking SSL issues on GitHub Actions
ubuntu-24.04 (see Troubleshooting section)Ubuntu 24.04's bundled podman (4.9.3) uses buildah 1.33.7 which doesn't support heredoc syntax. Install podman-static for full BuildKit compatibility:
- name: Install podman-static
run: |
ARCH=$(uname -m)
if [ "$ARCH" = "x86_64" ]; then
PODMAN_ARCH="amd64"
else
PODMAN_ARCH="arm64"
fi
curl -fsSL -o /tmp/podman-linux-${PODMAN_ARCH}.tar.gz \
https://github.com/mgoltzsche/podman-static/releases/latest/download/podman-linux-${PODMAN_ARCH}.tar.gz
cd /tmp && tar -xzf podman-linux-${PODMAN_ARCH}.tar.gz
sudo cp -f podman-linux-${PODMAN_ARCH}/usr/local/bin/* /usr/bin/
podman system migrate
Important: Install to /usr/bin/ (not /usr/local/bin/) to avoid AppArmor issues.
Copy workflow template:
cp assets/github-actions-workflow-matrix-build.yml .github/workflows/build.yml
Customize Containerfile path:
-f ./Containerfile.python-uv # or your Containerfile
Add your Containerfile (see secure-container-build plugin for templates)
Copy workflow template:
cp assets/github-actions-workflow-qemu.yml .github/workflows/build.yml
Follow steps 2-3 from above.
--platform flag| Approach | Artifact Size | Registry Overhead | Best For |
|---|---|---|---|
| Push-by-digest (default) | ~70 bytes | 1x | Production |
| Architecture tags | None | 2x (tags + manifest) | Debugging |
| OCI artifacts | Full images | 3x | Maximum privacy |
See references/github-actions-best-practices.md for detailed comparison.
For private repositories with GitHub Team or Enterprise Cloud plans:
Standard ARM64 runners (ubuntu-24.04-arm) don't work in private repos. Instead, create ARM64 larger runners:
Setup steps:
my-org-arm64-runner)Update workflow to use custom runner:
strategy:
matrix:
include:
- arch: amd64
runner: ubuntu-24.04
- arch: arm64
runner: my-org-arm64-runner # Your custom ARM64 larger runner name
Cost:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
- name: Login to GHCR
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | podman login "${{ env.REGISTRY }}" \
-u "${{ github.actor }}" \
--password-stdin
- name: Login to Docker Hub
run: |
echo "${{ secrets.DOCKERHUB_TOKEN }}" | podman login docker.io \
-u "${{ secrets.DOCKERHUB_USERNAME }}" \
--password-stdin
# Push to Docker Hub
podman manifest push --all "$IMAGE:latest" \
"docker://docker.io/${{ secrets.DOCKERHUB_USERNAME }}/app:latest"
# Pull specific architecture
podman pull --platform linux/arm64 ghcr.io/OWNER/REPO:latest
# Inspect manifest
podman manifest inspect ghcr.io/OWNER/REPO:latest
# Verify architectures
podman manifest inspect ghcr.io/OWNER/REPO:latest | jq '.manifests[].platform'
For detailed information, see references/github-actions-best-practices.md.
For Containerfile templates and security best practices, see the secure-container-build plugin which provides:
Container networking SSL errors (ubuntu-24.04 runners):
Symptom: UNKNOWN_CERTIFICATE_VERIFICATION_ERROR or SSL certificate verification failures during bun install,
npm install, pip install, etc. inside containers
Cause: GitHub Actions ubuntu-24.04 runner image 20251208.163.1+ has container networking configuration changes that break SSL/TLS connections from inside containers
Solution: Add --network=host flag to podman build:
podman build \
--network=host \
--format docker \
--platform linux/${{ matrix.arch }} \
-f ./Containerfile \
.
Verification: Test repository at https://github.com/pigfoot/test-bun-ssl-issue
GitHub Issue: https://github.com/actions/runner-images/issues/13422
Note: This is a known issue with ubuntu-24.04 runners. The --network=host workaround reduces network isolation
during build but is acceptable for CI/CD use cases.
Authentication failed:
Manifest add failed:
sha256:...)ARM64 runner not available:
podman-static installation fails:
AppArmor issues:
/usr/bin/ not /usr/local/bin/podman system migrate after installationWrong architecture pulled:
--platform flag when pulling--format docker when building for compatibility