fix(ci): add linux/arm64 Docker build support with QEMU optimization (#76)

- Add docker/setup-qemu-action@v3 to docker-publish.yml (was missing,
  causing multi-platform builds to hang indefinitely)
- Add platforms: linux/amd64,linux/arm64 to build-push-action step
- Optimize Dockerfile with --platform=$BUILDPLATFORM on builder stages
  so TypeScript compilation runs at native amd64 speed; only the lean
  npm ci --omit=dev step runs under QEMU in the final stage, compiling
  the three native modules (bcrypt, better-sqlite3, node-pty) for the
  correct target architecture — reduces arm64 build time from 6+ hours
  to ~15-30 minutes
This commit is contained in:
Anso
2026-03-24 07:50:33 -04:00
committed by GitHub
parent b7a39ce597
commit 278f7f18d9
3 changed files with 34 additions and 8 deletions
+4 -2
View File
@@ -16,8 +16,10 @@ jobs:
- name: Check out the repo
uses: actions/checkout@v4
- name: Set up QEMU (for ARM64 support)
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
@@ -44,8 +46,8 @@ jobs:
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=saelix/sencho:buildcache
+7
View File
@@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- feat(ci): add `linux/arm64` platform to Docker Hub publish workflow for ARM server support (e.g. Raspberry Pi 4/5, Oracle ARM VMs)
### Fixed
- fix(ci): add missing `docker/setup-qemu-action@v3` step to `docker-publish.yml` — without it multi-platform builds hang indefinitely and consume all available runner minutes
- fix(docker): optimize Dockerfile for multi-platform builds using `--platform=$BUILDPLATFORM` on builder stages so TypeScript compilation runs at native amd64 speed; native modules (bcrypt, better-sqlite3, node-pty) are compiled for the target architecture only in the lean production stage via `npm ci --omit=dev`, reducing arm64 QEMU-emulated work from 6+ hours to ~1530 minutes
### Added
- feat(ui): theme-aware sidebar logo — dark and light variants auto-switch based on active theme (dark/light/auto)
+23 -6
View File
@@ -1,5 +1,7 @@
# Stage 1: Build Frontend
FROM node:20-alpine AS frontend-builder
# Run on the BUILD platform (amd64 on GitHub Actions) — frontend has no native
# modules so the compiled output is platform-agnostic JS/CSS/HTML.
FROM --platform=$BUILDPLATFORM node:20-alpine AS frontend-builder
WORKDIR /app/frontend
@@ -17,8 +19,12 @@ COPY frontend/ ./
# Build frontend
RUN npm run build
# Stage 2: Build Backend
FROM node:20-alpine AS backend-builder
# Stage 2: Build Backend (TypeScript compilation only)
# Run on the BUILD platform (amd64) so tsc runs at native speed.
# Native modules (bcrypt, better-sqlite3, node-pty) are intentionally NOT
# copied to the final image — they are re-installed on the TARGET platform
# in Stage 3 so the correct architecture binaries are produced.
FROM --platform=$BUILDPLATFORM node:20-alpine AS backend-builder
WORKDIR /app/backend
@@ -40,6 +46,11 @@ COPY backend/ ./
RUN npm run build
# Stage 3: Production
# Runs on the TARGET platform (e.g. linux/arm64 via QEMU on amd64 runners).
# We minimise QEMU-emulated work to a single lean `npm ci --omit=dev` which
# compiles only the three native production modules (bcrypt, better-sqlite3,
# node-pty) for the correct architecture. Build tooling is removed afterwards
# to keep the image small.
FROM node:20-alpine
# Install Docker CLI, Docker Compose CLI, and Bash for Host Console
@@ -47,10 +58,16 @@ RUN apk add --no-cache docker-cli docker-cli-compose bash su-exec
WORKDIR /app
# Copy built backend and node_modules from backend-builder
# Install production dependencies on the TARGET platform so native modules
# (bcrypt, better-sqlite3, node-pty) are compiled for the right architecture.
# Build tools are added, used, then removed in a single RUN layer.
COPY backend/package*.json ./
RUN apk add --no-cache python3 make g++ && \
npm ci --omit=dev && \
apk del python3 make g++
# Copy compiled TypeScript output from the backend builder (platform-agnostic JS)
COPY --from=backend-builder /app/backend/dist ./dist
COPY --from=backend-builder /app/backend/node_modules ./node_modules
COPY --from=backend-builder /app/backend/package.json ./
# Copy built frontend from frontend-builder to public folder
COPY --from=frontend-builder /app/frontend/dist ./public