mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-12 02:19:43 +00:00
build: Cache the isolated-vm native compile across application changes (#36065)
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
653dfc6cf7
commit
409e3dfe6f
@@ -1,34 +1,35 @@
|
||||
ARG NODE_VERSION=24.18.1
|
||||
ARG N8N_VERSION=snapshot
|
||||
|
||||
# Builder stage exists because the runtime base image has no toolchain.
|
||||
# Pinned to multi-arch index digest (linux/amd64 + linux/arm64) for reproducible builds.
|
||||
# Bump the digest together with the tag when updating the base image.
|
||||
# Digest pins to node:24.18.1-alpine3.24 (Node 24.18.1, Alpine 3.24).
|
||||
FROM node:24.18.1-alpine3.24@sha256:f70403e87646dc51b45295f4b8b70cdad0b63d2297c4c9899119b03f7af7a6b3 AS builder
|
||||
COPY ./compiled /usr/local/lib/node_modules/n8n
|
||||
RUN apk add --no-cache python3 make g++ && \
|
||||
cd /usr/local/lib/node_modules/n8n && \
|
||||
npm rebuild sqlite3 && \
|
||||
# Rebuild isolated-vm from source. node-gyp-build's musl detection relies
|
||||
# on /etc/alpine-release which DHI Alpine omits, so the bundled prebuilt
|
||||
# loader picks the glibc binary and segfaults in musl pthread paths.
|
||||
# Removing prebuilds and invoking node-gyp directly avoids npm rebuild's
|
||||
# double-build behavior (built-in node-gyp + install-script node-gyp)
|
||||
# which races on dep-file state.
|
||||
# Use npm's bundled node-gyp rather than `npx node-gyp` so the toolchain
|
||||
# version is fixed by the pinned image digest instead of being fetched
|
||||
# from the registry at build time.
|
||||
rm -rf node_modules/isolated-vm/prebuilds && \
|
||||
cd node_modules/isolated-vm && \
|
||||
# The runtime base has no compiler, so this stage supplies one.
|
||||
# The digest pins node:24.18.1-alpine3.24 for amd64 and arm64. Change the tag and the digest together.
|
||||
FROM node:24.18.1-alpine3.24@sha256:f70403e87646dc51b45295f4b8b70cdad0b63d2297c4c9899119b03f7af7a6b3 AS toolchain
|
||||
RUN apk add --no-cache python3 make g++
|
||||
|
||||
# Build isolated-vm in a separate stage. The only cache input is the module source.
|
||||
# Below `COPY ./compiled`, each application change starts a new compile.
|
||||
FROM toolchain AS native-builder
|
||||
# `node_modules/isolated-vm` is a pnpm symlink, so copy the target directory.
|
||||
# The wildcard tracks the version in the catalog.
|
||||
COPY ./compiled/node_modules/.pnpm/isolated-vm@*/node_modules/isolated-vm /build/isolated-vm
|
||||
WORKDIR /build/isolated-vm
|
||||
# node-gyp-build reads /etc/alpine-release to detect musl. DHI Alpine has no such file,
|
||||
# so the loader takes the glibc prebuild and crashes. Build from source instead.
|
||||
# Call node-gyp directly: `npm rebuild` starts two builds that conflict, and
|
||||
# `npx node-gyp` downloads a different version at build time.
|
||||
RUN rm -rf prebuilds && \
|
||||
node /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js rebuild --release -j max
|
||||
|
||||
# Pinned to multi-arch index digest (linux/amd64 + linux/arm64) for reproducible builds.
|
||||
# n8nio/base is republished by a separate workflow (docker/images/n8n-base) on every
|
||||
# base change, so a base rebuild does not reach this image until the digest is
|
||||
# manually re-pinned here. Bump the digest together with the tag whenever the base
|
||||
# image is intentionally updated.
|
||||
# Digest pins to n8nio/base:24.18.1 (Node 24.18.1, Alpine 3.24).
|
||||
FROM toolchain AS builder
|
||||
COPY ./compiled /usr/local/lib/node_modules/n8n
|
||||
RUN cd /usr/local/lib/node_modules/n8n && npm rebuild sqlite3
|
||||
COPY --from=native-builder /build/isolated-vm/build/Release/isolated_vm.node \
|
||||
/usr/local/lib/node_modules/n8n/node_modules/isolated-vm/build/Release/isolated_vm.node
|
||||
# node-gyp-build finds build/Release first. Delete the prebuilds to remove the glibc fallback.
|
||||
RUN rm -rf /usr/local/lib/node_modules/n8n/node_modules/isolated-vm/prebuilds
|
||||
|
||||
# The digest pins n8nio/base:24.18.1 for amd64 and arm64. A separate workflow builds that
|
||||
# image, so a new base reaches this image only when you change the digest here.
|
||||
FROM n8nio/base:24.18.1@sha256:f7a23e449f093b8b203467919e969ca35d12ba959442aadc1f69bb174b160ad2
|
||||
|
||||
ARG N8N_VERSION
|
||||
@@ -42,7 +43,7 @@ WORKDIR /home/node
|
||||
COPY --from=builder /usr/local/lib/node_modules/n8n /usr/local/lib/node_modules/n8n
|
||||
COPY docker/images/n8n/docker-entrypoint.sh /
|
||||
|
||||
# The Alpine 3.24 base has no /usr/local/bin (node lives in /usr/bin); create it for the symlink.
|
||||
# The base keeps node in /usr/bin and has no /usr/local/bin. Make that directory for the symlink.
|
||||
RUN mkdir -p /usr/local/bin && \
|
||||
ln -s /usr/local/lib/node_modules/n8n/bin/n8n /usr/local/bin/n8n && \
|
||||
mkdir -p /home/node/.n8n && \
|
||||
|
||||
Reference in New Issue
Block a user