Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit 8941c1e696360fd4a10a1dfeb107e8955f518350
parent e4bc59181ffa629a0c7c6d4fb36383af208a3398
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Mon, 28 Sep 2026 12:47:01 -0400

docker: Dockerfile.build on Node 22.23.2 and pnpm 11.26.0, and its comments say the network is on

The image installed with pnpm 9.15.4 on node:20, which does not know the
workspace's `allowBuilds` / `minimumReleaseAgeExclude`. It now pins what the
workspace runs on (node:22.23.2-bookworm-slim — bookworm like the root
Dockerfile's build stage — and pnpm 11.26.0, which needs Node >= 22.13), as
build args with those defaults.

pnpm 11 checks before every `pnpm exec` / `pnpm run` that the whole workspace
is installed and runs `pnpm install` when it is not. The image installs only
common and export, so after `COPY . .` it never is, and that install fails as
the container's non-root uid (EACCES on /repo) — the first `pnpm --filter …
exec` in build-site.sh would never start. `pnpm_config_verify_deps_before_run
=false` turns the check off (the deps are frozen at image build), and the
update notice goes with it.

Three comments said the per-site containers run with --network=none; they do
not (runDockerBuildOne leaves it on for next/font/google). They now say so, and
the corepack reason no longer rests on being offline.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Diffstat:
MDockerfile.build | 48+++++++++++++++++++++++++++++++++++-------------
1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/Dockerfile.build b/Dockerfile.build @@ -1,13 +1,24 @@ # Build image for the docker export pipeline (Build all, whenever a container engine answers). # -# Bakes the repo source + installed deps so each per-site build container is -# hermetic and reproducible. The corpus, the shared LMDB index, the .export-index +# Bakes the repo source + installed deps so every per-site build container runs +# the same toolchain and code. The corpus, the shared LMDB index, the .export-index # staging, and the archive cache are bind-mounted READ-ONLY at run time — never # baked (they're hundreds of GB and change constantly). Each container writes only # its per-site output mount (/site). Deploy never runs here; it stays on the host. +# The network is left ON at run time (common/publish/build.ts, runDockerBuildOne): +# `next build` fetches each site's fonts through next/font/google. # -# Entry: docker/build-site.sh runs `compose:site + next build` for one SITE_ID. -FROM node:20-bookworm-slim +# Entry: docker/build-site.sh runs `archilyzer build site <SITE_ID> --nodata` +# (compose + next build) for one SITE_ID. +# +# Node and pnpm are pinned to what the workspace runs on. pnpm 11 is not optional: +# pnpm-workspace.yaml's `allowBuilds` and `minimumReleaseAgeExclude` are keys +# pnpm 9 does not know, and pnpm 11 itself needs Node >= 22.13. bookworm, like +# the root Dockerfile's build stage. +ARG NODE_IMAGE=node:22.23.2-bookworm-slim +FROM ${NODE_IMAGE} + +ARG PNPM_VERSION=11.26.0 # Archive compressors the export build shells out to. `zip` is the default format; # `tar`/`xz`/`gzip` cover the other configurable archive formats. @@ -15,30 +26,41 @@ RUN apt-get update \ && apt-get install -y --no-install-recommends zip tar xz-utils gzip \ && rm -rf /var/lib/apt/lists/* -# Install pnpm as a plain global binary (NOT corepack): the fan-out containers run -# fully offline (--network=none) as an arbitrary host uid with HOME=/tmp, where -# corepack — lacking a packageManager pin — would try to fetch pnpm from the -# registry and fail. A global install needs no network at run time. -RUN npm install -g pnpm@9.15.4 +# Install pnpm as a plain global binary (NOT corepack). There is no packageManager +# pin in package.json, so corepack would download a pnpm of its own choosing at +# run time — in every container, since each runs as an arbitrary host uid with +# HOME=/tmp and keeps nothing between runs. A global install is baked once and +# needs nothing at run time. +RUN npm install -g "pnpm@${PNPM_VERSION}" WORKDIR /repo # Install deps first for layer caching — rebuilds only when a manifest or the -# lockfile moves. `onlyBuiltDependencies` in pnpm-workspace.yaml rebuilds the -# native modules (lmdb, msgpackr-extract, esbuild). +# lockfile moves. `allowBuilds` in pnpm-workspace.yaml rebuilds the native +# modules (lmdb, msgpackr-extract, esbuild) for this image. COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./ COPY common/package.json common/package.json COPY export/package.json export/package.json RUN pnpm install --frozen-lockfile +# Only common and export (and the root) are installed — all the export build +# needs. Before every `pnpm exec` / `pnpm run`, pnpm 11 checks that the WHOLE +# workspace is installed and runs `pnpm install` when it is not; after `COPY . .` +# below it never is, and that install fails as the non-root runtime uid +# (EACCES on /repo). The deps are frozen here, so the check is off. So is the +# update notice, which every site's log would otherwise print. +ENV pnpm_config_verify_deps_before_run=false \ + pnpm_config_update_notifier=false + # Bake source last so a code change only re-runs from here. COPY . . # Containers run with `-u <host-uid>` (so /site outputs are host-owned, not root). # Next writes a couple of fixed-location files into the export package dir # (next-env.d.ts, tsconfig.tsbuildinfo) and the entrypoint symlinks .next/out from -# there — so that one dir must be writable by an arbitrary runtime uid. The image -# is ephemeral and isolated (--network=none), so widening it here is harmless. +# there — so that one dir must be writable by an arbitrary runtime uid. Every +# container is ephemeral (`docker run --rm`) and writes nothing back but its /site +# mount, so widening it here is harmless. RUN chmod -R a+rwX /repo/export ENTRYPOINT ["bash", "docker/build-site.sh"]