Skip to content

Fix multi-arch Docker build SIGILL by splitting frontend stage#36646

Merged
silverwind merged 5 commits into
go-gitea:mainfrom
silverwind:riscfix
Feb 17, 2026
Merged

Fix multi-arch Docker build SIGILL by splitting frontend stage#36646
silverwind merged 5 commits into
go-gitea:mainfrom
silverwind:riscfix

Conversation

@silverwind
Copy link
Copy Markdown
Member

@silverwind silverwind commented Feb 16, 2026

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

Context

The docker-dryrun CI has been failing with 100% rate whenever the container job is triggered because esbuild's native arm64 binary crashes under QEMU user-mode emulation. This is a known class of issues (evanw/esbuild#3153, docker/buildx#2028). The previous Dockerfile had a TODO comment anticipating this fix.

Test plan

  • Verify docker-dryrun CI passes (container job)
  • Verify the produced images work correctly on amd64, arm64, and riscv64

🤖 Generated with Claude Code

Build frontend assets on the native platform ($BUILDPLATFORM) in a
separate stage to avoid running esbuild/webpack under QEMU emulation,
which causes SIGILL on arm64/riscv64. Frontend assets (JS/CSS/fonts)
are platform-independent and only need to be built once.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Feb 16, 2026
@silverwind
Copy link
Copy Markdown
Member Author

silverwind commented Feb 16, 2026

This fixes the persistent build issue with SIGILL seen in docker-dryrun on riscv64 while speeding up the docker build itself by building frontend assets only once and not on every platform separately.

@silverwind
Copy link
Copy Markdown
Member Author

Example of the SIGILL failure: https://github.com/go-gitea/gitea/actions/runs/22049014112/job/63703196222

#36 [linux/arm64 build-env 5/7] RUN make
#36 279.3 undefined
#36 279.4  ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL  Command was killed with SIGILL (Invalid machine instruction): webpack --disable-interpret
#36 279.8 make: *** [Makefile:806: public/assets/js/index.js] Error 1

@silverwind silverwind added type/bug topic/build PR changes how Gitea is built, i.e. regarding Docker or the Makefile labels Feb 16, 2026
@silverwind silverwind requested a review from Copilot February 16, 2026 10:33
@silverwind silverwind marked this pull request as draft February 16, 2026 10:34
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes multi-architecture Docker build failures by splitting the build process into two stages: a frontend build stage that runs on the native platform and a backend build stage that runs on each target architecture. This change addresses SIGILL crashes caused by running esbuild under QEMU emulation when building for arm64 and riscv64.

Changes:

  • Split Dockerfile into frontend-build and build-env stages, with frontend running on $BUILDPLATFORM
  • Removed nodejs/pnpm dependencies from backend build stage since they're no longer needed
  • Changed backend stage to run make backend instead of make to avoid attempting frontend rebuild
  • Applied identical changes to both Dockerfile and Dockerfile.rootless for consistency

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
Dockerfile Added frontend-build stage on native platform; backend stage now copies frontend assets and only builds Go binary
Dockerfile.rootless Identical split-stage changes as Dockerfile, maintaining consistency for rootless builds

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Dockerfile
@silverwind
Copy link
Copy Markdown
Member Author

Assuming dryrun completes, this should be ready.

@silverwind silverwind marked this pull request as ready for review February 16, 2026 11:05
Comment thread Dockerfile
Comment thread Dockerfile.rootless
Address review feedback: add comment explaining why COPY is used
instead of bind mount in Dockerfile, and restore the cross-reference
comment in Dockerfile.rootless.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@silverwind
Copy link
Copy Markdown
Member Author

FYI, This branch results in a roughly 9% speed up of the docker-dryun workflow because of the frontend build now only executing once.

@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Feb 17, 2026
Copy link
Copy Markdown
Contributor

@TheFox0x7 TheFox0x7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tested it - image builds properly, there's no size difference and it starts as before so I see no issues.

Comment thread Dockerfile Outdated
@GiteaBot GiteaBot added lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. and removed lgtm/need 1 This PR needs approval from one additional maintainer to be merged. labels Feb 17, 2026
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
Signed-off-by: silverwind <me@silverwind.io>
@silverwind silverwind added the reviewed/wait-merge This pull request is part of the merge queue. It will be merged soon. label Feb 17, 2026
@silverwind silverwind enabled auto-merge (squash) February 17, 2026 08:24
@silverwind silverwind merged commit 883af8d into go-gitea:main Feb 17, 2026
23 checks passed
@GiteaBot GiteaBot added this to the 1.26.0 milestone Feb 17, 2026
@silverwind silverwind deleted the riscfix branch February 17, 2026 08:28
@wxiaoguang
Copy link
Copy Markdown
Contributor

Very useful improvement.

ps: I was trying to look for something like INCLUDE ./Dockerfile.common to share the FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build step , but I failed. It seems that Docker still doesn't have easy support for "build file inclusion" officially.

@silverwind
Copy link
Copy Markdown
Member Author

Yeah something to eliminate the duplication would be nice.

@TheFox0x7
Copy link
Copy Markdown
Contributor

Podman has support for cpp preprocessing so you could have #include <Dockerfile.common> but... it's less then great. IMO if you want to de-duplicate it somewhat then a single file would be easiest. Otherwise I think docker's bake could do this, though it would make my local builds funny if we swap.

@GiteaBot GiteaBot removed the reviewed/wait-merge This pull request is part of the merge queue. It will be merged soon. label Feb 17, 2026
@go-gitea go-gitea locked as resolved and limited conversation to collaborators May 18, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. topic/build PR changes how Gitea is built, i.e. regarding Docker or the Makefile type/bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants