bon now

ありのままの現実を書き殴る吐き溜め。底辺ITエンジニアの備忘録。
Written by bon who just a foolish IT Engineer.

Next.jsのNEXT_PUBLIC環境変数をCloud Build + Cloud Run + Terraformで管理する方法

Created Date: 2022/08/03 02:47
Updated Date: 2026/03/04 23:14

GCPでNext.jsをCloud Runにデプロイする際、NEXT_PUBLIC_ から始まる環境変数の扱いでハマったので、解決策と設定全体像をまとめておく。

NEXT_PUBLIC変数が特殊な理由

Next.jsにはサーバー専用の環境変数と、クライアントにも公開される環境変数の2種類がある。

種類 埋め込みタイミング
サーバー専用 API_SECRET_KEY ランタイム(コンテナ起動時)
クライアント公開 NEXT_PUBLIC_API_URL ビルド時にソースへ静的埋め込み

問題はここ。 バックエンドAPIなら docker run -e API_KEY=xxx のように起動時に環境変数を渡せばよいが、NEXT_PUBLIC_ 変数は next build 実行時にバンドルに書き込まれる ため、ビルド前に値が確定していなければならない。

つまり、Cloud RunのコンソールやTerraformで「実行時環境変数」として設定しても NEXT_PUBLIC_ には反映されない。

最初のアプローチとその問題点

最初に試みた構成:

ステップ 担当 内容
1 Terraform 環境変数を定義
2 Cloud Build (cloudbuild.yaml) docker build時に --build-arg でDockerfileに渡す
3 Dockerfile ARG で受け取り ENV に設定
4 Cloud Run 設定なし

この方法の問題は、環境変数を追加・変更するたびに Terraform・cloudbuild.yaml・Dockerfile の3箇所を修正しなければならない 点。変更漏れによるバグが起きやすい。

改善後の構成

yarn build(つまり next build)を Dockerビルドの前 にCloud Build上で実行することで、Dockerfileを環境変数の設定から切り離した。

ステップ 担当 内容
1 Terraform 環境変数を定義
2 Cloud Build yarn build に環境変数を渡してビルド → そのままDockerイメージ化
3 Dockerfile 設定不要
4 Cloud Run 設定不要

修正が必要な箇所が 2箇所(TerraformとCloud Build) だけになった。

実装詳細

cloudbuild.yaml の設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
steps:
  # Step 1: yarn buildしてNEXT_PUBLICをビルド時に埋め込む
  - id: 'yarn build'
    name: node
    entrypoint: yarn
    args: ['run', 'build']
    env:
      - 'NEXT_PUBLIC_FIREBASE_API_KEY=$$FIREBASE_API_KEY'
      - 'NEXT_PUBLIC_FIREBASE_APP_ID=$$FIREBASE_APP_ID'
      - 'NEXT_PUBLIC_API_URL=$$API_URL'
    secretEnv:
      - 'FIREBASE_API_KEY'
      - 'FIREBASE_APP_ID'

  # Step 2: ビルド済みの成果物をそのままDockerイメージにまとめる
  - id: 'build'
    name: 'gcr.io/cloud-builders/docker'
    entrypoint: 'sh'
    args:
      - '-c'
      - |
        docker build \
          --cache-from gcr.io/$PROJECT_ID/my-app:latest \
          -f ./docker/Dockerfile \
          -t gcr.io/$PROJECT_ID/my-app:latest \
          .
    waitFor:
      - 'yarn build'

availableSecrets:
  secretManager:
    - versionName: projects/$PROJECT_ID/secrets/FIREBASE_API_KEY/versions/latest
      env: 'FIREBASE_API_KEY'
    - versionName: projects/$PROJECT_ID/secrets/FIREBASE_APP_ID/versions/latest
      env: 'FIREBASE_APP_ID'

ポイントは $$VARIABLE_NAME という二重ドルの記法。Cloud Buildでは $VAR はCloud Build組み込み変数、$$VAR はSecret Managerや置換変数を参照するための記法。

Terraform での Secret Manager 設定例

1
2
3
4
5
6
7
8
9
10
11
resource "google_secret_manager_secret" "firebase_api_key" {
  secret_id = "FIREBASE_API_KEY"
  replication {
    auto {}
  }
}

resource "google_secret_manager_secret_version" "firebase_api_key" {
  secret      = google_secret_manager_secret.firebase_api_key.id
  secret_data = var.firebase_api_key
}

.gitignore の注意点

next build の成果物(.next/ ディレクトリ)をCloud Build上で生成してDockerイメージに含めるため、.gitignore から除外されていても問題ない(Cloud Build上でのみ生成・使用)。ただし、ローカルで誤ってコミットしないよう .gitignore には引き続き記載しておくこと

1
2
.next/
out/

セキュリティ上の注意

NEXT_PUBLIC_ 変数はブラウザのJavaScriptバンドルに平文で埋め込まれるため、公開しても問題のない値のみを設定すること。APIシークレットキーや認証情報を誤って NEXT_PUBLIC_ で定義しないよう注意。

まとめ

Next.jsの NEXT_PUBLIC_ 環境変数はビルド時埋め込みのため、Cloud Runの実行時環境変数では反映されない。Cloud Build上で next build を先に実行してからDockerイメージを作ることで、環境変数管理をシンプルにできる。

ビルドサービス(Cloud Build)のリソースを活用してビルドを行うことで、Dockerfileをシンプルに保つのがポイント。

local_offer
gcp
folder work

chat_bubble_outline コメントを残す