From a55d4c6c0fa8420ef90d915769bacc062771e445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elliot=20Morales=20Sol=C3=A9?= <5107985+elliotmoso@users.noreply.github.com> Date: Wed, 26 Aug 2026 17:57:02 +0200 Subject: [PATCH] build: pin the builder stage to the host platform The build already cross-compiles explicitly (CGO_ENABLED=0, GOOS=linux, GOARCH=$TARGETARCH), so the toolchain never needs to match the target arch. Without --platform=$BUILDPLATFORM a cross-arch build runs the entire Go compilation under QEMU emulation for a byte-identical binary: building linux/amd64 on an arm64 host went from minutes to still-running after ten. Only the final stage stays on $TARGETPLATFORM, where it belongs. go-version.sh reads the Go version out of the builder's FROM line, so its pattern now accepts an optional --platform flag before the image. --- .github/scripts/go-version.sh | 4 ++-- Dockerfile | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/scripts/go-version.sh b/.github/scripts/go-version.sh index 9ce6fab1a..d01bdb913 100755 --- a/.github/scripts/go-version.sh +++ b/.github/scripts/go-version.sh @@ -35,10 +35,10 @@ if [ ! -f "$dockerfile" ]; then exit 1 fi -version=$(sed -nE 's/^FROM[[:space:]]+golang:([0-9]+\.[0-9]+\.[0-9]+)[^[:space:]]*.*/\1/p' "$dockerfile" | sort -u) +version=$(sed -nE 's/^FROM[[:space:]]+(--platform=[^[:space:]]+[[:space:]]+)?golang:([0-9]+\.[0-9]+\.[0-9]+)[^[:space:]]*.*/\2/p' "$dockerfile" | sort -u) if [ -z "$version" ]; then - echo "$dockerfile: no pinned 'FROM golang:X.Y.Z-...' base image found" >&2 + echo "$dockerfile: no pinned 'FROM [--platform=...] golang:X.Y.Z-...' base image found" >&2 exit 1 fi diff --git a/Dockerfile b/Dockerfile index 733fb5e37..01db04889 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,13 @@ # This image is also the single source of truth for the Go toolchain: CI reads the # version out of this line (see .github/scripts/go-version.sh) so tests and images # always run the same runtime. -FROM golang:1.27.3-alpine3.24@sha256:f2c872bcee949b7be9c490efd02b48a8a2fbf947cdf533f1c58525ec9d8170fd AS builder +# --platform=$BUILDPLATFORM pins the BUILDER to the host's own architecture. The +# build below already cross-compiles explicitly (CGO_ENABLED=0, GOOS=linux, +# GOARCH=$TARGETARCH), so the toolchain never needs to be the target's arch — +# and without this line a cross-arch build runs the whole Go compilation under +# QEMU emulation, which is roughly an order of magnitude slower for an identical +# binary. Only the final stage stays on $TARGETPLATFORM, where it belongs. +FROM --platform=$BUILDPLATFORM golang:1.27.3-alpine3.24@sha256:f2c872bcee949b7be9c490efd02b48a8a2fbf947cdf533f1c58525ec9d8170fd AS builder ARG TARGETPLATFORM ARG TARGETARCH