September 29, 2022

Cloud Deployを使ってCloud Runへリリースする

こんにちは。 駅ログ!というアプリを趣味で開発しているのですが、そのバックエンドはCloud Runでホスティングされています。 これまではGitHub Actionsを使ってCI/CDを構築していたのですが、Cloud Deployを採用したので今回はそれについて書きます。

なぜCloud Deployにしたのか

Cloud Deployを採用した理由は以下の通りです。

  1. デプロイメントワークフローに求める機能(承認、ロールバック、etc)をサポートする機能が十分にあること
  2. マネージドサービスであること
  3. メトリクスをGCP上で取得できること
  4. Skaffoldがv2.0.0のBetaリリースからCloud Runをサポートしたこと
  5. 2022/9/13に、Cloud DeployからCloud Runにデプロイできるようになったこと

このような理由があり、Cloud Deployを使ってリリースするような流れにしようと決断しました。 承認フローなどはGitHub ActionsのEnvironment機能でも代替できますが、ロールバックなどの簡易さなどは特にCloud Deployが優れているところだと思います。またCloud Monitoringなどでパイプラインのメトリクスが取得できることは一元化にも繋がり、見通しの良いモニタリングを実施することができると考えています。

セットアップ

移行するとなると、まずはCloud DeployのDelivery PipelineやTargetの設定しなければなりません。

1. Skaffoldの設定

Skaffoldコマンドの起点となるskaffold.ymlを作成します。

apiVersion: skaffold/v3alpha1
kind: Config
metadata:
  name: ekilog
manifests:
  rawYaml:
  - service.yaml
deploy:
  cloudrun: {}

今回は特にProfileなどは使用しませんでした。ここでついでにCloud Runのserviceを定義するservice.yamlを作成しておきます。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: ekilog-backend
spec:
  template:
    spec:
      containers:
        - image: ekilog-backend
      serviceAccountName: ekilog-backend@<PROJECT_ID>.iam.gserviceaccount.com

imageは実行時に上書きされるのでここでは何でも良いです。

2. Targetの設定

駅ログ!では2つのデプロイメント環境があるのでそれぞれCloud Deploy Targetを作成します。YAMLのAPIはFor Cloud Run Targets, Google Cloudから参照をすることができます。

Terraformで作成しようとしましたがgoogle_clouddeploy_target, v4.38.0ではまだサポートされていないので仕方なくYAMLで作成しました。いずれCloud Runを対応されると思います。

apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
 name: prod
description: Production Ekilog backend
run:
 location: projects/PROJECT_ID/locations/asia-northeast1
requireApproval: "true"
executionConfigs:
    - usages:
        - [RENDER | DEPLOY]
      serviceAccount: clouddeploy-backend@<PROJECT_ID>.iam.gserviceaccount.com

executionConfigs.*.serviceAccountはあとのステップで作成します。

3. Delivery Pipelineの作成

以下のようにDeliveryを作成しました。Delivery PipelineはTerraformでも作成できるので、以下のように作成しました。

resource "google_clouddeploy_delivery_pipeline" "primary" {
  project  = google_project.ekilog.project_id
  location = "asia-northeast1"
  name     = "ekilog-backend"

  description = "Ekilog's backend pipeline"

  serial_pipeline {
    stages {
      profiles  = []
      target_id = "dev"
    }

    stages {
      profiles  = []
      target_id = "prod"
    }
  }
}

4. Cloud DeployがCloud Run Serviceをデプロイできるように設定をする

Terraformを使って諸設定をします。

4.1 Cloud Deploy用のService Accountを用意する

Cloud Deployが使うサービスアカウントは2種類あります。

  1. Service Agent: 主にGoogle側によって、顧客のGCP Projectで諸々操作(プロビジョニングなど)をするために使われるもの
  2. Execution Service Account: 顧客がDelivery Pipelineを実行したときに使われるもの。デフォルトではGCE service accountが使われる。

デフォルトのものを使うのは好ましくないので、以下のようにサービスアカウントを作成しました。

resource "google_service_account" "clouddeploy_backend" {
  account_id   = "clouddeploy-backend"
  project      = google_project.ekilog.project_id
  display_name = "clouddeploy-backend"
}

4.2 権限の付与

先程作ったサービスアカウントに以下の権限を付与します。

  • clouddeploy.jobRunner Project IAM
  • roles/run.developer Project IAM
  • Cloud Run service accountに対するroles/iam.serviceAccountUser service account IAM
resource "google_project_iam_member" "clouddeploy_backend_is_clouddeploy_job_runner" {
  project = google_project.ekilog.project_id
  role    = "roles/clouddeploy.jobRunner"
  member  = "serviceAccount:${google_service_account.clouddeploy_backend.email}"
}

resource "google_project_iam_member" "clouddeploy_backend_is_run_developer" {
  project = google_project.ekilog.project_id
  role    = "roles/run.developer"
  member  = "serviceAccount:${google_service_account.clouddeploy_backend.email}"
}
resource "google_service_account_iam_member" "clouddeploy_backend_is_ekilog_backend_user" {
  service_account_id = google_service_account.ekilog_backend.name
  role               = "roles/iam.serviceAccountUser"
  member             = "serviceAccount:${google_service_account.clouddeploy_backend.email}"
}

ここまで設定を終えると、以下のようにコマンドを実行できます。

$ gcloud deploy releases create ekilog-prod-003 \
  --project=<PROJECT_ID> \
  --region=asia-northeast1 \
  --delivery-pipeline=ekilog-backend \
  --images=ekilog-backend=<IMAGE_PATH_ON_GAR>

5. GitHub Actionsから実行できるようにする

CI(今回はGitHub Actions)から実行させるには以下の権限がGitHub Actionsのservice accountに必要になります。

  • clouddeploy.releaser Project IAM
  • Cloud Deploy service accountに対するiam.serviceAccount.actAs service account iam

あとはGitHub Actionsからトリガーをするだけです。

参考文献

© KeisukeYamashita 2023