Build each architecture on its own runner instead of emulating arm64 - #23
Merged
Conversation
Three image builds in a row published nothing. `npm ci` hangs indefinitely on linux/arm64 under QEMU: amd64 finished the same step in 4.3 seconds and went on to complete the whole image, while arm64 emitted its last line and then sat silent for six hours until GitHub's maximum job time killed the run. It happened on both main merges and on the v1.5.0 tag, so 1.5.0 has a tag and a release but no image. Nothing in the repo caused it. setup-qemu-action pulls tonistiigi/binfmt:latest, unpinned, so the emulation layer moved under us between 1.4.0 and now — and the workflow had no way to notice. Pinning binfmt would be guessing at a good version and would leave arm64 slow and emulated. Native runners remove QEMU from the question: each architecture builds on its own machine and pushes an untagged image by digest, then a merge job stitches the digests into one manifest list and puts the tags on that. ubuntu-24.04-arm is free on public repositories. Two things the same logs made obvious: Every job now sets timeout-minutes. The default is six hours, which is why each hang cost a full six before anyone heard about it. The image name is lowercased explicitly. metadata-action does that for you, but `docker buildx imagetools` in the merge job does not, and this owner's name has a capital in it — ghcr.io rejects the tag outright. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
1.5.0 has a git tag and a GitHub Release but no published image. Three image builds in a row published nothing.
What's wrong
npm cihangs indefinitely onlinux/arm64under QEMU emulation. From the run on the #21 merge:Not a slow build — a hang. Reproduced three times: both
mainmerges (32604849105,32605380021) and thev1.5.0tag build (32622498187, cancelled once the pattern was clear rather than burning another six hours).Nothing in this repo caused it. v1.4.0 built in 44 seconds on 20 Aug.
setup-qemu-actionpullstonistiigi/binfmt:latest— unpinned — so the emulation layer moved underneath us, and the workflow had no way to notice.The fix
Each architecture builds on its own native runner and pushes an untagged image by digest; a merge job stitches the digests into one manifest list and puts the tags on that.
ubuntu-24.04-armis free on public repos.Pinning binfmt instead would be guessing at a good version, would leave arm64 emulated and slow, and would leave the same unpinned-dependency exposure that caused this. Native runners remove QEMU from the question.
Tags are applied only on the manifest list, never per-architecture — two arch builds both carrying
:latestwould fight over the tag, last push winning.Two things the logs made obvious
timeout-minuteson every job. The default is six hours, which is exactly why each hang cost a full six before anyone heard about it. Now 30 (build) and 15 (merge).metadata-actiondoes this for you;docker buildx imagetoolsin the merge job does not — andauthorTomhas a capital T, which ghcr.io rejects outright. That would have failed the new merge step on its first run.Also
fail-fast: false, so one arch failing doesn't cancel the other — knowing whether it's "arm64 is broken" or "the build is broken" is the whole diagnosis.Not fixed here
GitHub is force-running all six pinned actions on Node 24 because Node 20 is deprecated. It's a warning today, not the cause of this, and bumping six action majors doesn't belong in the same change as unbreaking the release.
After merge
mainpublishes:edgeand:sha-…and proves the workflow works. Then re-run it against the existing tag —gh workflow run docker.yml --ref v1.5.0— to publish:1.5.0,:1.5,:1and:latest. The tag and Release need no changes.🤖 Generated with Claude Code