Skip to content

chore(docker): pin Node and prep images for a read-only root filesystem - #9387

Merged
waleedlatif1 merged 1 commit into
stagingfrom
chore/ro-root-prep
Oct 27, 2026
Merged

waleedlatif1 merged 1 commit into
stagingfrom
chore/ro-root-prep

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Node pin (app image base): ARG NODE_VERSION=24.22.1, install nodejs=${NODE_VERSION}-1nodesource1, then assert node --version = v${NODE_VERSION}. Before this, apt-get install nodejs took whatever NodeSource had published when the layer last rebuilt. The layer is cached, so Node only changed when an unrelated edit forced a rebuild. The version string comes from the NodeSource node_24.x Packages index for both amd64 and arm64. The -1nodesource1 suffix selects nodejs itself rather than nsolid, which Provides nodejs at the same version numbers (24.22.1-ns…). build-base/deps inherit base, so isolated-vm's node-gyp build compiles against the same Node (ABI 137) that runs it. 24.22.1 is the Node already running, so the next image build ships the same Node.
  • Read-only root prep: no change on today's writable filesystem. This adds writable paths and VOLUME declarations, following the egress gateway's precedent (mkdir + chown, then VOLUME). ECS copies the image's contents and ownership into a bind volume mounted at a VOLUME path.
    • app: /tmp (1777) is os.tmpdir() scratch for ffmpeg/audio processing, KB imports, the Pi agent, and libvips (sharp) spill files. /app/apps/sim/.next/cache (nextjs:nodejs) holds the image optimizer's disk cache (.next/cache/images) and the fetch data cache (next: { revalidate }).
    • realtime: /tmp (1777) + VOLUME.
    • pii: PYTHONDONTWRITEBYTECODE=1, so no __pycache__ is written next to server.py; pip already byte-compiles site-packages. Also /tmp (1777) + VOLUME, declared below the model download that stages wheels in /tmp.
  • experimental.isrFlushToDisk deliberately not changed. In the pinned Next 16.4.1, isrFlushToDisk: false does more than stop ISR write-back to .next/server/app. It also turns off the image optimizer's disk cache (image-optimizer.js: the disk LRU is only built when isrFlushToDisk is true, and there is no in-memory fallback), so every /_next/image miss would re-encode. That would change behavior today, so it waits for the read-only flip. Build-time prerender reads don't depend on it: the export worker hard-codes flushToDisk: !hasNextSupport, and seed/APP_PAGE reads aren't gated on it. Only FETCH reads and all writes are.

Self-hosting impact

  • Docker Compose: VOLUME creates anonymous volumes for /tmp and .next/cache (and /tmp in realtime). Compose reuses them when it recreates a container, so the image/fetch cache and /tmp now survive docker compose up upgrades instead of resetting. Fetch entries still honor their revalidate windows (60s–1h). docker compose up -V renews them, and docker compose down -v removes them. Nothing in the compose files mounts these paths, so nothing conflicts.
  • Helm/Kubernetes ignores VOLUME. No change.

Type of Change

  • Chore / infrastructure

Testing

  • Checked the NodeSource node_24.x Packages index (amd64 + arm64) for nodejs 24.22.1-1nodesource1. The package has no Recommends, so --no-install-recommends installs the same files.
  • Traced isrFlushToDisk through the published next@16.4.1 tarball (image-optimizer.js, next-server.js, file-system-cache.js, export/worker.js, build/index.js).
  • CI image builds cover the Dockerfiles. The new node --version assertion fails the build if the pin drifts.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing (new tests pass the test-audit authoring gate)
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docs Ready Ready Preview Oct 27, 2026 12:00am UTC

Request Review

@greptile-apps

greptile-apps Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable issues were found.

Summary

Pins the app image’s Node version and prepares writable scratch and cache paths for a read-only root filesystem.

  • The app image installs the same pinned Node version for builds and runtime.
  • The app keeps scratch files and Next.js caches on writable Docker volumes.
  • The realtime and PII services keep temporary files on writable volumes.

Acknowledged choices from waleedlatif1:

  • Compose now preserves scratch files and cache across container recreation.
  • Kubernetes ignores VOLUME; this PR does not change that behavior.
  • Changing isrFlushToDisk is deferred because it would also disable the image optimizer’s disk cache.

Reviews (1) · Last reviewed commit: "chore(docker): pin Node and prep images ..." · Reviewed by Greptile

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 3 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Turn on auto-fix | Re-trigger cubic

@waleedlatif1
waleedlatif1 merged commit 90c0da6 into staging Oct 27, 2026
68 checks passed
@waleedlatif1
waleedlatif1 deleted the chore/ro-root-prep branch October 27, 2026 00:03

This branch was successfully deployed

1 active deployment
Preview — d344dc45 Deployed Oct 27, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant