概要 #
Cloud Runへ自分のコンテナをデプロイするには、先にArtifact Registryが要ります。Runtime Service Accountへの読み取り権限も必要です。手順が複数のサービスにまたがるため、どこまでTerraformで書けるのかが分かりにくいところです。
そこで、まず公開Hello ImageでCloud Run Serviceを作ります。次にそのImageを自分のRepositoryへPushし、参照先を切り替えました。動く状態を保ったまま入れ替えるので、失敗した箇所を切り分けやすくなります。
Terraformの基本操作とDockerコマンドは前提としています。Cloud RunとArtifact Registryの組み合わせが初めての方向けです。
CI/CDパイプラインからの自動デプロイ、カスタムドメインの割り当て、複数リビジョンへのトラフィック分割は扱いません。
検証すること #
- Artifact RegistryとCloud Run v2 Serviceを作成できること
- Runtime Service AccountへRepository読取権限を付与できること
- 自前RepositoryへImageをPushしてCloud Runの参照先を変更できること
- 認証付きRequestでServiceを呼び出せること
前提環境 #
- Google Cloud CLI、Terraform、Docker
- Billingが有効な検証用Google Cloud Project
- Artifact Registry、Cloud Run、IAMを操作できるGoogleアカウント
- 検証時のバージョン:Terraform 1.14.3、google 7.43.0
今回の構成 #
Artifact RegistryとCloud Runはどちらもリージョナルなサービスですが、VPCの中には置きません。
flowchart TB
Dev["開発者の端末"]
Inv["Invoker"]
subgraph GCP["Google Cloud"]
subgraph Project["Project"]
SA["Runtime Service Account"]
subgraph Region["asia-northeast1"]
AR["Artifact Registry
Docker Repository"]
Run["Cloud Run v2 Service"]
end
end
end
Dev -->|"docker push"| AR
Run -->|"起動時に pull"| AR
Inv -->|"HTTPS + ID Token"| Run
SA -.->|"Serviceの実行ID"| Run
SA -.->|"artifactregistry.reader"| AR
点線が権限の関係です。Runtime Service AccountにRepositoryの読み取り権限がないと、Imageを取得できません。その場合Serviceは起動しません。
Imageを差し替えるまでの流れは次のとおりです。
sequenceDiagram
actor Dev as 開発者
participant AR as Artifact Registry
participant TF as Terraform
participant Run as Cloud Run
TF->>Run: 公開Hello Imageで Service を作成
Note over Run: まず動く状態を作る
Dev->>AR: docker push(自分のImage)
Dev->>TF: container_image を書き換え
TF->>Run: apply(参照先を切り替え)
Run->>AR: 新しいImageを pull
Run-->>Dev: 新しいリビジョンで起動
動く状態を保ったまま入れ替えるので、失敗した箇所を切り分けやすくなります。
使用するTerraformコード #
RepositoryとCloud Run #
resource "google_artifact_registry_repository" "app" {
location = var.region
repository_id = var.repository_id
format = "DOCKER"
}
resource "google_cloud_run_v2_service" "hello" {
name = var.service_name
location = var.region
template {
service_account = google_service_account.run.email
containers { image = var.container_image }
}
}
Cloud Run専用Service AccountにはRepositoryのroles/artifactregistry.readerを付与します。ImageをPushする開発者側にはWriter権限とDocker認証が別途必要です。
呼び出し権限 #
resource "google_cloud_run_v2_service_iam_member" "invoker" {
location = google_cloud_run_v2_service.hello.location
name = google_cloud_run_v2_service.hello.name
role = "roles/run.invoker"
member = var.invoker_member
}
標準は認証必須です。公開Serviceにする場合だけallUsersへInvokerを付与しますが、意図しない公開を避けるため変数で明示的に選択します。
実行とImageの切り替え #
cd Advanced-Examples/02-cloudrun-artifact-registry
cp terraform.tfvars.example terraform.tfvars
terraform init
terraform fmt -check
terraform validate
terraform apply
Artifact Registry、Runtime Service Account、Cloud Runが作成されます。合わせて8リソースです。
Apply complete! Resources: 8 added, 0 changed, 0 destroyed.
Outputs:
curl_authenticated_example = "curl -sS -H \"Authorization: Bearer $(gcloud auth print-identity-token)\" \"https://tf-adv-hello-ldzccxoqeq-an.a.run.app\""
example_ar_image = "asia-northeast1-docker.pkg.dev/YOUR_PROJECT_ID/tf-adv-run/hello:latest"
repository_url = "asia-northeast1-docker.pkg.dev/YOUR_PROJECT_ID/tf-adv-run"
service_name = "tf-adv-hello"
uri = "https://tf-adv-hello-ldzccxoqeq-an.a.run.app"
RepositoryへDocker認証し、Hello ImageをCopyします。
gcloud auth configure-docker REGION-docker.pkg.dev
docker pull us-docker.pkg.dev/cloudrun/container/hello
docker tag us-docker.pkg.dev/cloudrun/container/hello \
REGION-docker.pkg.dev/PROJECT/REPOSITORY/hello:latest
docker push REGION-docker.pkg.dev/PROJECT/REPOSITORY/hello:latest
container_imageをPush先へ変更して再度terraform applyします。
GCP側で確認する #
Serviceが実際に自前Repositoryのイメージを参照しているか確認します。
gcloud run services describe "$(terraform output -raw service_name)" \
--region="$(terraform output -raw location)" \
--format='value(spec.template.spec.containers[0].image)'
asia-northeast1-docker.pkg.dev/YOUR_PROJECT_ID/tf-adv-run/hello:latest
認証必須ServiceなのでID Tokenを付けて呼び出します。
curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" \
"$(terraform output -raw uri)"
HTTP 200
後片付けと注意点 #
terraform destroy
Destroy complete! Resources: 8 destroyed.
Repository内にImageが残ると削除できない設定があります。検証では削除Policyやcleanup_policyも検討してください。ProductionではImage TagよりDigest固定を使うと安全です。同じTerraform設定から異なるImageが配信される問題を避けられます。
まとめ #
- Docker RepositoryとCloud RunをTerraformで一体管理できる
- Runtime Service AccountにはImage読取だけを付与できる
- Invoker IAMで認証必須と公開を選択できる
- Image Push後にCloud Runの参照先を自前Repositoryへ切り替えられる
参考資料 #
次回 #
次回はGKE Workload Identity Federationを使います。Podから鍵なしでCloud Storageへアクセスします。