Communitygithub.com

Nuvraxis/nuvraxis-plugins

pnpm + Turborepo モノレポ内の Next.js スタンドアロンアプリ向け Dockerfile ルール集。マルチステージビルド、ダイジェスト指定の Node Alpine、チェックサム検証済み pnpm、非 root 実行、読み取り専用ルートファイルシステム、HEALTHCHECK などを定義します。

nuvraxis-plugins とは?

このスキルは、pnpm + Turborepo 構成のモノレポで動作する Next.js アプリケーションの Docker イメージを構築するためのベストプラクティスを提供します。`base`、`pruner`、`deps`、`builder`、`runner` の 5 ステージ構成により、ソースコードの変更時には影響を受けるステージのみを再ビルドし、ビルド時間を最適化します。Node イメージは特定のバージョンとダイジェストで固定し、pnpm は GitHub リリースから SHA-256 チェックサム検証付きでインストールします。`runner` ステージでは、スタンドアロン出力のみをコピーし、非 root ユーザー (uid 1001) で実行、読み取り専用ルートファイルシステムに対応します。また、HEALTHCHECK によるヘルスチェック、`.dockerignore` によるコンテキストの最小化、BuildKit のシークレットマウントとキャッシュマウント、マルチアーキテクチャビルド、OCI ラベルなどをサポートします。このスキールは、Claude Code、Cursor、Codex などの AI エージェントが、モノレポ内の Next.js アプリケーションの Dockerfile を作成・修正・デバッグする際に使用します。

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

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Docker for Next.js

アプリイメージに使用します。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. 5 ステージ構成: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 イメージ。 理由:ソースコードの変更は最後の 2 ステージのみを再ビルドし、ランナーには pnpm、ソース、開発依存関係が含まれません。
  2. Node イメージを正確なバージョンとダイジェストで固定し、.node-version に一致させる。 node:26.12.0-alpine3.24@sha256:6f08… を 1 つの ARG NODE_IMAGE で指定し、base と runner の両方で使用します。ダイジェストはマルチアーキテクチャインデックスであるため、amd64 と arm64 の両方で解決されます。 理由:Alpine を distroless よりも優先する理由:distroless Node はフローティングタグ(latest、nonroot)のみを公開するため、正確な Node バージョンを .node-version に一致させることができず、HEALTHCHECK 用の wget もありません。Alpine は小型で、正確に固定でき、sharp はプリビルドされた musl バイナリを提供するため、追加パッケージなしで画像最適化が機能します。

  3. pnpm を GitHub リリースのバイナリからインストールし、SHA-256 で検証する。npm i -g pnpm、Corepack、未検証の curl | sh は絶対に使用しない。 1 つの ARG PNPM_VERSION を packageManager と等しく設定し、アーキテクチャごとに pnpm-linux-{x64,arm64}-musl.tar.gz のチェックサムを 1 つ用意し、TARGETARCH で選択します。バンプするには:3 つの ARG を変更し、sha256 値をリリースのアセットダイジェスト(gh release view v<version> --repo pnpm/pnpm --json assets)から取得し、同じコミットで packageManager をバンプします。リリース形式が変更された場合のフォールバック:pruner/deps/builder ステージを ghcr.io/pnpm/pnpm:<version> ベースにし(Node なし、追加する)、新しいインストール方法を考案するのではなく、この方法を採用します。

  4. ランナーは正確に 3 つの要素をコピーする。

    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 は行わず(アプリはシェルツールセットを必要としません)、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.

関連スキル