Skip to content

Build each architecture natively instead of emulating arm64 - #1

Merged
karl-bullock merged 3 commits into
mainfrom
native-arm-build
Jul 29, 2026
Merged

Build each architecture natively instead of emulating arm64#1
karl-bullock merged 3 commits into
mainfrom
native-arm-build

Conversation

@karl-bullock

Copy link
Copy Markdown
Member

The publish job built linux/amd64 and linux/arm64 together under QEMU. This image compiles PHP extensions (gd, intl) during the build, which is close to the worst case for emulation — the last run on main spent over half an hour on publish while roundtrip finished in a few minutes.

GitHub provides free arm64 runners for public repos, so neither architecture needs emulating. Each now builds on its own native runner and pushes by digest; a small merge job stitches the digests into one multi-arch tag.

Three details:

  • Cache is scoped per-architecture. A shared scope has the two jobs overwrite each other's layers.
  • No per-arch tags are pushed. A tag written by both jobs ends up pointing at whichever finished last, so only the merge job names the image.
  • The manifest is verified. The run fails if both architectures aren't present, rather than silently shipping a half-published tag.

roundtrip is untouched, so the required check behaves exactly as before.

The publish job built linux/amd64 and linux/arm64 together under QEMU. This
image compiles php extensions (gd, intl) during the build, which is close to
the worst case for emulation — the last run spent over half an hour on publish
while the round-trip test beside it finished in a few minutes.

GitHub gives public repositories free arm64 runners, so nothing needs
emulating. Each arch now builds on its own native runner and pushes by digest,
and a small merge job stitches the digests into one multi-arch tag.

Two details worth keeping: the build cache is scoped per-architecture, since a
shared scope has the two jobs overwrite each other's layers; and no per-arch
tags are pushed, since a tag written by both jobs ends up pointing at whichever
finished last. The merge job names the image exactly once, then asserts both
architectures are actually in the manifest so a silently half-published tag
fails the run instead of shipping.
build/publish only ran on main or a tag, so a change to the build itself
could not be tested before merging: the pull request showed a green
roundtrip and said nothing about whether the image still publishes.
Adding workflow_dispatch makes this very change verifiable on its branch.
actions/upload-artifact rejects ':' in a filename, so the export step
failed after the image had already built and pushed successfully. The
merge job was already written to expect the bare hex and re-add the
prefix; only the export half was wrong.
@karl-bullock
karl-bullock merged commit c1463e7 into main Jul 29, 2026
10 checks passed
@karl-bullock
karl-bullock deleted the native-arm-build branch July 29, 2026 00:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant