Skip to content

ci: build multi-arch image on native runners instead of QEMU (fixes slow releases) - #7

Merged
veniplex merged 1 commit into
mainfrom
ci/native-arm64-build
Jul 13, 2026
Merged

veniplex merged 1 commit into
mainfrom
ci/native-arm64-build

Conversation

@veniplex

Copy link
Copy Markdown
Owner

Summary

Release runs were taking ~14 minutes, almost entirely in the single "Build and push" step. Root cause: the build produced linux/amd64 and linux/arm64 in one job, and the arm64 half ran under QEMU emulation on an amd64 runner — where npm ci + next build are several times slower. Emulation was essentially the whole build time.

Fix — build each arch natively, then merge manifests (the standard docker/build-push-action multi-arch pattern):

  • build job runs as a matrix: linux/amd64 on ubuntu-latest, linux/arm64 on ubuntu-24.04-arm (GitHub-hosted arm64 runners, free for public repos). Each pushes its image by digest (no tag yet).
  • merge job downloads the per-arch digests and assembles one multi-arch manifest with docker buildx imagetools create, using the same tag set as before.
  • Both arches build in parallel with no emulation → a few minutes each instead of ~14.

Also: added a per-ref concurrency group with cancel-in-progress, so a stalled or superseded build can't pile up (the history had a run stuck for 224 minutes before being cancelled). It's keyed by github.ref so a release's :edge build (on main) and its semver build (on the vX.Y.Z tag) — different refs — never cancel each other.

Unchanged (contract preserved)

  • Published tags: :main, :edge, :X.Y.Z, :X.Y, :X, :latest.
  • The workflow_dispatch entrypoint that version-bump.yml calls (gh workflow run release.yml --ref vX.Y.Z).
  • Still publishes both linux/amd64 and linux/arm64, so docs/self-hosting.md's promise holds.

Test plan

  • YAML validated (matrix, needs, concurrency, triggers).
  • After merge, confirm the dispatched release.yml run: both matrix legs build on their native runners (no QEMU step), the merge job pushes the manifest, and docker buildx imagetools inspect ghcr.io/veniplex/study-helper:<version> shows both amd64 and arm64. Compare wall-clock against the previous ~14 min.

Note: this PR is itself a good end-to-end test — add the release-candidate label before merging to exercise the full release path on the new workflow.


Generated by Claude Code

The release build spent ~14 min almost entirely in "Build and push"
because the linux/arm64 half ran under QEMU emulation on an amd64 runner,
where npm ci + next build are several times slower.

Rework release.yml into the build-by-digest + merge-manifest pattern:
each architecture builds on its own native runner (amd64 on ubuntu-latest,
arm64 on ubuntu-24.04-arm — free for public repos) and pushes by digest,
then a merge job assembles the multi-arch manifest with the same tag set
as before. Both arches build in parallel, so no emulation and a few
minutes each instead of ~14.

Also add a per-ref concurrency group with cancel-in-progress so a stalled
or superseded build (one run sat for 224 min before being cancelled)
can't pile up; keyed by ref so a release's :edge (main) and semver (tag)
builds don't cancel each other.

The published tags (:main, :edge, :X.Y.Z, :X.Y, :X, :latest) and the
workflow_dispatch entrypoint used by version-bump.yml are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ST7p7inT3agkLEp8qbPSC6
@veniplex veniplex added the release-candidate Creates a new release and deployment of docker image, once merged. label Jul 13, 2026
@veniplex
veniplex merged commit 14fbdaa into main Jul 13, 2026
1 of 2 checks passed
@veniplex
veniplex deleted the ci/native-arm64-build branch July 13, 2026 16:23
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-candidate Creates a new release and deployment of docker image, once merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants