Zenn
🛠

Kustomize で Cloud Run をデプロイする

2025/03/28に公開
1

クラウドエースの北野です。
Cloud Run を GitHub Actions と Kustomize を使って管理する方法を紹介します。

概要

Kustomize を使い Cloud Run の構成情報を定義し、overlays の各環境のディレクトリで以下のコマンドを実行すると、Cloud Run をデプロイできます。

kustomize build . | gcloud run services replace --project <PROJECT ID> -

GitHub Actions で次のようなジョブを定義すると、GitHub Actions から Kustomize を使って Cloud Run をデプロイできます。

name: Deploy Cloud Run

on:
  workflow_dispatch:

jobs:
  deploy-cloudrun:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    defaults:
      run:
        working-directory: <DIRECTORY PATH>

    steps:
      - uses: actions/checkout@v2

      - name: Authenticate to Google Cloud
        id: authorizaation-googlecloud
        uses: google-github-actions/auth@v1
        with:
          workload_identity_provider: ${{ vars.WORKLOADIDENTITY_PROVIDER_NAME }}
          service_account: ${{ vars.WORKLOADIDENTITY_SERVICEACCOUNT_EMAIL }}

      - name: cloudrun deploy
        id: deploy-cloudrun
        run: kustomize build . | gcloud run services replace --project ${{ vars.PROJECT_ID }} -

はじめに

Cloud Run は構成情報を YAML ファイルで定義でき、Cloud Run を構築する環境ごとにファイルを作成するとデプロイを一意に定義できます。

しかし、環境ごとに作成すると、すべてのファイルを管理しなければなりません。もし、Cloud Run の環境変数を追加したり、データベースへの接続方法を変えたりなど構成を大きく変えると、すべての構成ファイルを変更しなければなりません。開発環境のみ構成ファイルを変更し、他の環境の構成ファイルの変更を忘れ、本番環境などで Cloud Run が想定した挙動にならないということを見かけることがあります。
もし、各環境に構築する Cloud Run の構成情報で共通する部分をテンプレートなどで再利用できれば、こうした運用のミスの削減できると考えられます。

この記事では、Kustomize を使い Cloud Run の構成ファイルを管理し、共通部分を再利用する方法を紹介します。また、定義した構成ファイルを GitHub Actions からデプロイする方法も最後に紹介します。

Kustomize とは

Kustomize は Kubernetes マニフェストのカスタマイズをテンプレートやドメイン固有言語を使わずに行うツールです。マニフェストを複数の目的に合わせてカスタマイズできるため、base で共通部分のマニフェストを作り overlays で各環境に合わせてカスタマイズするという使い方が Kubernetes で広くされています。

Cloud Run の構成情報の YAML ファイルは、Kubernetes のマニフェストと同じ構造をしているため、Kustomize を使い定義することができます。

Kustomize から Cloud Run のデプロイ

次のような Cloud Run を Kustomize からデプロイします。

設定項目
name helloworld
docker image us-docker.pkg.dev/cloudrun/container/hello:sample-public-image-71cb7d367a8875eef4e0d1599b2046a8edfbb018f20d2e0c40fe0124fd5e3106
location asia-northeast1
service account デフォルトサービスアカウント

Kustomize の base では、Cloud Run のリージョンを定義し、イメージのバージョンを latest とします。overlays でサービスアカウントとイメージバージョンを指定します。

以下で紹介する Terraform と Kustomize のコードの <> で囲まれた部分は環境に合わせて読み替えてください。

ローカルからのデプロイ

ローカル環境から Cloud Run をデプロイしてみます。ディレクトリ構造を次のようにします。base の service.yaml に共通部分の構成情報を定義します。

tree
.
├── base
│   ├── kustomization.yaml
│   └── service.yaml
└── overlays
    └── dev
        ├── kustomization.yaml
        └── service.yaml

共通部分の kustomization.yaml と service.yaml は次の通りです。

base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ./service.yaml
base/service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld
  labels:
    cloud.googleapis.com/location: asia-northeast1
spec:
  template:
    spec:
      containers:
        - name: helloworld
          image: us-docker.pkg.dev/cloudrun/container/hello:latest

overlays でカスタマイズする構成ファイルは次の通りです。

overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ../../base

patchesStrategicMerge:
  - ./service.yaml

patchesJson6902:
  - target:
      kind: Service
      name: helloworld
    patch: |-
      - op: replace
        path: /spec/template/spec/containers/0/image
        value: us-docker.pkg.dev/cloudrun/container/hello:sample-public-image-71cb7d367a8875eef4e0d1599b2046a8edfbb018f20d2e0c40fe0124fd5e3106
overlays/dev/service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld
spec:
  template:
    spec:
      serviceAccountName: <PROJECT NUMBER>-compute@developer.gserviceaccount.com

ビルドをしてデプロイされる構成定義を確認すると、base の定義からプロジェクトのデフォルトサービスアカウントが追加されているのと、sample-public-image-71cb7d367a8875eef4e0d1599b2046a8edfbb018f20d2e0c40fe0124fd5e3106 バージョンのイメージを使うようにカスタマイズされているのが分かるかと思います。

kustomize build .
# Warning: 'patchesJson6902' is deprecated. Please use 'patches' instead. Run 'kustomize edit fix' to update your Kustomization automatically.
# Warning: 'patchesStrategicMerge' is deprecated. Please use 'patches' instead. Run 'kustomize edit fix' to update your Kustomization automatically.
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  labels:
    cloud.googleapis.com/location: asia-northeast1
  name: helloworld
spec:
  template:
    spec:
      containers:
      - image: us-docker.pkg.dev/cloudrun/container/hello:sample-public-image-71cb7d367a8875eef4e0d1599b2046a8edfbb018f20d2e0c40fe0124fd5e3106
        name: helloworld
      serviceAccountName: <PROJECT NUMBER>-compute@developer.gserviceaccount.com

ここから実際に Kustomize を使って Cloud Run をデプロイします。デプロイの前に作成する helloworld の Cloud Run が存在しないことを確認します。

gcloud run services describe helloworld --region asia-northeast1 --project <PROJECT ID>
ERROR: (gcloud.run.services.describe) Cannot find service [helloworld]

Cloud Run がないことが確認できたので、以下のコマンドでデプロイして、Cloud Run が作成されることを確認します。

kustomize build . | gcloud run services replace --project <PROJECT ID> -

# Warning: 'patchesJson6902' is deprecated. Please use 'patches' instead. Run 'kustomize edit fix' to update your Kustomization automatically.
# Warning: 'patchesStrategicMerge' is deprecated. Please use 'patches' instead. Run 'kustomize edit fix' to update your Kustomization automatically.
Applying new configuration to Cloud Run service [helloworld] in project [<PROJECT ID>] region [asia-northeast1]
Deploying new service...
Creating Revision..............................................................................................................done
Routing traffic.....done
Done.
New configuration has been applied to service [helloworld].
URL: https://helloworld-<PROJECT NUMBER>.asia-northeast1.run.app

gcloud run services describe helloworld --region asia-northeast1 --project <PROJECT ID>
✔ Service helloworld in region asia-northeast1

URL:     https://helloworld-<PROJECT NUMBER>.asia-northeast1.run.app
Ingress: all
Traffic:
  100% LATEST (currently helloworld-00001-htt)

Scaling: Auto (Min: 0)

Last updated on 2025-03-27T07:22:33.269068Z by <GOOGLE ACCOUNT>:
  Revision helloworld-00001-htt
  Container helloworld
    Image:           us-docker.pkg.dev/cloudrun/container/hello:sample-public-image-71cb7d367a8875eef4e0d1599b2046a8edfbb018f20d2e0c40fe0124fd5e3106
    Port:            8080
    Memory:          512Mi
    CPU:             1000m
    Startup Probe:
      TCP every 240s
      Port:          8080
      Initial delay: 0s
      Timeout:       240s
      Failure threshold: 1
      Type:          Default
  Service account:   <PROJECT NUMBER>-compute@developer.gserviceaccount.com
  Concurrency:       80
  Max instances:     100
  Timeout:           300s

GitHub Actions からのデプロイ

最後に GitHub Actions からデプロイする CD パイプラインを紹介します。
Google Cloud の認証に Workload Identity を使います。Workload Identity を使い GitHub Actions を Google Cloud に認証させる詳細については、こちらの記事を確認ください。

Google Cloud の設定

Workload Identity を設定するため、Workload Identity Pool および、サービスアカウントを次のコードで作成します。

workload_identity.tf
resource "google_iam_workload_identity_pool" "main" {
  workload_identity_pool_id = <WORKLOAD IDENTITY POOL ID>

  project = var.project
}

resource "google_iam_workload_identity_pool_provider" "main" {
  workload_identity_pool_provider_id = <WORKLOAD IDENTITY PROVIDER ID>

  workload_identity_pool_id = google_iam_workload_identity_pool.main.workload_identity_pool_id
  project                   = var.project

  attribute_condition = "assertion.repository == \"<GITHUB ORGANIZATION>/<GITHUB REPOSITORY NAME>\""
  attribute_mapping = {
    "google.subject"       = "assertion.sub"
    "attribute.actor"      = "assertion.actor"
    "attribute.repository" = "assertion.repository"
  }
  oidc {
    issuer_uri = "https://token.actions.githubusercontent.com"
  }
}
service_account.tf
resource "google_service_account" "main" {
  account_id = <SERVICE ACCOUNT ID>

  project = var.project
}

resource "google_service_account_iam_member" "main" {
  service_account_id = google_service_account.main.name

  role   = "roles/iam.workloadIdentityUser"
  member = format("principalSet://iam.googleapis.com/%s/%s", google_iam_workload_identity_pool.main.name, local.filter)
}

resource "google_project_iam_member" "main" {
  project  = var.project

  role   = "roles/editor"
  member = google_service_account.main.member
}

GitHub 変数の設定

GitHub Actions で使う以下の変数を Terraform で定義します。

変数名 変数の内容
PROJECT_ID Cloud Run をデプロイする Google Cloud のプロジェクト ID
WORKLOADIDENTITY_PROVIDER_NAME Workload Identity のプロバイダ名
WORKLOADIDENTITY_SERVICEACCOUNT_EMAIL サービスアカウントの email
github_actions_variables.tf
locals {
  envs = [
    {
      name  = "PROJECT_ID"
      value = var.project
    },
    {
      name  = "WORKLOADIDENTITY_PROVIDER_NAME"
      value = google_iam_workload_identity_pool_provider.main.name
    },
    {
      name  = "WORKLOADIDENTITY_SERVICEACCOUNT_EMAIL"
      value = google_service_account.main.email
    }
  ]
}

resource "github_actions_variable" "main" {
  provider = github.aquamarinearia
  for_each = { for v in local.envs : v.name => v }

  variable_name = each.value.name

  value      = each.value.value
  repository = data.github_repository.main.name
}

実行

次のワークフローを定義し GitHub Actions を実行させます。

workflow.yaml
name: Deploy Cloud Run

on:
  workflow_dispatch:

jobs:
  deploy-cloudrun:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    defaults:
      run:
        working-directory: <DIRECTORY PATH>

    steps:
      - uses: actions/checkout@v2

      - name: Authenticate to Google Cloud
        id: authorizaation-googlecloud
        uses: google-github-actions/auth@v1
        with:
          workload_identity_provider: ${{ vars.WORKLOADIDENTITY_PROVIDER_NAME }}
          service_account: ${{ vars.WORKLOADIDENTITY_SERVICEACCOUNT_EMAIL }}

      - name: Deploy Cloud Run
        id: deploy-cloudrun
        run: kustomize build . | gcloud run services replace --project ${{ vars.PROJECT_ID }} -

<DIRECTORY PATH> は overlays のパスを指定してください。実行すると次のように成功します。

さいごに

Cloud Run のデプロイに Kustomize を使う方法を紹介しました。環境変数が多い Cloud Run を運用している場合、この方法を適用すると運用ミスが減る可能性があるので、活用を検討してみてください。

1

Discussion

ログインするとコメントできます