Skip to content

ci(testing): build the minimal image natively per architecture (draft) - #181

Merged
jsokol merged 1 commit into
testingfrom
FEATURE-native-arm64-build
Oct 28, 2026
Merged

jsokol merged 1 commit into
testingfrom
FEATURE-native-arm64-build

Conversation

@jsokol

@jsokol jsokol commented Oct 28, 2026

Copy link
Copy Markdown
Member

Why

The minimal publish takes about 88 minutes: 3 PHP variants x {amd64, arm64} built one after another in a single job, with arm64 emulated by QEMU. Per-step timings from the 2026-10-27 run (publish-testing, run 40561303824) show where it goes. For one variant:

amd64 (native) arm64 (QEMU)
docker-php-ext-configure/install (PHP extension compile) 1.6 min 24.3 min
apt-get update/install 0.4 min 2.7 min
all steps summed ~2.4 min ~27.5 min

A native arm64 leg should take about the amd64 time (~2.5 min of build work plus export and runner setup). Estimate: ~10-15 min total instead of 88; not measured on a real arm runner yet.

What changes (publish-testing.yml only)

  • build-minimal: matrix {php83, php84, php85} x {amd64 on ubuntu-latest, arm64 on ubuntu-24.04-arm}. Each leg builds only its own architecture, no QEMU, and pushes by digest (no tag), uploading the digest as an artifact.
  • merge-minimal: per variant, docker buildx imagetools create points the real tags at one multi-arch index, then fails unless every tag carries both linux/amd64 and linux/arm64.
  • scan-minimal: one Grype leg per variant (same action, same published-minimal-php8x labels; fail-fast: false so all three reports upload).
  • promote: needs all three scans, then the same single SSM write as before. A critical finding still blocks the promote.
  • grype_report now depends on scan-minimal and publish-full.
  • New workflow_dispatch input dry_run: builds, merges and scans under <VERSION>-nativetest-php8x only. It never moves the bare <VERSION> tag or :testing and skips the promote.

Unchanged

Triggers, concurrency group, the tag set (<VERSION>-php83/-php84/-php85, bare <VERSION> and :testing on php85), the bundle fetch + sha256 verification, the context assembly, the full-stack job, and the published image shape (amd64 + arm64 + 2 attestation manifests). It is still one tag per image: the per-arch images exist only as untagged digests referenced by the index, and GA still promotes the index digest.

Verification

  • actionlint: clean.
  • The merge-and-verify commands, run verbatim against a local registry with two single-arch images built with the same attestation setting: all three tags resolve to the same index digest, each lists linux/amd64 + linux/arm64, and the index has 2 attestation manifests, matching simplerisk/simplerisk-minimal:20261020-001-php85 on Docker Hub.
  • Not run: a real build on ubuntu-24.04-arm, the Grype matrix, or the dry-run path. Nothing here has executed in Actions yet.

Open questions / risks

  • Is ubuntu-24.04-arm available to this repo? The repo is public, so GitHub's free arm runners should apply, but org runner settings were not readable to confirm.
  • The testing environment only admits the testing branch, so the first run cannot happen from this branch. Plan: merge, then dispatch from testing with dry_run=true and check the -nativetest- tags (both architectures, scans green), then let the next normal push be the first live run. This PR stays a draft until that is agreed.
  • Cache scopes are now per architecture, so the first native run starts cold.
  • The 3 build matrices fail fast: one failed leg cancels the rest and nothing is merged or promoted.
  • Reverting is a single revert of this PR.

Follow-up (not in this PR)

An arm64 smoke test after the merge (for example, exercising set_db_ssl_flags against the arm64 image's own mysql) would have caught the MariaDB-client flag problem fixed in #180.

🤖 Generated with Claude Code

The minimal job built 3 PHP variants x {amd64, arm64} sequentially in one job with arm64
emulated by QEMU: about 27 min per variant, 88 min total. Per-step timings from the 10-27 run show
why: the PHP extension compile (docker-php-ext-configure/install) took 24.3 min on emulated arm64
and 1.6 min on native amd64; the whole variant summed to 27.5 min emulated vs 2.4 min native.

build-minimal is now a matrix of {php83, php84, php85} x {amd64 on ubuntu-latest, arm64 on
ubuntu-24.04-arm}; each leg builds only its own architecture and pushes by digest (no tag).
merge-minimal turns each variant's two digests into the published tags with
'docker buildx imagetools create' and fails unless every tag carries linux/amd64 and
linux/arm64. scan-minimal (one leg per variant) keeps the Grype gate and report labels;
promote needs all three scans and does the same single SSM write as before.

Unchanged: triggers, concurrency, the tag set (<VERSION>-php83/-php84/-php85, bare <VERSION> and
:testing on php85), the full-stack job, and the shape of the published image (amd64 + arm64 +
attestations). New: a workflow_dispatch dry_run input that publishes only
<VERSION>-nativetest-php8x tags, never the bare tag or :testing, and skips the promote. It must be
dispatched from testing (the testing environment admits only that branch).

Verified: actionlint clean; the merge-and-verify commands run against a local registry produce one
index digest for all tags, both platforms, and 2 attestation manifests, matching the shape of
20261020-001-php85. Not run here: a real build on ubuntu-24.04-arm.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jsokol
jsokol marked this pull request as ready for review October 28, 2026 20:45
@jsokol
jsokol merged commit 4b4fb01 into testing Oct 28, 2026
8 checks passed
@jsokol
jsokol deleted the FEATURE-native-arm64-build branch October 28, 2026 20:46
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