From 42d843235636804641d5d4222ecf14dc7d57da98 Mon Sep 17 00:00:00 2001 From: Joshua B Fleitell Date: Sat, 5 Sep 2026 13:46:19 -0400 Subject: [PATCH 1/2] ci: build on native arm64 runners instead of QEMU-emulated x86_64 Both image builds ran on ubuntu-latest (x86_64) and emulated the whole chroot provisioning stage via qemu-aarch64-static -- every apt-get/dpkg call inside the mounted arm64 image ran through QEMU user-mode translation, which is commonly 5-10x slower than native for that kind of CPU-bound work. Packer's arm-image plugin already supports skipping this: it only adds the QEMU/binfmt steps when `!ImageArch.IsNative()` (pkg/builder/builder.go). Set image_arch = "arm64" in the shared dpx-buttonode.pkr.hcl and switched both builder workflows to ubuntu-24.04-arm (free, GitHub-hosted, native arm64) -- with host arch matching image_arch, the plugin skips QEMU entirely on its own, no custom logic needed. Removed the now-unnecessary qemu-user-static install steps. Verified before touching CI: Packer itself installs via HashiCorp's own apt repo (multi-arch, resolves correctly on arm64), and packer-plugin-arm-image v0.2.7 publishes a linux_arm64 build. Isolated on its own branch off main, not mixed into the action-plan hardware-fix branch -- this is unverified until a real CI run confirms it, and a broken build here shouldn't be confused with a regression in the already-tested fixes. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/armbian-builder.yaml | 13 ++++++++----- .github/workflows/raspios-builder.yaml | 12 ++++++------ dpx-buttonode.pkr.hcl | 1 + 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.github/workflows/armbian-builder.yaml b/.github/workflows/armbian-builder.yaml index ceece9a..5889689 100644 --- a/.github/workflows/armbian-builder.yaml +++ b/.github/workflows/armbian-builder.yaml @@ -283,7 +283,14 @@ on: jobs: build: - runs-on: ubuntu-latest + # Native arm64 runner -- the images we build are arm64, and Packer's + # arm-image plugin skips its QEMU/binfmt chroot steps entirely when + # image_arch (set in dpx-buttonode.pkr.hcl) matches the host's actual + # runtime arch (pkg/builder/builder.go: `!ImageArch.IsNative()`). On + # ubuntu-latest (x86_64), every apt-get/dpkg inside the chroot ran + # through qemu-aarch64-static emulation, which is commonly 5-10x + # slower than native for that kind of CPU-bound work. + runs-on: ubuntu-24.04-arm permissions: contents: read outputs: @@ -294,10 +301,6 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - # ARM emulation is required to chroot into the ARM64 Armbian image - - name: Install QEMU user-static - run: sudo apt-get update -q && sudo apt-get install -y qemu-user-static - # ── Download Bitfocus Buttons package from mirror ────────────────────── - name: Download Buttons USB Relay package from mirror env: diff --git a/.github/workflows/raspios-builder.yaml b/.github/workflows/raspios-builder.yaml index 459e766..b1ff950 100644 --- a/.github/workflows/raspios-builder.yaml +++ b/.github/workflows/raspios-builder.yaml @@ -41,7 +41,12 @@ on: jobs: build: - runs-on: ubuntu-latest + # See armbian-builder.yaml's build job for why: native arm64 runner + # lets Packer's arm-image plugin skip QEMU/binfmt entirely + # (image_arch in dpx-buttonode.pkr.hcl matches the host arch), instead + # of emulating every chroot apt-get/dpkg call via qemu-aarch64-static + # on an x86_64 runner. + runs-on: ubuntu-24.04-arm permissions: contents: read outputs: @@ -52,11 +57,6 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - # ARM emulation is required to chroot into the ARM64 image, same as - # the Armbian pipeline -- unrelated to which OS built the base image. - - name: Install QEMU user-static - run: sudo apt-get update -q && sudo apt-get install -y qemu-user-static - # ── Download Bitfocus Buttons package from mirror ────────────────────── - name: Download Buttons USB Relay package from mirror env: diff --git a/dpx-buttonode.pkr.hcl b/dpx-buttonode.pkr.hcl index a7a46c3..b309098 100644 --- a/dpx-buttonode.pkr.hcl +++ b/dpx-buttonode.pkr.hcl @@ -73,6 +73,7 @@ source "arm-image" "base" { iso_url = var.url target_image_size = var.variant == "full" ? 8000000000 : 5000000000 output_filename = "output-dpx-buttonode/dpx-buttonode.img" + image_arch = "arm64" qemu_binary = "qemu-aarch64-static" image_mounts = var.image_mounts From d3983335d1b0733a59cce8345ed5092f31cddf30 Mon Sep 17 00:00:00 2001 From: Joshua B Fleitell Date: Sat, 5 Sep 2026 14:08:21 -0400 Subject: [PATCH 2/2] fix: keep qemu-user-static install on native arm64 runners Removing it broke the build outright: packer-plugin-arm-image's Prepare() unconditionally resolves a qemu_binary path via exec.LookPath, regardless of whether the emulation is actually needed later -- only its separate Run()-time IsNative() check decides that. Without the binary present, Prepare() falls back to an "embedded qemu" feature that's amd64-only and fails outright on arm64: embedded qemu is not available - currently, embedded qemu is only available for linux amd64. please download qemu-user-static manually Confirmed via a live test build (33982012810) that failed exactly this way. Re-added the install -- it's a fast package install, not the slow part we're trying to avoid, and the plugin's own IsNative() check still skips actually invoking it during the chroot provisioning. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/armbian-builder.yaml | 12 ++++++++++++ .github/workflows/raspios-builder.yaml | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/.github/workflows/armbian-builder.yaml b/.github/workflows/armbian-builder.yaml index 5889689..38e3a47 100644 --- a/.github/workflows/armbian-builder.yaml +++ b/.github/workflows/armbian-builder.yaml @@ -301,6 +301,18 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + # Still needed even on a native arm64 runner: the plugin's Prepare() + # step unconditionally resolves a qemu_binary path via exec.LookPath + # regardless of whether it'll actually be used later -- only its + # separate Run()-time IsNative() check decides whether QEMU is + # actually invoked for the chroot. Without this installed, Prepare() + # falls back to an "embedded qemu" feature that's amd64-only and + # fails outright on arm64 (confirmed: "embedded qemu is not + # available - currently, embedded qemu is only available for linux + # amd64"). This is just a fast package install, not the slow part. + - name: Install QEMU user-static + run: sudo apt-get update -q && sudo apt-get install -y qemu-user-static + # ── Download Bitfocus Buttons package from mirror ────────────────────── - name: Download Buttons USB Relay package from mirror env: diff --git a/.github/workflows/raspios-builder.yaml b/.github/workflows/raspios-builder.yaml index b1ff950..9e548cb 100644 --- a/.github/workflows/raspios-builder.yaml +++ b/.github/workflows/raspios-builder.yaml @@ -57,6 +57,12 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + # Still needed on a native arm64 runner -- see armbian-builder.yaml's + # build job for why (Prepare()-time qemu_binary resolution is + # unconditional, only actual usage is skipped on native arch). + - name: Install QEMU user-static + run: sudo apt-get update -q && sudo apt-get install -y qemu-user-static + # ── Download Bitfocus Buttons package from mirror ────────────────────── - name: Download Buttons USB Relay package from mirror env: