Communitygithub.com

Nuvraxis/nuvraxis-plugins

用於 pnpm + Turborepo 單倉庫中 Next.js 獨立應用程式的 Dockerfile 規則 — 多階段建構(turbo prune → pnpm fetch/offline install → turbo build → 最小執行環境),鎖定 Node 26 Alpine 摘要版本,經校驗和驗證的 pnpm 二進位檔,非 root 使用者 uid 1001,唯讀根檔案系統搭配可寫入的 .next/cache,對 /api/health 進行 HEALTHCHECK,建構參數僅限於 NEXT_PUBLIC_* 值,BuildKit 密鑰與快取掛載,多架構,OCI 標籤與 .dockerignore。適用於儲存庫中包含 Dockerfile、.dockerignore、compose 檔案或 next.config 設定 output 為 "standalone" 時,或當要求容器化、縮小、強化或除錯映像檔時。

nuvraxis-plugins 是什麼?

此技能提供了一組嚴格的 Dockerfile 規則,專為在 pnpm + Turborepo 單倉庫中運行 Next.js 獨立輸出模式而設計。它採用五階段多層次建構流程,從基礎的 Node 與 pnpm 開始,經由 Turbo 進行依賴修剪、離線安裝依賴項、建構應用程式,最終產生一個最小化的執行環境。其核心優勢在於安全性與效率:使用非 root 使用者、唯讀根檔案系統、僅對 .next/cache 目錄授予寫入權限,並透過 SHA-256 校驗和驗證 pnpm 二進位檔。此外,該規則要求精確鎖定 Node 映像檔摘要,使用 BuildKit 密鑰與快取掛載以提升建構速度,並設定 HEALTHCHECK 端點與 OCI 標籤,確保映像檔可在本地與 Kubernetes 環境中可靠運作。此技能主要支援基於 Docker 的建構流程,並與 GitHub Actions 及 Helm 圖表協作,適用於需要標準化、安全且可重現的 Next.js 應用程式容器化場景。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Nuvraxis/nuvraxis-plugins/tree/HEAD/plugins/nuvraxis-frontend/skills/docker-nextjs

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

Next.js 適用的 Docker

用於應用程式映像檔。Next.js 獨立部署的相關資訊位於 nextjs-production(references/self-hosting.md);在 Kubernetes 中執行此映像檔的方式請見 helm-nextjs;CI 如何建構與推送則請見 github-actions。

範本的 apps/<app>/Dockerfile 是唯一真理來源;references/Dockerfile.md 包含完整內容與註解。從儲存庫根目錄建構:docker build -f apps/<app>/Dockerfile -t <app> .

規則

  1. 五個階段:base → pruner → deps → builder → runner。

    • base:僅包含 Node 與 pnpm,無其他內容。
    • pruner:對完整儲存庫執行 turbo prune <app> --docker,僅保留應用程式及其工作區依賴項。
    • deps:僅複製 out/json/(清單檔案)與 out/pnpm-lock.yaml,然後執行 pnpm fetch + pnpm install --frozen-lockfile --offline。此層在清單檔案或鎖定檔變更前會重複使用,因此原始碼編輯不會觸發重新安裝。
    • builder:複製 out/full/(原始碼),執行 pnpm exec turbo run build --filter=<app>。
    • runner:一個全新的 Node 映像檔,僅包含獨立輸出。 原因:原始碼變更只會重建最後兩個階段,且執行環境中沒有 pnpm、原始碼或開發依賴項。
  2. 將 Node 映像檔鎖定到確切版本與摘要,並與 .node-version 保持一致。 在一個 ARG NODE_IMAGE 中使用 node:26.12.0-alpine3.24@sha256:6f08…,同時用於 base 和 runner。此摘要是多架構索引,因此 amd64 和 arm64 皆可解析。 為什麼選擇 Alpine 而非 distroless:distroless Node 僅發布浮動標籤(latest、nonroot),因此無法將確切的 Node 版本與 .node-version 匹配,且它沒有用於 HEALTHCHECK 的 wget。Alpine 體積小,可精確鎖定,且 sharp 提供預建置的 musl 二進位檔,因此映像檔最佳化無需額外套件。

  3. 從 GitHub 發行版二進位檔安裝 pnpm,並經由 SHA-256 驗證。絕不使用 npm i -g pnpm、Corepack 或未經驗證的 curl | sh。 一個 ARG PNPM_VERSION 等於 packageManager,再加上每個架構一個用於 pnpm-linux-{x64,arm64}-musl.tar.gz 的校驗和,透過 TARGETARCH 選擇。更新時:變更三個 ARG,從發行版的資產摘要(gh release view v<version> --repo pnpm/pnpm --json assets)取得 sha256 值,並在同一次提交中更新 packageManager。如果發行版格式變更,備案是將 pruner/deps/builder 階段基於 ghcr.io/pnpm/pnpm:<version>(不含 Node,需自行添加),而不是發明新的安裝方法。

  4. 執行環境僅複製三項內容。

    COPY --from=builder /repo/apps/<app>/.next/standalone ./
    COPY --from=builder /repo/apps/<app>/.next/static ./apps/<app>/.next/static
    COPY --from=builder /repo/apps/<app>/public ./apps/<app>/public
    

    獨立輸出不包含 static 或 public;缺少它們,應用程式將無法提供任何 JS 或 CSS。在單倉庫中,伺服器位於 apps/<app>/server.js。CMD ["node", "apps/<app>/server.js"],使用 exec 格式,以便 Node 直接接收 SIGTERM 訊號。

  5. 以 uid/gid 1001 執行,檔案歸 root 擁有。 建立 nextjs:nodejs(1001:1001),保留複製的檔案為 root 擁有(應用程式可讀取但無法修改自身程式碼),並僅對 apps/<app>/.next/cache 執行 chown。USER 1001:1001,使用數字格式,以便 Kubernetes 無需解析名稱即可驗證 runAsNonRoot。

  6. 映像檔必須能在唯讀根檔案系統上運作。 唯一的執行時期寫入操作發生在 .next/cache(映像檔最佳化、ISR/快取擷取)。Kubernetes 會在該處掛載一個 emptyDir;本地端使用 --tmpfs。測試方式:

    docker run --rm -p 3000:3000 --read-only \
      --tmpfs /app/apps/<app>/.next/cache:uid=1001,gid=1001 \
      --cap-drop ALL --security-opt no-new-privileges <app>
    
  7. 在執行環境中設定 NODE_ENV=production、HOSTNAME=0.0.0.0、PORT=3000、NEXT_TELEMETRY_DISABLED=1。 如果沒有 HOSTNAME=0.0.0.0,獨立伺服器會綁定到容器主機名稱,導致探測失敗。

  8. HEALTHCHECK 使用 busybox 的 wget 存取 /api/health。 此檢查用於 docker run/Compose;Kubernetes 會忽略它,而是使用圖表中相同路徑的探測器。

  9. 建構參數僅限於在建構時內聯的值:NEXT_PUBLIC_* 和 NEXT_DEPLOYMENT_ID。 NEXT_PUBLIC_* 會被編譯進 JS 中,因此它必須是 builder 中的 ARG + ENV,且在映像檔運行的每個環境中都相同。每個環境的特定設定均來自圖表中的執行時期環境變數。若要新增一個:

    ARG NEXT_PUBLIC_APP_NAME
    ENV NEXT_PUBLIC_APP_NAME=${NEXT_PUBLIC_APP_NAME}
    

    …並在兩個工作流程中加上 build-args,且 NEXT_PUBLIC_* 已在 turbo 的 env 中。

  10. 祕密資訊絕不可放入 ARG、ENV 或 COPY 中。 這些會遺留在映像檔歷史中。請使用 BuildKit 密鑰掛載,它僅在該 RUN 期間存在:

    RUN --mount=type=secret,id=npm_token,env=NPM_TOKEN pnpm fetch   # 私有註冊表
    

    範本的建構步驟已透過此方式宣告了可選的 next_server_actions_key 密鑰。

  11. 使用 BuildKit 快取掛載快取 pnpm 儲存庫。 在 fetch/install/dlx 上使用 --mount=type=cache,id=pnpm-store,target=/pnpm/store,搭配 pnpm_config_store_dir=/pnpm/store。儲存庫在同一個建構器上的建構之間持續存在,而不會進入映像檔層。在 CI 中,層級快取為 type=gha(請參閱 github-actions)。

  12. 儲存庫根目錄的 .dockerignore 可保持建構上下文小而安全,並排除祕密資訊。 它排除 node_modules、.next、.turbo、dist、coverage、.env*、.git、.github、charts。包含來自 Windows 或 macOS 的 node_modules 的上下文會破壞 Linux 映像檔中的原生套件。

  13. 多架構為 linux/amd64,linux/arm64,由 CI 建構。 在本地端,請建構您自己的架構。每個階段都與架構無關,除了 pnpm 下載會根據 TARGETARCH 選擇其校驗和。

  14. 標籤: Dockerfile 設定 org.opencontainers.image.title 和 licenses;CI 透過 docker/metadata-action 新增 source、revision、version、created。請勿硬編碼版本標籤。

  15. 保持各階段不含應用程式特定的駭客技巧。 執行環境中不要有 apk add(應用程式不需要 shell 工具集),不要有 npm,不要從主機複製 node_modules。如果應用程式在執行時期需要原生工具,請在註解中說明理由。

偵錯

症狀原因
建構期間 extends: … doesn't resolve應用程式所需的根層級檔案不在修剪後的樹中:將其移入一個工作區套件
deps 階段出現 ERR_PNPM_OUTDATED_LOCKFILE清單檔案變更後未提交鎖定檔
ERR_PNPM_IGNORED_BUILDS新的依賴項需要安裝腳本:在 allowBuilds 中決定
應用程式啟動,但無 CSS/JS.next/static 或 public 未複製到 apps/<app>/
健康檢查失敗,日誌正常HOSTNAME 未設定為 0.0.0.0
執行時期出現 EROFS有內容寫入 .next/cache 之外的位置;請找出它,不要取消 --read-only
NEXT_PUBLIC_X 為空未作為建構參數傳遞(它是在建構時烘焙的)

驗證

docker build -f apps/<app>/Dockerfile -t <app>:local --build-arg NEXT_DEPLOYMENT_ID=local .
docker run -d --name <app> -p 3000:3000 --read-only --tmpfs /app/apps/<app>/.next/cache:uid=1001,gid=1001 --cap-drop ALL <app>:local
curl -fsS localhost:3000/api/health
docker exec <app> id                     # uid=1001(nextjs)
docker inspect --format '{{.State.Health.Status}}' <app>   # 約 30 秒後變為 healthy
docker rm -f <app>

來源

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

Nuvraxis/nuvraxis-plugins

>- Biome 2.5 setup and rules for Nuvraxis monorepos — root biome.json with pinned $schema, VCS ignore, formatter settings, the recommended preset with a11y and the react/next domains, nursery policy, organize imports, overrides, nested per-package configs ("extends": "//"), biome check --write locally, biome ci in CI, VS Code settings, and migrating from ESLint/Prettier. Use when the repo has biome.json or biome.jsonc, @biomejs/biome in package.json, .eslintrc*/eslint.config.*/.prettierrc* to migrate, or when fixing lint and formatting errors.

Nuvraxis/nuvraxis-plugins

>- GitHub Actions conventions for Nuvraxis Next.js apps — exactly three workflows: pr.yaml (every PR to any branch: Biome, stylelint, typecheck/test/build with turbo --affected, Docker build + health check, helm lint + kubeconform; publishes nothing), main.yaml (push to main: one multi-arch image to GHCR tagged sha-SHORTSHA and main, provenance + SBOM, gha cache), release.yaml (tag vX.Y.Z: verify on main, retag the existing image without rebuilding, package and push the Helm chart to OCI, GitHub Release with chart, digest and SBOM). Minimal permissions per job, GITHUB_TOKEN only, pinned action majors. Use when editing .github/workflows/*, adding a CI step, or debugging a failed run or release.

Nuvraxis/nuvraxis-plugins

>- Helm chart rules for Nuvraxis Next.js apps — one chart per app in charts/ (named after the app), published to oci://ghcr.io/nuvraxis/charts and synced by Argo CD; Chart.yaml version/appVersion set only by release.yaml; Deployment with startup/liveness/readiness probes on /api/health, non-root read-only security context, emptyDir for .next/cache, ConfigMap + existing Secret via envFrom, Service, Ingress with cert-manager, HPA, PDB, ServiceAccount, topology spread; no Helm hooks; helm lint --strict + kubeconform. Use when the repo has charts/, Chart.yaml, values*.yaml, templates/*.yaml with Helm syntax, or an Argo CD Application, or when asked to deploy, scale, expose or configure the app on Kubernetes.

Nuvraxis/nuvraxis-plugins

>- Production rules for Next.js 16 App Router apps at Nuvraxis — Server/Client Component boundaries, Cache Components ("use cache", cacheLife, cacheTag, updateTag), Server Actions, route handlers, env handling, instrumentation, output standalone and the /api/health route. Use when the project has "next" in package.json, an app/ or src/app/ directory, next.config.ts, proxy.ts, instrumentation.ts, or files named page.tsx, layout.tsx, route.ts, loading.tsx, error.tsx.

相關技能