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 <me@silverwind.io>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
This commit is contained in:
silverwind
2026-02-17 09:25:07 +01:00
committed by GitHub
parent 1b874d1403
commit 883af8d42d
2 changed files with 24 additions and 15 deletions
+13 -9
View File
@@ -1,5 +1,12 @@
# syntax=docker/dockerfile:1 # 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 FROM docker.io/library/golang:1.26-alpine3.23 AS build-env
ARG GOPROXY=direct ARG GOPROXY=direct
@@ -12,22 +19,19 @@ ARG CGO_EXTRA_CFLAGS
# Build deps # Build deps
RUN apk --no-cache add \ RUN apk --no-cache add \
build-base \ build-base \
git \ git
nodejs \
pnpm
WORKDIR ${GOPATH}/src/code.gitea.io/gitea 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. # 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 will be mounted later separately for getting version data. # ".git" directory is mounted separately later only for version data extraction.
# 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.
COPY --exclude=.git/ . . COPY --exclude=.git/ . .
COPY --from=frontend-build /src/public/assets public/assets
# Build gitea, .git mount is required for version data # Build gitea, .git mount is required for version data
RUN --mount=type=cache,target=/go/pkg/mod \ RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target="/root/.cache/go-build" \ --mount=type=cache,target="/root/.cache/go-build" \
--mount=type=cache,target=/root/.local/share/pnpm/store \
--mount=type=bind,source=".git/",target=".git/" \ --mount=type=bind,source=".git/",target=".git/" \
make make backend
COPY docker/root /tmp/local COPY docker/root /tmp/local
+11 -6
View File
@@ -1,5 +1,12 @@
# syntax=docker/dockerfile:1 # 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 FROM docker.io/library/golang:1.26-alpine3.23 AS build-env
ARG GOPROXY=direct ARG GOPROXY=direct
@@ -12,20 +19,18 @@ ARG CGO_EXTRA_CFLAGS
# Build deps # Build deps
RUN apk --no-cache add \ RUN apk --no-cache add \
build-base \ build-base \
git \ git
nodejs \
pnpm
WORKDIR ${GOPATH}/src/code.gitea.io/gitea WORKDIR ${GOPATH}/src/code.gitea.io/gitea
# See the comments in Dockerfile # See the comments in Dockerfile
COPY --exclude=.git/ . . COPY --exclude=.git/ . .
COPY --from=frontend-build /src/public/assets public/assets
# Build gitea, .git mount is required for version data # Build gitea, .git mount is required for version data
RUN --mount=type=cache,target=/go/pkg/mod \ RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target="/root/.cache/go-build" \ --mount=type=cache,target="/root/.cache/go-build" \
--mount=type=cache,target=/root/.local/share/pnpm/store \
--mount=type=bind,source=".git/",target=".git/" \ --mount=type=bind,source=".git/",target=".git/" \
make make backend
COPY docker/rootless /tmp/local COPY docker/rootless /tmp/local