👍

Cloud Build + Cloud DeployでNext.jsをデプロイする

2024/12/02に公開

この記事はコミューンプロダクト開発アドベントカレンダー2024のシリーズ1の2日目の記事です。

はじめに

Next.js アプリケーションを Cloud Run にデプロイしてみます。
デプロイには Cloud Build と Cloud Deploy を、データベースには Cloud SQL を使用します。
※本記事では、必要な API の有効化については省略しています。適宜設定してください。

構成図

以下の構成で、main ブランチへのプッシュをトリガーに Cloud Run へデプロイします。

サンプルアプリケーション

使用するアプリケーションはこちら: https://github.com/uyori/next-prisma-sample

  • Next.js: v15.3
  • Prisma: v6.0
  • MySQL: v8.0.36

Cloud SQLの設定

1.インスタンスの作成

以下記事を参考に作成します。データベースエンジンは、MySQL 8.0を選択し、インスタンス名は next-prisma-instance で作成します。
https://zenn.dev/google_cloud_jp/articles/cloudrun-cloudsql#cloud-sql-インスタンスを作成する

2.データベースとユーザーの作成

作成したインスタンスにデータベースとユーザーを追加します。

  • データベース: next-prisma-db
  • ユーザー
    • ユーザー名: app
    • パスワード: password

3.テーブルの作成とサンプルデータの登録

Cloud SQL Studioにログインし、以下のSQLクエリを実行します。

-- Todos テーブルの作成
CREATE TABLE `Todos` (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `completed` tinyint(1) NOT NULL DEFAULT '0',
  `createdAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  `updatedAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  PRIMARY KEY (`id`)
);

-- サンプルデータの登録
INSERT INTO `Todos` (`id`, `title`, `completed`) VALUES
    (1, 'Buy milk', 0),
    (2, 'Buy bread', 0),
    (3, 'Buy eggs', 1);

4.Secret Managerに保存

データベースの接続情報を Secret Manager に保存します。

echo 'mysql://app:password@<プライベートIPアドレス>:3306/next-prisma-db' | \
gcloud secrets create db \
    --data-file=-

※ <プライベートIPアドレス> は Cloud SQL インスタンスのプライベートIPアドレスに置き換えてください。

Cloud Buildの設定

1.Artifact Registoryの作成

デプロイする Docker イメージを保存するリポジトリを作成します。

$ gcloud artifacts repositories create next-prisma-repository \
    --location=asia-northeast1 \
    --repository-format=docker

2.Cloud Build Triggerの作成

まず、Cloud Build用のサービスアカウントを作成します。

gcloud iam service-accounts create next-prisma-cloud-build

gcloud projects add-iam-policy-binding <プロジェクトID> \
  --member=serviceAccount:next-prisma-cloud-build@<プロジェクトID>.iam.gserviceaccount.com \
  --condition=None \
  --role=roles/logging.logWriter
gcloud projects add-iam-policy-binding <プロジェクトID> \
  --member=serviceAccount:next-prisma-cloud-build@<プロジェクトID>.iam.gserviceaccount.com \
  --condition=None \
  --role=roles/cloudbuild.builds.builder
  gcloud projects add-iam-policy-binding <プロジェクトID> \
  --member=serviceAccount:next-prisma-cloud-build@<プロジェクトID>.iam.gserviceaccount.com \
  --condition=None \
  --role=roles/clouddeploy.releaser
gcloud projects add-iam-policy-binding <プロジェクトID> \
  --member=serviceAccount:next-prisma-cloud-build@<プロジェクトID>.iam.gserviceaccount.com \
  --condition=None \
  --role=roles/iam.serviceAccountUser

*<プロジェクトID>は、自身のプロジェクトIDに置き換えてください。

コンソールからCloud Build Triggerを作成していきます。名前は next-prisma-trigger で、リージョンは global を選択します。

trigger対象となるリポジトリ(next-prisma-sample)を選択し、構成からCloud Build 構成ファイルを選択します。

先ほど作成したサービスアカウントを設定し、保存します。

3.cloudbuild.yaml の作成

以下の cloudbuild.yaml をプロジェクトルートに作成します。

cloudbuild.yaml
steps:
  - id: build
    name: 'gcr.io/cloud-builders/docker'
    args: 
      - build
      - '-t'
      - 'asia-northeast1-docker.pkg.dev/${PROJECT_ID}/next-prisma-repository/app:${SHORT_SHA}'
      - '.'
  - id: push
    name: 'gcr.io/cloud-builders/docker'
    args: 
      - push
      - 'asia-northeast1-docker.pkg.dev/${PROJECT_ID}/next-prisma-repository/app:${SHORT_SHA}'
  - id: deploy
    name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: 'gcloud'
    args:
      - deploy
      - releases
      - create
      - 'release-${SHORT_SHA}'
      - '--delivery-pipeline'
      - 'next-prisma-pipeline'
      - '--region'
      - 'asia-northeast1'
      - '--images'
      - 'app=asia-northeast1-docker.pkg.dev/${PROJECT_ID}/next-prisma-repository/app:${SHORT_SHA}'
options:
  logging: 'CLOUD_LOGGING_ONLY'
  • build ステップ:
  • push ステップ:
    • ビルドしたイメージを Artifact Registry にプッシュします。
  • deploy ステップ:
    • Cloud Deploy を使用してリリースを作成します

Cloud Deployの設定

1.デリバリーパイプラインの作成

まず、Cloud Build用のサービスアカウントを作成し、権限を付与します。

gcloud iam service-accounts create next-prisma-cloud-deploy

gcloud projects add-iam-policy-binding <プロジェクトID> \
  --member=serviceAccount:next-prisma-cloud-deploy@<プロジェクトID>.iam.gserviceaccount.com \
  --condition=None \
  --role=roles/logging.logWriter
gcloud projects add-iam-policy-binding <プロジェクトID> \
  --member=serviceAccount:next-prisma-cloud-deploy@<プロジェクトID>.iam.gserviceaccount.com \
  --condition=None \
  --role=roles/storage.objectUser
gcloud projects add-iam-policy-binding <プロジェクトID> \
  --member=serviceAccount:next-prisma-cloud-deploy@<プロジェクトID>.iam.gserviceaccount.com \
  --condition=None \
  --role=roles/run.developer
gcloud projects add-iam-policy-binding <プロジェクトID> \
  --member=serviceAccount:next-prisma-cloud-deploy@<プロジェクトID>.iam.gserviceaccount.com \
  --condition=None \
  --role=roles/iam.serviceAccountUser

次に、Cloud Runをデプロイ先ターゲットとするデリバリーパイプラインを作成します。
以下の clouddeploy.yaml をプロジェクトルートに作成します。

clouddeploy.yaml
apiVersion: deploy.cloud.google.com/v1
kind: DeliveryPipeline
metadata:
  name: next-prisma-pipeline
serialPipeline:
  stages:
    - targetId: next-prisma-target
---
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
  name: next-prisma-target
run:
  location: projects/<プロジェクトID>/locations/asia-northeast1
- usages:
  - RENDER
  - DEPLOY
  serviceAccount: next-prisma-cloud-deploy@<プロジェクトID>.iam.gserviceaccount.com

以下のコマンドを実行し、実際にデリバリーパイプライン及びターゲットを作成します。

gcloud deploy apply \
    --file=clouddeploy.yaml \
    --region asia-northeast1

2.skaffold.yamlの作成

Cloud Deployに必要なskaffold.yamlを、プロジェクトのルートディレクトリに作成します。

skaffold.yaml
apiVersion: skaffold/v4beta5
kind: Config
metadata:
  name: next-prisma
manifests:
  rawYaml:
    - ./cloudrun.yaml
deploy:
  cloudrun: {}

3.service.yamlの作成

Cloud Run用のサービスアカウントを作成し、Secret Managerにアクセスするための権限を付与します。

gcloud iam service-accounts create next-prisma-app

gcloud secrets add-iam-policy-binding db \
  --member=serviceAccount:next-prisma-app@<プロジェクトID>.iam.gserviceaccount.com \
	--role=roles/secretmanager.secretAccessor

Skaffold がデプロイする Cloud Run サービスを定義したservice.yamlを作成します。

service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: next-prisma-app
spec:
  template:
    metadata:
      annotations:
        # Cloud SQL の VPC、サブネットを設定
        run.googleapis.com/network-interfaces: '[{"network":"default","subnetwork":"default"}]'
    spec:
      containers:
      - image: app
        ports:
        - name: http1
          containerPort: 3000
        # 環境変数DATABASE_URLに、secretManagerに登録したdbの接続情報を設定
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              key: 1
              name: db
        startupProbe:
          tcpSocket:
            port: 3000

さいごに

Cloud Build と Cloud Deploy を使用して Next.js アプリケーションを Cloud Run にデプロイすることができました。今後は GoogleCloud のリソースを Terraform で構築していきたいです💪

参考

https://techbookfest.org/product/jQP5REJPx6pwMFEyx8QHPN?productVariantID=qGHnmQt1X84CDs89pCeuJ
https://zenn.dev/google_cloud_jp/articles/cloudrun-cloudsql
https://zenn.dev/google_cloud_jp/articles/cloudrun-vpc
https://cloud.google.com/deploy/docs/integrating-ci?hl=ja#examples_passing_a_build_artifacts_file

Discussion