Skip to content

ci: use native Go cross-compilation instead of QEMU emulation for arm64 builds - #869

Merged
kirkbrauer merged 1 commit into
mainfrom
ci/go-cross-compile-arm64
Jul 10, 2026
Merged

ci: use native Go cross-compilation instead of QEMU emulation for arm64 builds#869
kirkbrauer merged 1 commit into
mainfrom
ci/go-cross-compile-arm64

Conversation

@mangelajo

Copy link
Copy Markdown
Member

Problem

The build-images.yaml CI workflow builds Go container images for linux/amd64,linux/arm64 using Docker Buildx on ubuntu-latest (x86_64) runners. For arm64 images, the entire builder stage — including Go compilation — runs under QEMU user-static emulation, which is ~10-20x slower than native execution.

The irony is that the Containerfiles were already set up for cross-compilation (CGO_ENABLED=0, GOOS=${TARGETOS}, GOARCH=${TARGETARCH}), but the builder stage was still being emulated because it lacked the --platform=$BUILDPLATFORM directive.

Solution

Add --platform=$BUILDPLATFORM to the builder FROM line in both Go Containerfiles. This tells BuildKit to run the builder stage natively on the host CPU (x86_64), while Go cross-compiles for the target architecture via GOARCH=${TARGETARCH}.

Files changed

File Change
controller/Containerfile Add --platform=$BUILDPLATFORM to builder FROM
controller/Containerfile.operator Add --platform=$BUILDPLATFORM to builder FROM
controller/Makefile Remove Containerfile.cross workaround from docker-buildx target
controller/deploy/operator/Makefile Remove Containerfile.operator.cross workaround from docker-buildx target

Why this is safe

  • CGO_ENABLED=0 — pure Go, no C toolchain needed
  • Go has first-class cross-compilation support for all target architectures
  • The Makefile docker-buildx targets already applied this exact transformation via a sed workaround (generating temporary Containerfile.cross files) — this PR makes it permanent and removes the workaround
  • Single-arch docker-build is unaffected ($BUILDPLATFORM equals the target platform)
  • The runtime stage (FROM ubi-micro) is unaffected — it pulls the correct arch variant and only runs metadata operations (COPY, USER, ENTRYPOINT)

Expected impact

  • arm64 Go compilation: ~10-20x faster (native cross-compile vs QEMU emulation)
  • Overall arm64 image build: ~5-10x faster (Go compilation dominates build time)
  • amd64 builds: No change (already native)
  • No CI workflow changes needed — QEMU setup remains for other images in the matrix

…64 builds

Add --platform=$BUILDPLATFORM to the builder stage in both Go Containerfiles
so that the Go compiler runs natively on the build host (x86_64) and
cross-compiles for arm64 via GOOS/GOARCH, instead of running the entire
compilation under QEMU user-static emulation.

This is safe because CGO_ENABLED=0 and the Containerfiles already set
GOOS=${TARGETOS} GOARCH=${TARGETARCH} for cross-compilation.

Also removes the Containerfile.cross workaround from both Makefile
docker-buildx targets, since the Containerfiles now include the
--platform directive directly.

Expected speedup: ~10-20x for the arm64 Go compilation portion of CI
builds (QEMU emulation vs native cross-compile).
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cf08ee5c-6954-494e-be9c-c3e3f817a6d1

📥 Commits

Reviewing files that changed from the base of the PR and between d46e91a and d4bdeb6.

📒 Files selected for processing (4)
  • controller/Containerfile
  • controller/Containerfile.operator
  • controller/Makefile
  • controller/deploy/operator/Makefile

📝 Walkthrough

Walkthrough

The PR pins builder stage base images to $BUILDPLATFORM in controller/Containerfile and controller/Containerfile.operator, adding comments about native compilation via GOOS/GOARCH and CGO_ENABLED=0. Corresponding Makefiles are simplified to build directly from these Containerfiles, removing temporary Containerfile.cross/Containerfile.operator.cross generation and cleanup steps.

Changes

BuildPlatform Pinning and Makefile Simplification

Layer / File(s) Summary
Pin builder stage to BUILDPLATFORM
controller/Containerfile, controller/Containerfile.operator
Builder stage FROM instructions now include --platform=$BUILDPLATFORM, with comments explaining native builder execution and GOOS/GOARCH-driven cross-compilation with CGO_ENABLED=0.
Remove temporary cross Containerfile generation
controller/Makefile, controller/deploy/operator/Makefile
docker-buildx targets no longer generate or delete temporary Containerfile.cross/Containerfile.operator.cross files; buildx builds now reference the original Containerfiles directly while keeping builder lifecycle steps.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • jumpstarter-dev/jumpstarter#819: Both PRs adjust Docker multi-platform build stages to pin stages to $BUILDPLATFORM to address cross-arch Docker build failures.

Suggested labels: build-pr-images

Suggested reviewers: raballew

Poem

A hop, a build, no QEMU strife,
$BUILDPLATFORM pins the builder's life,
Cross files gone, the Makefile's light,
GOOS and GOARCH steer it right,
This bunny thumps in pure delight! 🐇🔧

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: switching arm64 image builds to native Go cross-compilation instead of QEMU emulation.
Description check ✅ Passed The description is directly about the same build optimization and matches the changed Containerfiles and Makefiles.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/go-cross-compile-arm64

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Container Images

The following container images have been built for this PR:

Image URI
jumpstarter-controller quay.io/jumpstarter-dev/jumpstarter-controller:pr-869
jumpstarter-operator quay.io/jumpstarter-dev/jumpstarter-operator:pr-869
jumpstarter-operator-bundle quay.io/jumpstarter-dev/jumpstarter-operator-bundle:pr-869
jumpstarter quay.io/jumpstarter-dev/jumpstarter:pr-869
jumpstarter-utils quay.io/jumpstarter-dev/jumpstarter-utils:pr-869
jumpstarter-dev quay.io/jumpstarter-dev/jumpstarter-dev:pr-869
jumpstarter-devspace quay.io/jumpstarter-dev/jumpstarter-devspace:pr-869

Images expire after 7 days.

@mangelajo
mangelajo requested review from bennyz and kirkbrauer July 10, 2026 08:23
@mangelajo

Copy link
Copy Markdown
Member Author

Reduces the build time of multiarch golang images to 4-6m instead of 20-25m , no more qemu-user-static.

We had that hack because podman buildx didn't support the build platform references well in previous versions, but it's fixed now.

@kirkbrauer
kirkbrauer added this pull request to the merge queue Jul 10, 2026
Merged via the queue into main with commit b453a6e Jul 10, 2026
34 checks passed
@kirkbrauer
kirkbrauer deleted the ci/go-cross-compile-arm64 branch July 10, 2026 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants