💨

Cloud Build + Cloud Runでお手軽デリバリーを構築する

2025/01/22に公開

はじめに

WED株式会社でバックエンドエンジニアをしているkimurayです。

最近シンプルなWebアプリを複数構築してリリースするというケースが複数件ありました。
Webアプリのデプロイ先としてCloud Runを活用し、CI/CDとしてCloud Buildを用いることで簡単にデリバリーを実現することができたので記事としてまとめます。(内容的には手垢がいっぱいついていますが備忘録的な形として...笑)

前提

  • ソースコードはGitHubで管理
  • WebアプリはCloud Runで稼働
  • リソースはTerraformで管理
  • DockerイメージはArtifact Registryで管理
  • アプリはAPI参照がメインでDBと直接疎通していない

Webフロントのようなアプリのイメージです。

構成イメージ

最終的なデリバリーの形は

  • mainブランチにPRがマージされたらステージング環境にデプロイ
  • リリースタグが切られたらステージングと本番環境にデプロイ

となります。

イメージとしては以下のような形になります。

Cloud Build用のTerraformリソースを定義

Service Account

Cloud Buildを実行するためのSAを定義しておきます。

resource "google_service_account" "cloudbuild" {
  project      = "project_id"
  account_id   = "cloudbuild"
  display_name = "cloudbuild"
  description  = var.description
}

resource "google_project_iam_member" "cloudbuild" {
  for_each = toset([
    "roles/iam.serviceAccountUser",
    "roles/secretmanager.secretAccessor",
    "roles/cloudbuild.builds.builder",
  ])
  role    = each.key
  member  = "serviceAccount:${google_service_account.cloudbuild.email}"
  project = "project_id"
}

Cloud BuildのSAからCloud Runを扱えるようにするため以下のロールもSAに付与しておきます。
Cloud Runのデプロイのためにロールとしてはroles/run.developerを付与し、Cloud Run起動ユーザーの権限が必要になるのでroles/iam.serviceAccountUserを付与します。

resource "google_service_account_iam_member" "cloudrun_build" {
  service_account_id = "projects/${project_id}/serviceAccounts/${CloudRun起動のSAのemail}"
  role               = "roles/iam.serviceAccountUser"
  member             = "serviceAccount:${google_service_account.cloudbuild.email}"
}

resource "google_project_iam_member" "cloudrun_build" {
  project = "project_id"
  role    = "roles/run.developer"
  member  = "serviceAccount:${google_service_account.cloudbuild.email}"
}

Cloud Buildトリガー

まずはGitHubでPRマージやタグ作成があった時にCloud Buildが検知できるようにGitHubとCloud Buildを連携します。

resource "google_cloudbuildv2_connection" "github" {
  project  = "project_id"
  location = "region"
  name     = "github-connection"

  github_config {
    app_installation_id = xxxxxxx
    # https://github.com/organizations/xxxxxxx/settings/installations/xxxxxxx
    authorizer_credential {`
      oauth_token_secret_version = google_secret_manager_secret_version.github-token-secret-version.id
    }
  }
}

resource "google_cloudbuildv2_repository" "sample" {
  project           = "project_id"
  location          = "region"
  name              = "sample"
  parent_connection = google_cloudbuildv2_connection.github.name
  remote_uri        = "https://github.com/リポジトリ名.git"
}

次にCloud Buildのトリガーを定義します。

resource "google_cloudbuild_trigger" "sample_production" {
  name     = "sample-production"
  project  = "project_id"
  location = "region"

  repository_event_config {
    repository = google_cloudbuildv2_repository.sample.id
    push {
      tag = "^v.*$"
    }
  }

  filename        = "cloudbuild/production.yaml"
  service_account = google_service_account.cloudbuild.id
}

resource "google_cloudbuild_trigger" "sample_staging" {
  name     = "sample-staging"
  project  = "project_id"
  location = "region"

  repository_event_config {
    repository = google_cloudbuildv2_repository.sample.id
    push {
      branch = "^main$"
    }
  }

  filename        = "cloudbuild/staging.yaml"
  service_account = google_service_account.cloudbuild.id
}

このトリガーの定義によってsampleリポジトリでmainブランチに変更があった際にcloudbuild/staging.yamlの設定に応じてデプロイ、v*の形式でリリースタグが切られた際にcloudbuild/production.yamlの設定応じてデプロイが実行されるようになります。

Cloud Buildの設定ファイルを作成

Cloud Buildのトリガー時に読み込む設定ファイルをデプロイ対象のリポジトリに配置します。
今回の設定ではcloudbuildディレクトリをリポジトリのルートに配置し、その中にstaging.yaml, production.yamlを作成します。

設定内容としては以下を記載します。
まずはステージングの設定です。

cloudbuild/staging.yaml
steps:
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'region-docker.pkg.dev/$PROJECT_ID/sample/sample:$COMMIT_SHA', '.']
    env:
      - 'BUILD=$BUILD_ID'

  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'region-docker.pkg.dev/$PROJECT_ID/sample/sample:$COMMIT_SHA']
    env:
      - 'BUILD=$BUILD_ID'

  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: 'gcloud'
    args:
      [
        'run',
        'deploy',
        'sample-staging',
        '--image',
        'region-docker.pkg.dev/$PROJECT_ID/sample/sample:$COMMIT_SHA',
        '--platform',
        'managed',
        '--region',
        'region',
        '--project',
        'project_id',
      ]

options:
  logging: CLOUD_LOGGING_ONLY

images:
  - 'region-docker.pkg.dev/$PROJECT_ID/sample/sample:$COMMIT_SHA'

流れとしては

  1. Dockerイメージをbuild
  2. Artifact RegistryにbuildしたイメージをPUSH
  3. PUSHしたイメージを使ってCloud Runにデプロイ

の順で実行しています。まだステージングへのリリースという段階なのでCOMMIT_SHAでタグ付けするようにしています。

本番環境の設定は以下になります。

cloudbuild/production.yaml
steps:
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'region-docker.pkg.dev/$PROJECT_ID/sample/sample:$TAG_NAME', '.']
    env:
      - 'BUILD=$BUILD_ID'

  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'region-docker.pkg.dev/$PROJECT_ID/sample/sample:$TAG_NAME']
    env:
      - 'BUILD=$BUILD_ID'

  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: 'gcloud'
    args:
      [
        'run',
        'deploy',
        'sample-staging',
        '--image',
        'region-docker.pkg.dev/$PROJECT_ID/sample/sample:$TAG_NAME',
        '--platform',
        'managed',
        '--region',
        'region',
        '--project',
        'project_id',
      ]

  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: 'gcloud'
    args:
      [
        'run',
        'deploy',
        'sample-production',
        '--image',
        'region-docker.pkg.dev/$PROJECT_ID/sample/sample:$TAG_NAME',
        '--platform',
        'managed',
        '--region',
        'region',
        '--project',
        'project_id',
      ]

options:
  logging: CLOUD_LOGGING_ONLY

images:
  - 'region-docker.pkg.dev/$PROJECT_ID/sample/sample:$TAG_NAME'

流れとしてはstagingへのデプロイとほぼ同一ですが

  1. Dockerイメージをbuild
  2. Artifact RegistryにbuildしたイメージをPUSH
  3. PUSHしたイメージを使ってステージングのCloud Runにデプロイ
  4. PUSHしたイメージを使って本番のCloud Runにデプロイ

本番のCloud Runへのデプロイも行うようにしています。
本番用のデプロイはリリースタグでDockerイメージのタグを設定するようにしています。

さいごに

Cloud RunでのWebアプリ立ち上げもDockerイメージをbuildさえできれば簡単に行えますが、Cloud Buildを活用することでCI/CDもかなり手軽に設定することができました。

サクッとWebアプリを立ち上げたいであったり、個人でサービスを立ち上げたいという時はかなり有用なので手軽に試してみてください。

WED Engineering Blog

Discussion