Skip to content

ci: use native arm64 runners and GHA layer cache#35

Open
marc0olo wants to merge 6 commits into
mainfrom
feat/native-arm64-build-cache
Open

ci: use native arm64 runners and GHA layer cache#35
marc0olo wants to merge 6 commits into
mainfrom
feat/native-arm64-build-cache

Conversation

@marc0olo

@marc0olo marc0olo commented Jun 10, 2026

Copy link
Copy Markdown
Member

Problem

All three images were built using QEMU to emulate linux/arm64 on an amd64 runner. Rust compilation under QEMU is ~10–20× slower than native, which caused the rust and all image builds to take ~50 minutes.

Changes

Native arm64 runners — each image build is split into two parallel jobs:

  • build-{name}-amd64 on ubuntu-latest (native amd64)
  • build-{name}-arm64 on ubuntu-24.04-arm (native arm64, free for public repos)

A third merge-{name} job waits for both, then assembles the final multi-arch manifest via docker buildx imagetools create. The published result is identical to before: a single multi-arch image tag covering both platforms.

Push by digest — platform builds use push-by-digest=true and pass their digest as a job output. The merge job references images by digest ({image}@sha256:...) rather than SHA-suffixed tags, so no intermediate tags accumulate in GHCR.

GHA layer cachecache-from/cache-to: type=gha,mode=max is added to every platform build, scoped per image and platform (e.g. scope=rust-arm64). When only ICP_CLI_VERSION changes, the slow cargo binstall candid-extractor layer is served from cache and skipped entirely. No actions: write permission is needed — the type=gha cache backend uses ACTIONS_RUNTIME_TOKEN, not GITHUB_TOKEN.

Tag ref support — added type=ref,event=tag to all merge jobs so workflow_dispatch triggered on a tag ref always produces at least one --tag destination for imagetools create.

Safe TAGS construction — the merge steps use printf + grep -v '^$' to filter blank lines before building the --tag argument list, preventing a bare --tag with no value if the tags output were ever empty.

QEMU setup is removed from all jobs — it's no longer needed.

Expected impact

Scenario Before After (est.)
Cold build, rust/all arm64 ~45 min (QEMU) ~5–8 min (native)
Warm build (icp-cli bump only) ~45 min (QEMU, no cache) ~2–3 min (cache hit on cargo layer)
Cold build, motoko ~5 min ~3 min

Test plan

  • Trigger workflow_dispatch on this branch and verify all 9 jobs succeed
  • Verify GHCR shows both linux/amd64 and linux/arm64 in the manifest for each image
  • Confirm build times are significantly reduced for the rust and all arm64 jobs
  • Confirm no intermediate tags appear in GHCR after the build

🤖 Generated with Claude Code

Splits each image build into parallel amd64 (ubuntu-latest) and arm64
(ubuntu-24.04-arm) jobs, then merges them into a multi-arch manifest via
`docker buildx imagetools create`. This eliminates QEMU emulation for
arm64, which was responsible for the ~50 min build time on rust/all.

Adds GHA layer caching (type=gha, mode=max, scoped per image+platform)
so that unchanged layers (e.g. candid-extractor when only icp-cli bumps)
are served from cache on subsequent releases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the container-image publishing workflow to build linux/amd64 and linux/arm64 images on native runners (eliminating QEMU emulation) and introduces GitHub Actions BuildKit layer caching to significantly reduce CI build times—especially for Rust-heavy images.

Changes:

  • Split each image build into parallel per-architecture jobs (amd64 on ubuntu-latest, arm64 on ubuntu-24.04-arm) and add a merge job to publish a combined multi-arch manifest.
  • Add cache-from / cache-to BuildKit GHA cache configuration, scoped per image + platform.
  • Remove QEMU setup from the workflow since cross-arch emulation is no longer needed.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml
Addresses Copilot review on #35:
- Switch platform builds to push-by-digest (outputs: push-by-digest=true)
  so no SHA-suffixed intermediate tags accumulate in GHCR; digests are
  passed between jobs via outputs and referenced directly in imagetools create
- Add type=ref,event=tag to all merge jobs so workflow_dispatch on a tag
  ref always produces at least one --tag destination

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.

Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
Replace echo with printf + grep -v '^$' in the TAGS construction of all
three merge jobs. echo always emits a trailing newline so an empty tags
output would produce '--tag ' (with no value), causing imagetools create
to fail. The grep filter drops blank lines so TAGS is truly empty when
no tags are generated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 6 comments.

Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml
marc0olo and others added 2 commits June 11, 2026 02:01
Required for cache-from/cache-to: type=gha — without it the GHA cache
backend denies both reads and writes when permissions are explicitly set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@marc0olo

Copy link
Copy Markdown
Member Author

Reverting the actions: write addition from the last Copilot suggestion (commit 943e827).

The cache-from/cache-to: type=gha backend in BuildKit does not use GITHUB_TOKEN — it uses ACTIONS_RUNTIME_TOKEN, which is a separate short-lived token automatically provisioned by the GitHub Actions runner. The permissions: key in a workflow YAML only controls GITHUB_TOKEN scopes, so adding actions: write there has no effect on whether the GHA cache works.

The suggestion cited a real failure mode (cache access being denied in restricted-permission contexts) but the wrong fix. The cache will work correctly with just contents: read and packages: write as originally written.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.

Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
grep -v '^$' exits 1 when all input lines are empty, which would fail
the merge step under bash -e before imagetools create runs. awk NF
filters blank lines identically but always exits 0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

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.

2 participants