はじめに
DX開発事業部の北村です。
GitHub上のMonorepo構成Next.jsアプリをCloud Build(第2世代)でCloud Runに自動デプロイする手順と、Monorepo構成やCloud Build第2世代を利用する際のポイントを解説します。
今回解説する手順は、以下の通りです。
- Docker環境構築
- Cloud Build構成ファイル作成
- ソースリポジトリ(GitHub)とCloud Buildリポジトリの接続
- Artifact Registry構築
- サービスアカウント設定
- Cloud Buildトリガー構築
Docker環境構築
今回デプロイ対象のプロジェクトは、以下のMonorepo構成となっています。
app(プロジェクトルート)/ ├── frontend/ ├── backend/ ├── mobile/ └── infra/
このうち、フロントエンド部分であるfrontend
ディレクトリのコンテナイメージをビルドするDockerファイルを作成します。
app(プロジェクトルート)/ ├── .devcontainer/ │ ├── frontend/ │ │ └── Dockerfile │ └── backend/ ├── frontend/ ├── backend/ ├── mobile/ └── infra/
Dockerfile
# ビルドステージ FROM node:22-slim AS builder WORKDIR /app COPY frontend/package*.json ./ RUN npm ci COPY frontend . RUN npm run build # 実行ステージ FROM node:22-slim WORKDIR /app COPY --from=builder /app/public ./public COPY --from=builder /app/.next ./.next COPY --from=builder /app/package*.json ./ # devdependenciesを排除 RUN npm ci --omit=dev EXPOSE 3000 CMD ["npm", "start"]
ℹ️ 解説
上記のようにビルドプロセスの段階を分けるマルチステージビルドを活用することで、最終的な実行イメージに必要な最小限のファイル(ビルド成果物、依存関係など)だけが含まれ、コンテナイメージのサイズを削減することができます。
Cloud Build構成ファイル作成
Cloud Buildのワークフローを定義する構成ファイルを作成します。
_AR_HOSTNAME,PROJECT_ID,_REPO_NAME,_SERVICE_NAME,_DEPLOY_REGIONは、Cloud Buildトリガーを作成時に定義する変数です。変数の内容はこちらを参照。
app(プロジェクトルート)/ ├── .cloudbuild/ │ ├── frontend/ │ │ └── cloudbuild.yml │ └── backend/ ├── frontend/ ├── backend/ ├── mobile/ └── infra/
steps: # docker build - name: 'gcr.io/cloud-builders/docker' args: [ 'build', '--no-cache', '-t', '${_AR_HOSTNAME}/${PROJECT_ID}/${_REPO_NAME}/${_SERVICE_NAME}:latest', '-f', '.devcontainer/frontend/Dockerfile', '.' ] # DockerイメージをArtifact Registryへプッシュする - name: 'gcr.io/cloud-builders/docker' args: [ 'push', '${_AR_HOSTNAME}/${PROJECT_ID}/${_REPO_NAME}/${_SERVICE_NAME}:latest' ] # Cloud Runへデプロイ - name: 'google/cloud-sdk' args: [ 'gcloud', 'run', 'deploy', '${_SERVICE_NAME}', '--image=${_AR_HOSTNAME}/${PROJECT_ID}/${_REPO_NAME}/${_SERVICE_NAME}:latest', '--region', '${_DEPLOY_REGION}', '--platform', 'managed', # 本番環境で公開Webサイトではない場合、このオプションは使用せず、IAMロールなどでアクセス制御を行うことを推奨します '--allow-unauthenticated', '--port=3000' ] # イメージをArtifact Registryへ保存する images: - '${_AR_HOSTNAME}/${PROJECT_ID}/${_REPO_NAME}/${_SERVICE_NAME}:latest' # ログをCloud Loggingにのみ送信する options: logging: CLOUD_LOGGING_ONLY
ソースリポジトリ(GitHub)とCloud Buildリポジトリの接続
デプロイ対象のソースコードを管理しているGitHubとCloud Buildリポジトリを接続し、ソースコードへのアクション(PushやPull Request作成など)を検知できるようにします。
Google Cloudコンソールから「Cloud Build/リポジトリ/第2世代」へ移動し、「ホスト接続を作成」を押下します。
⚠️注意
今回は、第2世代を使用します。第2世代は、Terraformでの管理が可能となりました。IaCを考えている方は、第2世代を使用すると良いでしょう。第1世代と第2世代では、GitHubとの連携手順などが一部異なります。
接続の構成を入力し、「接続」を押下します。
GitHubとCloud Buildを接続するためには、GitHubでCloud Buildアプリが必要です。インストールしていない場合は、GitHub側でインストールし、既存のアプリがある場合は、既存のアプリを選択して接続を行います。(GitHubのCloud Buildアプリを通して認証を行います)
GitHubとCloud Buildの接続を許可します。
接続したGitHubのホストが表示されていることを確認します。
ℹ️ 解説
GitHubの認証情報は、Secret Managerに保存されます。
次に、作成したホストにGitHubのリポジトリをリンクさせます。「リポジトリをリンク」を押下します。
接続するリポジトリ情報を入力し、「リンク」を押下します。
対象のリポジトリがホストにリンクされていることを確認します。
以上で、GitHubとCloud Buildリポジトリの接続が完了しました。
Artifact Registry構築
次に、Artifact Regitryを構築し、コンテナイメージを保存できるようにします。
Google Cloudコンソールから「Artifact Registry」に移動し、「リポジトリの作成」を押下します。
リポジトリの構成を入力し、「作成」を押下します。
⚠️ 注意
Artifact Registryにコンテナイメージを保存する際に、脆弱性をチェックしセキュリティを高めたい場合、「脆弱性スキャン」を「有効」にしてください。今回は、「無効」を選択します。
リポジトリが作成されていることを確認します。
以上で、Artifact Registryの構築は完了です。
サービスアカウント設定
次に、サービスアカウントを設定し、Cloud Buildトリガーに付与する権限を設定します。
Google Cloudコンソールから「IAMと管理/サービスアカウント」に移動し、「サービスアカウントを作成」を押下します。
サービスアカウントの詳細を入力し、「完了」を押下します。
サービスアカウントが作成されていることを確認します。
次に、サービスアカウントにIAMロールの紐付けを行います。
「IAMと管理/IAM」に移動し、「アクセスを許可」を押下します。
前のステップで作成したサービスアカウントを選択後、Cloud Buildトリガーで必要な権限を付与し(最小権限の原則で付与)、「保存」を押下します。
ℹ️ 解説
ロール「Secret Managerのシークレット アクセサー」は、Secret Managerに保存されたGitHub認証情報を参照するために必要となります。
⚠️ 注意
権限エラーが出る場合は、特にCloud Run側でカスタムサービスアカウントを指定している場合は、Cloud Runのサービスアカウントにロール「サービスアカウントユーザー」を付与してください。
以上で、サービスアカウントの設定は完了し、Cloud Buildトリガーを構築する準備が整いました。
Cloud Buildトリガー構築
最後に、Cloud Buildのトリガーを構築し、GitHubの任意のブランチ(今回はmain)にPushされた時に自動デプロイが実行(実行されるワークフローは、cloudbuild.ymlで定義)されるようにします。
Google Cloudコンソールから「Cloud Build/トリガー」に移動し、「トリガーを作成」を押下します。
Cloud Buildトリガーの設定を入力し、「作成」を押下します。
⚠️ 注意
Monorepo構成の場合、「ソース」で変更を検知するディレクトリを指定する必要があります。今回は、フロントエンド部分をデプロイするので、frontend/**
をフィルタとして指定します。フィルタを指定しない場合、backendやinfraなど対象外のディレクトリが変更された場合でもCloud Buildトリガーが発火してしまうので、注意しましょう。
「詳細」で定義する変数の値は、cloudbuild.ymlで記載した変数に代入されます。
- _AR_HOSTNAME:Artifact Registryのホスト名(基本的にasia-northeast1-docker.pkg.dev)
- _DEPLOY_REGION:デプロイするリージョン(基本的にasia-northeast1)
- _PROJECT_ID:Google CloudプロジェクトのID
- _REPO_NAME:Artifact Registryの名前
- _SERVICE_NAME:Cloud Runのサービス名、コンテナイメージ名(任意の名前を入力)
⚠️ 注意
「サービスアカウント設定」で作成したサービスアカウントを選択する。
Cloud Buildトリガーが作成されていることを確認します。
Cloud Runが作成され、デプロイされていることを確認します。
お疲れ様でした!以上で、Next.jsアプリをCloud BuildでCloud Runに自動デプロイする手順は完了となります!
最後に
Monorepo構成で対象のディレクトリだけをデプロイする方法やCloud Buildリポジトリ第2世代での設定方法、サービスアカウントの設定方法が特にポイントかと思います。
Next.jsアプリをCloud Runにデプロイする際は、今回の方法で自動デプロイを試していただければと思います!