Cloud Run のための実践 Cloud Deploy
はじめに
本記事では実践的な Cloud Run のデプロイパイプライン実装を通して Cloud Deploy の理解を試みます。Cloud Deploy は元々 Kubernetes 用のプロダクトとしてリリースされたこともあり、Cloud Run に限って利用するには学習コストが高すぎるところもあります。本記事では Cloud Run のデプロイの本番環境構築・運用に必要な部分のみをピックアップして次のようなことを説明します。
- Cloud Deploy の仕組み
- Cloud Deploy を使ったデプロイパイプラインの設計・実装方法
- Service Account、IAM 設計
- おすすめの Infra as Code の方法
- おすすめの skaffold.yaml の書き方
Automation、デプロイフック、カナリアデプロイなどの高度なパイプライン、監視などは上記のような基本をおさえれば応用が効くので本記事では説明しません。
本記事の想定読者は Cloud Run を使っているが Cloud Deploy は使っていないという人です。Kubernetes の知識がなくても理解できるようにしていますが、次のような知識を前提としています。
- Google Cloud (gcloud CLI、プロジェクト、IAM、Service Account、Cloud Run、Cloud Build、Cloud Storage、Artifact Registry)
- Docker、コンテナ
- Terraform
Disclaimer
本記事ではおすすめの方法などを紹介していますが、筆者が実際に構築・運用をする中で考えたおすすめやベストプラクティスであって、Google Cloud 公式のものではありません。また、わかりやすさのため説明が厳密ではない部分があります。
Cloud Deploy とは
Cloud Deploy 概要
「開発環境 → ステージング環境 → 本番環境」のような、異なる環境に対する一連のデプロイパイプラインを管理・自動化するためのフルマネージドサービスです。Cloud Deploy ではそのようなパイプラインを Delivery Pipeline と呼びます。
本記事ではこれ以上の概要は割愛しますが、 Cloud Deploy で何ができるのか、何が嬉しいのかを把握するには以下の記事がおすすめです。
Delivery Pipeline の例
Cloud Deploy では例えば以下のような Delivery Pipeline を実現できます。各 Delivery Pipeline に対してサンプル実装を用意しているので参考にしてください。
シリアル デプロイ
1 つの Cloud Run service アプリを dev → stg → prd と順にデプロイするシンプルなパイプラインです。
並行デプロイ
複数の Cloud Run service アプリを各環境に順にデプロイするパイプラインです。ひとつの環境に対しては複数の Cloud Run service を同時にデプロイします。例えば、1 つの Delivery Pipeline で同じアプリをマルチリージョンに同時にデプロイできます。
カナリア デプロイ
カナリアデプロイもできます。
Cloud Deploy のアーキテクチャとデプロイの流れ
Delivery Pipeline を正しく構築するためには Cloud Deploy がどのようなアーキテクチャでどうやってデプロイするかを理解しておく必要があるためそれを説明します。
Skaffold
まずはじめに、Cloud Deploy を使い始めた人が戸惑うであろう Skaffold について説明します。
Cloud Deploy は Skaffold という OSS を利用してデプロイを実現します。Skaffold は Kubernetes 用の開発ツールで機能が多く学習コストも高いのですが、Cloud Run のデプロイをする場合は一旦次のような理解を持っておけば大丈夫です。
Skaffold は skaffold.yaml
という YAML ファイルの設定に従い以下を行う。
- コンテナイメージをビルドして Artifact Registry にプッシュする
- ビルドしたイメージに基づいて Cloud Run service YAML をレンダリングする (以下、
manifest.yaml
とします) - レンダリングした
manifest.yaml
を Cloud Run service にデプロイする
Cloud Deploy のアーキテクチャ
Cloud Deploy の Delivery Pipeline は Delivery Pipeline とそれに紐づく複数の Target で構成されます。
Delivery Pipeline は Cloud Deploy のメインとなるリソースで、何をどういう順番でデプロイするかを定義します。順番の定義には Stage という概念が使われます。例えば dev、stg、prd 環境があるとき、それぞれ dev の stage、stg の stage、prd の stage を定義します。そして各 Stage には 1 つ以上の Target が紐付きます。
Target はデプロイ先を表現するリソースで、Cloud Run の場合はデプロイ先のプロジェクトとロケーションを定義します。
Delivery Pipeline と Target を Terraform で表現すると次のようになります。
resource "google_clouddeploy_target" "hello-app-dev" {
name = "hello-app-dev"
run {
location = "projects/hello-app-dev/locations/us-west1"
}
}
resource "google_clouddeploy_target" "hello-app-stg" {
name = "hello-app-stg"
run {
location = "projects/hello-app-stg/locations/us-west1"
}
}
resource "google_clouddeploy_target" "hello-app-prd" {
name = "hello-app-prd"
run {
location = "projects/hello-app-prd/locations/us-west1"
}
}
resource "google_clouddeploy_delivery_pipeline" "delivery-pipeline" {
name = "hello-app-pipeline"
serial_pipeline {
stages { target_id = google_clouddeploy_target.hello-app-dev.id }
stages { target_id = google_clouddeploy_target.hello-app-stg.id }
stages { target_id = google_clouddeploy_target.hello-app-prd.id }
}
}
デプロイの流れ
デプロイの全体像
Cloud Deploy での一連のデプロイは大きく次のような流れになります。
- 事前準備: コンテナイメージをビルドする
- Release 作成: ビルドしたイメージを Cloud Deploy の Release というリソースに紐付ける
- 各 Stage に対して以下をそれぞれ行う
- Promote: 次の Stage にイメージをデプロイする
事前準備
Cloud Deploy はあくまでもデプロイに特化したサービスなので、コンテナイメージのビルド等を事前にやっておく必要があります。具体的には skaffold build
コマンドの実行が事前に必要です。
次のようなコマンドを実行すると、Skaffold が skaffold.yaml
の設定に従いコンテナイメージをビルド・プッシュして結果を artifacts.json
として出力します。
skaffold build \
--filename skaffold.yaml \
--default-repo us-west1-docker.pkg.dev/hello-app-pipeline/my-app \
--file-output artifacts.json
artifacts.json
にはビルドしたイメージの情報が格納されています。Cloud Deploy ではこの情報をデプロイ単位として扱うことで、各環境に同じ成果物をデプロイすることを保証します。
{
"builds": [
{
"imageName": "hello-app",
"tag": "us-west1-docker.pkg.dev/hello-app-pipeline/hello-app/hello-app:v1.0.0@sha256:6e0fea340f0db7af620de12a2e121231ed497adc4903cf2a920fed497fc06e5b"
}
]
}
Release 作成
Cloud Deploy でのデプロイはまず Release というリソースを作ります。Release は事前準備でビルドしたコンテナイメージを Delivery Pipeline に紐付けるリソースです。Release を作ることで紐づけたコンテナイメージを Cloud Run service へデプロイできるようになります。Release はコンテナイメージの情報以外にも manifest.yaml
をレンダリングするためのソース (skaffold.yaml
と manifest.yaml
のテンプレート) が保存された Cloud Storage の URI を持ちます。
gcloud を使って Release を作成するには次のようにします。
gcloud deploy releases create v-1-0-0 \
--region us-west1 \
--delivery-pipeline hello-app \
--gcs-source-staging-dir gs://hello-app-pipeline/hello-app/source \
--build-artifacts artifacts.json \
--skaffold-file skaffold.yaml \
--source .
また、Release は作成されると同時に全 Target に対する manifest.yaml
をレンダリングして Cloud Storage に保存します。具体的には各 Target ごとに Cloud Build を起動して skaffold render
コマンドを実行します。
Promote
Release を作成したあと、その Release を Promote して次の Stage へ実際にデプロイします。
実は、Cloud Deploy でよく目にする「Promote」ですが、API 的に「Promote」という処理は存在しません。Promote といわれたとき、具体的な処理としては Rollout というリソースの作成をしています。
Rollout は Release と Target を紐付けるリソースです。Cloud Deploy は Rollout が作成されると Cloud Build を起動して skaffold apply
コマンドによりレンダリング済みの manifest.yaml
を Target にデプロイします。
以上をおさえた上で「Promote する」とは、一般的には「対象とする Release について、次の Stage が指す Target に紐づく Rollout を作成する」ことです。 gcloud を使って Promote するには次のようにします。
gcloud deploy releases promote \
--release v-1-0-0 \
--delivery-pipeline hello-app \
--region us-west11
最初の Stage に対する Rollout 作成は Release 作成と同時に実行することが多く、コンソールや gcloud deploy releases create
もそうなっています。つまり、dev → stg → prd のような Delivery Pipeline の場合、Release を作成すると同時に dev 環境へのデプロイが実施されます。
Rollout についての補足
Promote についての補足
Promote は実態としては特定の Target に対する Rollout の作成です。このことを理解しておけば、必ずしも dev → stg → prd という順番を守ってデプロイする必要はないことがわかります。例えば、--disable-initial-rollout
オプションを使って gcloud deploy releases create
を実行すると、dev への Rollout を作成せずに Release を作成できます。その状態で、--to-target
オプションを使って gcloud deploy releases promote
を実行するといきなり prd 環境へデプロイすることも可能です。prd 環境へ hotfix する場合などに活用できます。
まとめ
Cloud Deploy を使った dev → stg → prd というデプロイパイプラインにおけるデプロイの流れをまとめると次のようになります。
-
事前準備
-
skaffold build
でコンテナイメージをビルドして Artifact Registry へプッシュする - ビルド結果として
artifacts.json
を手に入れる
-
-
Release 作成
-
gcloud deploy releases create
コマンド等で Release を作成する - Release は各 Target にデプロイするための
manifest.yaml
をskaffold render
でレンダリングして Cloud Storage へ格納する - 自動的に dev 環境への Rollout が作成される
- Rollout は
skaffold apply
で dev 用のmanifest.yaml
を dev 環境へデプロイする
-
-
stg 環境への Promote
-
gcloud deploy releases promote
コマンド等で Promote する - stg 環境への Rollout が作成される
- Rollout は
skaffold apply
で stg 用のmanifest.yaml
を stg 環境へデプロイする
-
-
prd 環境への Promote
-
gcloud deploy releases promote
コマンド等で Promote する - prd 環境への Rollout が作成される
- Rollout は
skaffold apply
で prd 用のmanifest.yaml
を prd 環境へデプロイする
-
デプロイの流れ全体像
Delivery Pipeline を構築する
ここからは hello-app
という Cloud Run service アプリの dev → stg → prd というデプロイパイプライン構築を通して Cloud Deploy の仕組み、おすすめの構築方法、おすすめの設計を説明していきます。
記事上の Terraform コードは省略して書いてあるためそのままコピペしても動きません。サンプルコードを参照してください。
プロジェクト構成
Google Cloud では環境ごとにプロジェクトを分けることがベストプラクティスです。では Delivery Pipeline などデプロイ用のリソースをどこに置けばいいかというと、サービス用のプロジェクトとは別にパイプライン用のプロジェクトを作成するのがおすすめです。
権限設計
Delivery Pipeline 周辺にどのような登場人物 (Google Cloud 用語で Principal) がいて、それぞれ何ができればよいかを考えます。
Principals
まずはどのような Principal がいるのかを見ていきます。下図は登場する Principal をまとめたものです。
それぞれ役割とやることを簡単に説明します。
-
releaser: 事前準備と Release 作成をする人
-
skaffold build
の実行 (コンテナイメージのビルド・プッシュ) -
gcloud deploy releases create
の実行 (Release の作成) - 結果として dev への Rollout 作成
-
-
stg promoter: stg への Rollout を作成する人
-
gcloud deploy releases promote
の実行 (stg への Rollout 作成)
-
-
prd promoter: prd への Rollout を作成する人
-
gcloud deploy releases promote
の実行 (prd への Rollout 作成)
-
-
Cloud Build の Service Account: 各 Target に関する Cloud Build の Service Account。
skaffold render
やskaffold apply
を実行する
releaser の権限
releaser は次の処理を行います。各処理に必要な role または permission を併記します。
-
skaffold build
- コンテナイメージをビルド
- コンテナイメージをプッシュ (Artifact Registry repository に対する
roles/artifactregistry.writer
)
-
gcloud deploy releases create
- Release の作成 (Delivery Pipeline に対する
clouddeploy.releases.create
)-
source.tgz
を Cloud Storage へアップロード (Cloud Storage bucket に対するroles/storage.objectCreator
、roles/storage.legacyBucketReader
) - 各 Target に対して
skaffold render
を実行するための Cloud Build の起動 (各 Target に設定された Service Account に対するroles/iam.serviceAccountUser
)
-
- dev に対する Rollout の作成 (Delivery Pipeline に対する条件付き
roles/clouddeploy.releaser
)- dev Target に対して
skaffold apply
を実行するための Cloud Build の起動 (dev Target に設定された Service Account に対するroles/iam.serviceAccountUser
)
- dev Target に対して
- 非同期処理 (Operations) の取得 (pipeline プロジェクトへの
roles/clouddeploy.viewer
)
- Release の作成 (Delivery Pipeline に対する
releaser に必要な権限の補足
Rollout を作成するとき各 Target に対する読み取り権限も必要になります。今回は Operation を取得するためにプロジェクトへ roles/clouddeploy.viewer
をつける必要があり、それで全 Target を読み取りできるようになるので省略しています。
releaser の処理はソースコードの変更をトリガーに起動する GitHub Workflow や Cloud Build で自動化されるケースが多いので、それに対応する Service Account へこれらの権限を付与することになるでしょう。
ある Service Account を releaser としたときに Terraform で権限を設定すると次のようになります。
resource "google_service_account" "hello-app-releaser" {
project = google_project.pipeline.project_id
account_id = "hello-app-releaser"
}
resource "google_artifact_registry_repository_iam_member" "hello-app-deployer" {
project = google_artifact_registry_repository.hello-app.project
location = google_artifact_registry_repository.hello-app.location
repository = google_artifact_registry_repository.hello-app.name
role = "roles/artifactregistry.writer"
member = "serviceAccount:${google_service_account.hello-app-releaser.email}"
}
resource "google_storage_bucket_iam_member" "objectCreator" {
bucket = google_storage_bucket.storage.name
role = "roles/storage.objectCreator"
member = "serviceAccount:${google_service_account.hello-app-releaser.email}"
}
resource "google_storage_bucket_iam_member" "legacyBucketReader" {
bucket = google_storage_bucket.storage.name
role = "roles/storage.legacyBucketReader"
member = "serviceAccount:${google_service_account.hello-app-releaser.email}"
}
resource "google_service_account_iam_member" "serviceAccountUser" {
for_each = ["dev", "stg", "prd"]
service_account_id = google_service_account.hello-app-target[each.key].name
role = "roles/iam.serviceAccountUser"
member = "serviceAccount:${google_service_account.hello-app-releaser.email}"
}
resource "google_project_iam_custom_role" "clouddeployReleaseCreator" {
project = google_project.pipeline.project_id
role_id = "clouddeployReleaseCreator"
title = "Cloud Deploy Release Creator"
permissions = ["clouddeploy.releases.create"]
}
data "google_iam_policy" "hello-app-pipeline-policy" {
binding {
role = google_project_iam_custom_role.clouddeployReleaseCreator.id
members = ["serviceAccount:${google_service_account.hello-app-releaser.email}"]
}
binding {
role = "roles/clouddeploy.releaser"
members = ["serviceAccount:${google_service_account.hello-app-releaser.email}"]
condition {
title = "Rollout to hello-app-dev"
expression = "api.getAttribute(\"clouddeploy.googleapis.com/rolloutTarget\", \"\") == \"${google_clouddeploy_target.hello-app-target["dev"].name}\""
}
}
// ...
}
resource "google_clouddeploy_delivery_pipeline_iam_policy" "policy" {
project = google_clouddeploy_delivery_pipeline.hello-app-pipeline.project
location = google_clouddeploy_delivery_pipeline.hello-app-pipeline.location
name = google_clouddeploy_delivery_pipeline.hello-app-pipeline.name
policy_data = data.google_iam_policy.hello-app-pipeline-policy.policy_data
}
resource "google_project_iam_member" "hello-app-deployer_clouddeploy_viewer" {
project = google_project.pipeline.project_id
role = "roles/clouddeploy.viewer"
member = "serviceAccount:${google_service_account.hello-app-releaser.email}"
}
releaser の権限設定の補足
Terraform では releaser に対する権限設定が複雑になっていますが、releaser が stg や prd へデプロイできなくするために必要な設定です。Delivery Pipeline に Release を作成するための role として roles/clouddeploy.releaser
がありますが、これには Rollout を作成する permission も含まれているため、Delivery Pipeline に対して条件なしで付与するとすべての Target へのデプロイができるようになってしまいます。そのため、Release を作成するためだけの custom role を作成しています。また、roles/clouddeploy.releaser
は dev 環境に対してのみ有効化されるような条件を設定しています。
Cloud Build の Service Account
Delivery Pipeline から起動される Cloud Build にアタッチされる Service Account は、その Cloud Build がどの Target に関するものかで決まります。例えば dev Target に関する Cloud Build にアタッチする Service Account を設定する Terraform は次のようになります。
resource "google_service_account" "hello-app-target-dev" {
project = google_project.pipeline.project_id
account_id = "hello-app-target-dev"
}
resource "google_clouddeploy_target" "hello-app-target-dev" {
project = google_project.pipeline.project_id
location = "us-west1"
name = "hello-app-dev"
execution_configs {
service_account = google_service_account.hello-app-target-dev.email
}
run {
location = "projects/hello-app-dev/locations/us-west1"
}
}
1 つの Target に対して Cloud Build は 2 回、Release 作成時と Rollout 作成時にそれぞれ起動されます。それぞれで実行する処理と必要な権限は次のようになります。
-
skaffold render
(Release 作成時に起動される)-
source.tgz
を Cloud Storage からダウンロード (Cloud Storage bucket へのroles/storage.objectViewer
) -
manifest.json
を Cloud Storage へアップロード (Cloud Storage bucket へのroles/storage.objectCreator
)
-
-
skaffold apply
(Rollout 作成時に起動される)-
manifest.json
を Cloud Storage からダウンロード (Cloud Storage bucket へのroles/storage.objectViewer
) - Cloud Run service をデプロイ (Cloud Run service への
roles/run.developer
、Cloud Run service の Service Account へのroles/iam.serviceAccountUser
)
-
また、Cloud Build を実行する基本的な role として roles/logging.logWriter
が必要です。
Terraform で dev Target に関する Cloud Build の Service Account に必要な権限を設定すると次のようになります。(stg, prd も同様)
resource "google_service_account" "hello-app-target-dev" {
project = google_project.pipeline.project_id
account_id = "hello-app-target-dev"
}
resource "google_project_iam_member" "logWriter" {
project = google_project.pipeline.project_id
role = "roles/logging.logWriter"
member = "serviceAccount:${google_service_account.hello-app-target-dev.email}"
}
resource "google_storage_bucket_iam_member" "objectViewer" {
bucket = google_storage_bucket.storage.name
role = "roles/storage.objectViewer"
member = "serviceAccount:${google_service_account.hello-app-target-dev.email}"
}
resource "google_storage_bucket_iam_member" "objectCreator" {
bucket = google_storage_bucket.storage.name
role = "roles/storage.objectCreator"
member = "serviceAccount:${google_service_account.hello-app-target-dev.email}"
}
resource "google_service_account_iam_member" "serviceAccountUser" {
service_account_id = google_service_account.hello-app-dev.name
role = "roles/iam.serviceAccountUser"
member = "serviceAccount:${google_service_account.hello-app-target-dev.email}"
}
resource "google_cloud_run_v2_service_iam_member" "hello-app-target_run_developer" {
project = google_cloud_run_v2_service.hello-app-dev.project
location = google_cloud_run_v2_service.hello-app-dev.location
name = google_cloud_run_v2_service.hello-app-dev.name
role = "roles/run.developer"
member = "serviceAccount:${google_service_account.hello-app-target-dev.email}"
}
Cloud Build の Service Account の権限についての補足
Cloud Deploy のデフォルトの設定では source.tgz
を格納する Cloud Storage bucket と manifest.json
を格納する Cloud Storage bucket は別の bucket を使うようになっています。そのため、権限設定も 2 つのバケットに対して必要になります。実用上同じ bucket で問題ない場合は同じにしておくのがおすすめです。
stg promoter と prd promoter
stg promoter は次の処理を行います (prd promoter も同様)。
-
gcloud deploy releases promote
- stg に対する Rollout の作成 (Delivery Pipeline への条件付き
roles/clouddeploy.releaser
)- stg Target に対して
skaffold apply
を実行するための Cloud Build の起動 (stg Target に設定された Service Account へのroles/iam.serviceAccountUser
)
- stg Target に対して
- 非同期処理 (Operations) の取得 (pipeline プロジェクトへの
roles/clouddeploy.viewer
)
- stg に対する Rollout の作成 (Delivery Pipeline への条件付き
promoter は SRE などの人、もしくは人やなんらかのイベントがトリガーする自動化システムになるでしょう。
stg promoter を Service Account として実装する場合の権限設定 Terraform は次のようになります (prd promoter も同様)。
resource "google_service_account" "hello-app-stg-promoter" {
project = google_project.pipeline.project_id
account_id = "hello-app-stg-promoter"
}
resource "google_service_account_iam_member" "serviceAccountUser" {
service_account_id = google_service_account.hello-app-target["stg"].name
role = "roles/iam.serviceAccountUser"
member = "serviceAccount:${google_service_account.hello-app-stg-promoter.email}"
}
data "google_iam_policy" "hello-app-policy" {
// ...
binding {
role = "roles/clouddeploy.releaser"
members = ["serviceAccount:${google_service_account.hello-app-stg-promoter.email}"]
condition {
title = "Rollout to hello-app-stg"
expression = "api.getAttribute(\"clouddeploy.googleapis.com/rolloutTarget\", \"\") == \"${google_clouddeploy_target.hello-app-stg.name}\""
}
}
// ...
}
resource "google_clouddeploy_delivery_pipeline_iam_policy" "policy" {
project = google_clouddeploy_delivery_pipeline.hello-app.project
location = google_clouddeploy_delivery_pipeline.hello-app.location
name = google_clouddeploy_delivery_pipeline.hello-app.name
policy_data = data.google_iam_policy.hello-app-policy.policy_data
}
resource "google_project_iam_member" "clouddeploy_viewer" {
project = google_project.pipeline.project_id
role = "roles/clouddeploy.viewer"
member = "serviceAccount:${google_service_account.hello-app-stg-promoter.email}",
}
Delivery Pipeline 構築
Cloud Deploy に関する公式ドキュメントや記事には Delivery Pipeline を YAML で定義するように書かれているものが多いですが、まったくその必要はありません。いつも通りの方法、例えば Terraform で管理しましょう。
Terraform の場合 google_clouddeploy_delivery_pipeline リソースを使って以下のように定義します。
resource "google_clouddeploy_delivery_pipeline" "hello-app-pipeline" {
location = "us-west1"
name = "hello-app-pipeline"
serial_pipeline {
stages { target_id = google_clouddeploy_target.hello-app-dev.name }
stages { target_id = google_clouddeploy_target.hello-app-stg.name }
stages { target_id = google_clouddeploy_target.hello-app-prd.name }
}
}
location
は、デプロイ先の location とは無関係です。
多くのドキュメントやサンプルで、各ステージに profiles
というものを設定していますが不要です。特に Cloud Run の場合は使わないようにしたほうがシンプルでわかりやすく構成できます。
manifest.yaml
manifest.yaml
は Cloud Run service YAML のことです。普段 Cloud Run を使うだけであればこの YAML は必要ないのですが、Cloud Deploy を使う場合は必要になります。
現在 Cloud Run を使っているのであれば、この YAML はコンソールからも確認できますし、次のコマンドでも確認できます。コピペしてリファレンスと見比べながら不必要なものを削除していくのがいいでしょう。
gcloud run services describe hello-app \
--region us-central1 \
--format yaml
manifest.yaml
は Cloud Run service アプリに対して 1 つあればよく (dev、stg、prd それぞれ別に作る必要はない)、簡単な manifest.yaml
は次のようになります。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: hello-app
annotations:
run.googleapis.com/ingress: all
spec:
template:
spec:
serviceAccountName: dummy # from-param: ${service_account_name}
containers:
- name: hello-app
image: hello-app
env:
- name: MESSAGE
value: dummy # from-param: ${message}
ここで、# from-param: ${service_account_name}
のようなコメントがついているフィールドがありますが、このコメントには意味があります。# from-param:
によって設定されるパラメータは deploy parameters と呼ばれます。deploy parameters は Target ごとに設定できるため、環境ごとに変化する値を使いたい場合は deploy parameters を利用します。
例えば上の YAML の場合、Cloud Deploy で各環境に対して次のような値に書き換えられてから Cloud Run にデプロイされます。
- dev 環境
-
serviceAccountName
:dummy
→hello-app@hello-app-dev.iam.gserviceaccount.com
-
env[0].value
:dummy
→Hello, dev!
-
- stg 環境
-
serviceAccountName
:dummy
→hello-app@hello-app-stg.iam.gserviceaccount.com
-
env[0].value
:dummy
→Hello, stg!
-
- prd 環境
-
serviceAccountName
:dummy
→hello-app@hello-app-prd.iam.gserviceaccount.com
-
env[0].value
:dummy
→Hello, prd!
-
manifest.yaml のレンダリングについての補足
本記事ではシンプルで学習コストが低く Terraform で管理しやすい deploy parameters を推していますが、manifest.yaml
が複雑になってくると 1 つの manifest.yaml
と deploy parameters だけではレンダリングが難しくなってくる場合があるかもしれません。その場合、Cloud Deploy では Helm、Kustomize、kpt が使えるのでそれらレンダリングツールの利用を検討してください。
Target
Cloud Deploy の Target も Delivery Pipeline と同じく Terraform 等で構築しましょう。Terraform の場合は google_clouddeploy_target リソースを使います。
resource "google_clouddeploy_target" "hello-app-dev" {
location = "us-west1"
name = "hello-app-dev"
execution_configs {
usages = ["RENDER", "DEPLOY"]
service_account = google_service_account.hello-app-target-dev.email
artifact_storage = "gs://${google_storage_bucket.storage.name}/artifacts"
}
run {
location = "projects/hello-app-dev/locations/us-west1"
}
deploy_parameters = {
message = "Hello, dev!"
service_account_name = google_service_account.hello-app-dev.email
}
}
location
はデプロイ先の Cloud Run ではなく、Delivery Pipeline と同じ location にしておく必要があります。
manifest.yaml
で説明した deploy parameters はここで設定します。
skaffold.yaml
これまでコンテナイメージのビルド・プッシュを skaffold build
、manifest.yaml
のレンダリングを skaffold render
で行っていると説明しましたが、それらのコマンドの設定を skaffold.yaml
に記述します。
-
skaffold build
- コンテナイメージタグの命名方法
- コンテナイメージ名
- コンテナイメージのビルド設定
-
skaffold render
-
manifest.yaml
のパス
-
-
skaffold apply
- 特になし (おまじないのみ)
これらを設定した skaffold.yaml
は次のようになります。
apiVersion: skaffold/v3
kind: Config
metadata:
name: hello-app
build:
tagPolicy:
envTemplate:
template: "{{ .APP_VERSION }}"
artifacts:
- image: hello-app
context: ../../app
docker:
buildArgs:
app_version: "{{ .APP_VERSION }}"
dockerfile: ../../app/Dockerfile
local:
useBuildkit: true
push: true
deploy:
cloudrun: {}
manifests:
rawYaml:
- manifest.yaml
それぞれの詳しい説明は skaffold.yaml のリファレンスを参照してください。最低限必要なものは以下で簡単に説明します。
-
build.tagPolicy
: コンテナイメージのタグ命名方法を設定します。上のサンプルは環境変数で設定するenvTemplate
を利用していてskaffold build
時にAPP_VERSION
環境変数に設定した値がタグになります。他には Git から自動でタグを設定するgitCommit
などが存在します。詳しくはドキュメントを参照してください。 -
build.artifacts[].image
: コンテナイメージの名前です。manifest.yaml
の中でこの名前に一致するイメージが実際にビルドしたコンテナイメージに置換されます。 -
build.artifacts[].context
:docker build
を実行するときの context です。 -
build.artifacts[].docker
:docker build
の設定です。 -
manifests.rawYaml
:manifest.yaml
のパスを指定します。
ディレクトリ構成
skaffold.yaml
と manifest.yaml
はそれらだけで同じディレクトリに置いておくと便利です。そうすると、そのディレクトリに入って skaffold build
や gcloud deploy releases create
を実行すればいろいろ上手く動きます。
.
├── README.md
├── app
│ ├── Dockerfile
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── deploy
│ ├── manifest.yaml
│ └── skaffold.yaml
└── terraform
├── pipeline.tf
├── service.tf
├── variables.tf
└── versions.tf
おわりに
概要を調べても何なのかよく分からず、中身もなかなか複雑な Cloud Deploy ですが、本記事の内容を理解すれば問題なく構築・運用できます。理解して使えばとても便利なサービスなのでガンガン使っていきましょう 🚀✨
Discussion