ci: run pipeline natively on arm64 act runners
Build Talos CM5 Image / build (push) Failing after 9s

- runs-on: arm64 (was talos-rpi5/macOS Mac Mini)
- replace Homebrew deps with native arm64 (crane+jq static binaries)
- gmake -> make across workflows and auto-update.sh
- guard Homebrew gnu-sed PATH in Makefile for Linux
- no QEMU/binfmt — builds are native arm64
- docs: TECHNICAL.md runner setup for ASUS GX10

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mathias Beaulieu-Duncan
2026-06-16 09:54:19 -04:00
parent fa93fe06c4
commit 238a814d61
5 changed files with 72 additions and 37 deletions
+27 -15
View File
@@ -1,13 +1,13 @@
# Build and release custom Talos CM5 image
#
# Triggered by pushing a version tag (e.g. v1.11.5-1)
# Runs on ARM64 self-hosted runner (ASUS GX10)
#
# Produces:
# - Installer container image → Docker Hub (svrnty/talos-rpi5:<tag>)
# - Raw disk image → Gitea release (metal-arm64.raw.zst)
#
# Runner: Apple Silicon Mac Mini (self-hosted, macOS, arm64)
# Runner: ASUS GX10 (self-hosted, Linux, arm64), host mode.
# Builds natively on arm64 — no QEMU/binfmt emulation.
name: Build Talos CM5 Image
@@ -18,7 +18,7 @@ on:
jobs:
build:
runs-on: talos-rpi5
runs-on: arm64
timeout-minutes: 180
steps:
@@ -30,14 +30,26 @@ jobs:
- name: Install build dependencies
run: |
for pkg in make gnu-sed crane; do
brew list --formula "$pkg" &>/dev/null || brew install "$pkg"
done
echo "/opt/homebrew/opt/gnu-sed/libexec/gnubin" >> "$GITHUB_PATH"
gmake --version | head -1
# Native arm64 host — make, sed, git, docker and buildx come from the host.
# Only crane + jq are fetched (static arm64 binaries, no sudo, no QEMU).
mkdir -p "$HOME/.local/bin"
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
export PATH="$HOME/.local/bin:$PATH"
if ! command -v crane >/dev/null 2>&1; then
curl -fsSL https://github.com/google/go-containerregistry/releases/latest/download/go-containerregistry_Linux_arm64.tar.gz \
| tar -xz -C "$HOME/.local/bin" crane
fi
if ! command -v jq >/dev/null 2>&1; then
curl -fsSL https://github.com/jqlang/jq/releases/latest/download/jq-linux-arm64 -o "$HOME/.local/bin/jq"
chmod +x "$HOME/.local/bin/jq"
fi
make --version | head -1
crane version || true
- name: Set up Docker Buildx
run: |
# Native arm64 builder — the docker-container driver is used only for
# SBOM/provenance attestation, not for cross-arch (no QEMU registered).
docker buildx version
docker buildx create --name talos-builder --driver docker-container --use 2>/dev/null || docker buildx use talos-builder
docker buildx inspect --bootstrap
@@ -50,22 +62,22 @@ jobs:
run: echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
- name: Clone upstream sources
run: gmake checkouts
run: make checkouts
- name: Apply patches
run: gmake patches
run: make patches
- name: Build kernel
run: gmake kernel
run: make kernel
- name: Build SBC overlay
run: gmake overlay
run: make overlay
- name: Build installer and disk image
run: gmake installer
run: make installer
- name: Tag release images
run: gmake release TAG=${{ steps.version.outputs.tag }}
run: make release TAG=${{ steps.version.outputs.tag }}
- name: Compress disk image
run: |
@@ -126,4 +138,4 @@ jobs:
- name: Clean up
if: always()
run: gmake clean
run: make clean
+15 -6
View File
@@ -13,7 +13,7 @@ on:
jobs:
check-and-build:
runs-on: talos-rpi5
runs-on: arm64
timeout-minutes: 15
steps:
@@ -24,10 +24,19 @@ jobs:
- name: Install dependencies
run: |
for pkg in make gnu-sed crane jq; do
brew list --formula "$pkg" &>/dev/null || brew install "$pkg"
done
echo "/opt/homebrew/opt/gnu-sed/libexec/gnubin" >> "$GITHUB_PATH"
# Native arm64 host — make, sed, git come from the host.
# Only crane + jq are fetched (static arm64 binaries, no sudo, no QEMU).
mkdir -p "$HOME/.local/bin"
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
export PATH="$HOME/.local/bin:$PATH"
if ! command -v crane >/dev/null 2>&1; then
curl -fsSL https://github.com/google/go-containerregistry/releases/latest/download/go-containerregistry_Linux_arm64.tar.gz \
| tar -xz -C "$HOME/.local/bin" crane
fi
if ! command -v jq >/dev/null 2>&1; then
curl -fsSL https://github.com/jqlang/jq/releases/latest/download/jq-linux-arm64 -o "$HOME/.local/bin/jq"
chmod +x "$HOME/.local/bin/jq"
fi
- name: Check for upstream updates
id: check
@@ -86,7 +95,7 @@ jobs:
### Steps
1. Check out this repo and run \`scripts/auto-update.sh\` to see what fails
2. Port patches to the new upstream version
3. Verify: \`gmake checkouts patches && gmake checkouts-clean\`
3. Verify: \`make checkouts patches && make checkouts-clean\`
4. Push changes — the next scheduled run will pick them up
### Links
+4 -1
View File
@@ -15,8 +15,11 @@ PKG_VERSION = v1.13.0
TALOS_VERSION = v1.13.2
SBCOVERLAY_VERSION = main
# Prefer GNU coreutils (macOS: brew install gnu-sed coreutils)
# Prefer GNU coreutils. Native on the Linux arm64 runner; on macOS use the
# Homebrew gnu-sed if present (brew install gnu-sed coreutils).
ifneq ($(wildcard /opt/homebrew/opt/gnu-sed/libexec/gnubin),)
export PATH := /opt/homebrew/opt/gnu-sed/libexec/gnubin:$(PATH)
endif
REGISTRY ?= docker.io
REGISTRY_USERNAME ?= svrnty
+20 -12
View File
@@ -37,32 +37,40 @@ A weekly scheduled workflow checks for new Talos and RPi kernel releases and cre
| `REGISTRY_USERNAME` | Docker Hub username (org-level) |
| `REGISTRY_PASSWORD` | Docker Hub access token (org-level) |
## Runner Setup (Apple Silicon Mac Mini)
## Runner Setup (ASUS GX10 — Linux arm64)
The build runner needs:
- Docker Desktop with Buildx (arm64 native)
- Gitea `act_runner` registered with labels: `self-hosted`, `macOS`, `arm64`
Builds run **natively on arm64** — no QEMU/binfmt emulation. The runner executes
jobs in **host mode** (directly on the Linux host, not in a container), so the
host provides the toolchain.
The build host needs:
- Docker Engine + the Buildx plugin (arm64 native)
- `make`, `git`, `curl`, `tar` (e.g. `apt-get install -y make git curl tar`)
- Sufficient disk space for kernel builds (~20GB)
```bash
# Install act_runner via Homebrew
brew install act_runner
`crane` and `jq` are fetched automatically by the workflows (static arm64
binaries into `~/.local/bin`), so they don't need to be pre-installed.
# Or download directly
curl -sL https://gitea.com/gitea/act_runner/releases/latest/download/act_runner-darwin-arm64 -o act_runner
```bash
# Download the act_runner for linux/arm64
curl -sL https://gitea.com/gitea/act_runner/releases/latest/download/act_runner-linux-arm64 -o act_runner
chmod +x act_runner
# Register
# Register — the `:host` label runs jobs directly on the host (no container)
./act_runner register \
--instance https://git.openharbor.io \
--token <runner-token> \
--name mac-mini \
--labels self-hosted,macOS,arm64
--name gx10 \
--labels arm64:host
# Run as service
./act_runner daemon
```
> The workflows use `runs-on: arm64`. The `arm64:host` label maps that to host
> execution; drop `:host` only if you switch to container-based jobs (which then
> need Docker-in-Docker for the privileged build steps).
## Project Structure
```
+6 -3
View File
@@ -21,6 +21,9 @@ LATEST_RPI_TAG=${LATEST_RPI_TAG:-}
MAKEFILE="Makefile"
PATCH_FILE="patches/siderolabs/pkgs/0001-Patched-for-Raspberry-Pi-5.patch"
# GNU make: `gmake` on macOS (Homebrew), `make` on the Linux arm64 runner.
MAKE=$(command -v gmake || command -v make)
# Helper: extract kernel semver (e.g. 6.12.47) from the RPi repo Makefile
get_kernel_version() {
local tag="$1"
@@ -81,13 +84,13 @@ fi
# ── Smoke test — verify patches apply ───────────────────────────────
echo "Running patch smoke test ..." >&2
if ! gmake checkouts patches; then
if ! "$MAKE" checkouts patches; then
echo "Patches failed to apply!" >&2
gmake checkouts-clean >/dev/null 2>&1 || true
"$MAKE" checkouts-clean >/dev/null 2>&1 || true
echo "patch_failed=true"
exit 0
fi
gmake checkouts-clean >/dev/null 2>&1
"$MAKE" checkouts-clean >/dev/null 2>&1
# ── Generate tag ────────────────────────────────────────────────────
TALOS_VER=$(grep '^TALOS_VERSION' "$MAKEFILE" | awk '{print $NF}')