fix(docker): build the frontend and the binary once, and cross-compile
Two of the last five releases died at exit 132 — SIGILL, an instruction
QEMU does not implement — partway through `npm run build`. It reads as a
broken build and is a broken emulator.
The cause is that neither builder stage was pinned to the build platform,
so buildx ran both once per target: Node and esbuild under emulation for
arm64, and the entire Go toolchain too. Nothing in either stage needs to be
the target architecture. The frontend produces HTML, CSS and JavaScript,
which are the same bytes wherever the image runs, and Go cross-compiles
natively with CGO already off.
So both are `--platform=$BUILDPLATFORM` now, and the binary is built with
`GOARCH=${TARGETARCH}`. The frontend is built once instead of twice, and
nothing is emulated at all — which should also take most of the fifteen
minutes off a release.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c2e2d66e76
commit
b0ab6ee5c0
+20
-3
@@ -5,7 +5,17 @@
|
|||||||
# manager and no libc — the attack surface of the running container is the binary.
|
# manager and no libc — the attack surface of the running container is the binary.
|
||||||
|
|
||||||
# --- 1. the web interface ----------------------------------------------------
|
# --- 1. the web interface ----------------------------------------------------
|
||||||
FROM node:22-alpine AS web
|
#
|
||||||
|
# Pinned to the *build* platform, not the target. What this stage produces is
|
||||||
|
# HTML, CSS and JavaScript, which are the same bytes whatever the image will run
|
||||||
|
# on — so building it once and copying it into both architectures is not an
|
||||||
|
# optimisation, it is the correct thing.
|
||||||
|
#
|
||||||
|
# Without the pin, buildx runs this stage once per target, which means running
|
||||||
|
# Node and esbuild under QEMU for arm64. That crashes: exit 132, SIGILL, an
|
||||||
|
# instruction the emulator does not implement, roughly one release in three. It
|
||||||
|
# looks like a broken build and is a broken emulator.
|
||||||
|
FROM --platform=$BUILDPLATFORM node:22-alpine AS web
|
||||||
|
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY web/ ./
|
COPY web/ ./
|
||||||
@@ -24,7 +34,12 @@ RUN if [ -f package.json ]; then \
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# --- 2. the binary -----------------------------------------------------------
|
# --- 2. the binary -----------------------------------------------------------
|
||||||
FROM golang:1.26-alpine AS build
|
#
|
||||||
|
# Also pinned to the build platform, and cross-compiled instead. Go does that
|
||||||
|
# natively and CGO is already off, so there is nothing to emulate — where
|
||||||
|
# building *in* the target architecture means running the whole Go toolchain
|
||||||
|
# under QEMU for one of the two.
|
||||||
|
FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS build
|
||||||
|
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
|
|
||||||
@@ -37,11 +52,13 @@ COPY . .
|
|||||||
COPY --from=web /src/build ./cmd/verdande/webbuild
|
COPY --from=web /src/build ./cmd/verdande/webbuild
|
||||||
|
|
||||||
ARG VERSION=dev
|
ARG VERSION=dev
|
||||||
|
# Supplied by buildx per target. The default keeps a plain `docker build` working.
|
||||||
|
ARG TARGETARCH=amd64
|
||||||
|
|
||||||
# CGO off is what makes this binary static, and it is only possible because the
|
# CGO off is what makes this binary static, and it is only possible because the
|
||||||
# SQLite driver is pure Go. -trimpath and the empty buildid keep the output
|
# SQLite driver is pure Go. -trimpath and the empty buildid keep the output
|
||||||
# reproducible; -s -w drop the symbol and DWARF tables, which is most of the size.
|
# reproducible; -s -w drop the symbol and DWARF tables, which is most of the size.
|
||||||
RUN CGO_ENABLED=0 GOOS=linux go build \
|
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} go build \
|
||||||
-tags embedweb \
|
-tags embedweb \
|
||||||
-trimpath \
|
-trimpath \
|
||||||
-ldflags="-s -w -buildid= -X main.version=${VERSION}" \
|
-ldflags="-s -w -buildid= -X main.version=${VERSION}" \
|
||||||
|
|||||||
Reference in New Issue
Block a user