↓メインコンテンツへスキップ
  1. Blogs/

TerraformでArtifact RegistryのコンテナをCloud Runへデプロイしてみた

2 分
Terraform GoogleCloud CloudRun ArtifactRegistry
0222-nnn
著者
0222-nnn
猫が好き
目次
Terraform-GoogleCloud - この記事は連載の一部です
パート 18: この記事

概要
#

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へアクセスします。

Terraform-GoogleCloud - この記事は連載の一部です
パート 18: この記事

関連記事

TerraformでCloud RunからCloud SQL for PostgreSQLへ接続してみた
2 分
Terraform GoogleCloud CloudRun CloudSQL SecretManager
Terraform StateをCloud Storage Remote Backendへ移行してみた
2 分
Terraform GoogleCloud CloudStorage
TerraformからGoogle Cloudへ接続してProject情報を取得してみた
3 分
Terraform GoogleCloud
TerraformでArtifact RegistryのDocker Repositoryを作成してみた
2 分
Terraform GoogleCloud Docker
TerraformでBigQuery DatasetとTableを作成してみた
2 分
Terraform GoogleCloud
TerraformでCloud KMSのKeyRingとCryptoKeyを作成してみた
2 分
Terraform GoogleCloud