From 883af8d42d49b9eb9f287baf25b1e363f469e370 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 17 Feb 2026 09:25:07 +0100 Subject: [PATCH] Fix multi-arch Docker build SIGILL by splitting frontend stage (#36646) ## Summary - Split Dockerfile and Dockerfile.rootless into a two-stage build: frontend assets are built on the native platform (`$BUILDPLATFORM`) then copied to the per-architecture backend build stage - This avoids running esbuild/webpack under QEMU emulation which causes SIGILL (Invalid machine instruction) on arm64/riscv64 - Frontend assets (JS/CSS/fonts) are platform-independent so they only need to be built once - The `build-env` stage no longer needs `nodejs`/`pnpm` since it only builds the Go backend Signed-off-by: silverwind Co-authored-by: Claude Opus 4.6 Co-authored-by: TheFox0x7 --- Dockerfile | 22 +++++++++++++--------- Dockerfile.rootless | 17 +++++++++++------ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Dockerfile b/Dockerfile index 79f507dbc68..f71b13e8f3c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,12 @@ # syntax=docker/dockerfile:1 -# Build stage +# Build frontend on the native platform to avoid QEMU-related issues with esbuild/webpack +FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build +RUN apk --no-cache add build-base git nodejs pnpm +WORKDIR /src +COPY --exclude=.git/ . . +RUN --mount=type=cache,target=/root/.local/share/pnpm/store make frontend + +# Build backend for each target platform FROM docker.io/library/golang:1.26-alpine3.23 AS build-env ARG GOPROXY=direct @@ -12,22 +19,19 @@ ARG CGO_EXTRA_CFLAGS # Build deps RUN apk --no-cache add \ build-base \ - git \ - nodejs \ - pnpm + git WORKDIR ${GOPATH}/src/code.gitea.io/gitea -# Use COPY but not "mount" because some directories like "node_modules" contain platform-depended contents and these directories need to be ignored. -# ".git" directory will be mounted later separately for getting version data. -# TODO: in the future, maybe we can pre-build the frontend assets on one platform and share them for different platforms, the benefit is that it won't be affected by webpack plugin compatibility problems, then the working directory can be fully mounted and the COPY is not needed. +# Use COPY instead of bind mount as read-only one breaks makefile state tracking and read-write one needs binary to be moved as it's discarded. +# ".git" directory is mounted separately later only for version data extraction. COPY --exclude=.git/ . . +COPY --from=frontend-build /src/public/assets public/assets # Build gitea, .git mount is required for version data RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target="/root/.cache/go-build" \ - --mount=type=cache,target=/root/.local/share/pnpm/store \ --mount=type=bind,source=".git/",target=".git/" \ - make + make backend COPY docker/root /tmp/local diff --git a/Dockerfile.rootless b/Dockerfile.rootless index fe94774add7..bc210132c53 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,5 +1,12 @@ # syntax=docker/dockerfile:1 -# Build stage +# Build frontend on the native platform to avoid QEMU-related issues with esbuild/webpack +FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build +RUN apk --no-cache add build-base git nodejs pnpm +WORKDIR /src +COPY --exclude=.git/ . . +RUN --mount=type=cache,target=/root/.local/share/pnpm/store make frontend + +# Build backend for each target platform FROM docker.io/library/golang:1.26-alpine3.23 AS build-env ARG GOPROXY=direct @@ -12,20 +19,18 @@ ARG CGO_EXTRA_CFLAGS # Build deps RUN apk --no-cache add \ build-base \ - git \ - nodejs \ - pnpm + git WORKDIR ${GOPATH}/src/code.gitea.io/gitea # See the comments in Dockerfile COPY --exclude=.git/ . . +COPY --from=frontend-build /src/public/assets public/assets # Build gitea, .git mount is required for version data RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target="/root/.cache/go-build" \ - --mount=type=cache,target=/root/.local/share/pnpm/store \ --mount=type=bind,source=".git/",target=".git/" \ - make + make backend COPY docker/rootless /tmp/local