Cloud Build + Cloud Runでお手軽デリバリーを構築する
はじめに
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
を作成します。
設定内容としては以下を記載します。
まずはステージングの設定です。
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'
流れとしては
- Dockerイメージをbuild
- Artifact RegistryにbuildしたイメージをPUSH
- PUSHしたイメージを使ってCloud Runにデプロイ
の順で実行しています。まだステージングへのリリースという段階なのでCOMMIT_SHAでタグ付けするようにしています。
本番環境の設定は以下になります。
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へのデプロイとほぼ同一ですが
- Dockerイメージをbuild
- Artifact RegistryにbuildしたイメージをPUSH
- PUSHしたイメージを使ってステージングのCloud Runにデプロイ
- PUSHしたイメージを使って本番のCloud Runにデプロイ
本番のCloud Runへのデプロイも行うようにしています。
本番用のデプロイはリリースタグでDockerイメージのタグを設定するようにしています。
さいごに
Cloud RunでのWebアプリ立ち上げもDockerイメージをbuildさえできれば簡単に行えますが、Cloud Buildを活用することでCI/CDもかなり手軽に設定することができました。
サクッとWebアプリを立ち上げたいであったり、個人でサービスを立ち上げたいという時はかなり有用なので手軽に試してみてください。
Discussion