Closed13

Cloud Deploy と Cloud Run をためす

ピン留めされたアイテム
waddy_uwaddy_u

結論

  • 現在、擬似的にすべてのビルド・デプロイ作業を Cloud Build (+gcloudコマンド)で実施している
  • Cloud Deploy を組み込むことは少なからずこれを崩すことであり、コストメリットが薄い
  • コスト
    • ブランチ・リリース戦略の見直し(mainブランチへ一本化したほうがよさそう)
    • 検証環境の昇格戦略の見直し(検証・本番でビルドイメージを統一したほうがよさそう)
    • Google Cloud プロジェクト構成の見直し
    • DBマイグレーション実行タイミングと実行方法の調整
  • メリット
    • デプロイサイクルに関するメトリクスの収集

プロジェクトが黒字になり、チーム人数が10人を超えたら検討するでよさそう。

waddy_uwaddy_u

モチベーション

  • デリバリパフォーマンスを計測したい
  • 現状 Cloud Run へのデプロイ制御にために手動でコマンドを打つ場面があり、これを承認ボタンはいOKに置き換えたい

わかっていないので知りたいこと

  • どんなメトリクスがとれるのか
  • いま、Cloud Build で DB マイグレーションを実行している。Cloud Deploy によるデプロイへ置き換えたとき、これはどうすればよいだろうか
waddy_uwaddy_u

まずはチュートリアルをやってみる

全体像をつかむため、チュートリアルをやる。

https://cloud.google.com/deploy/docs/deploy-app-run?hl=ja

サンプルは Compute Engine のサービスアカウントにロールを付与しているが、Cloud Deploy 専用のサービスアカウントを個別に作ることとした。

variable "project_id" {
  description = "GCPのproject_idです"
  type        = string
}
variable "cloud_run_backend_service_account_name" {
  description = "Cloud Run に設定するサービスアカウントです。Cloud Runサービスアカウントを利用するのに利用します。"
  type        = string
}
variable "cloud_run_frontend_service_account_name" {
  description = "Cloud Run に設定するサービスアカウントです。Cloud Runサービスアカウントを利用するのに利用します。"
  type        = string
}
resource "google_service_account" "cloud_deploy_for_app" {
  project      = var.project_id
  account_id   = "cloud-deploy-for-app"
  display_name = "Cloud Deploy for Applications Service Account"
}

# 参考: https://cloud.google.com/deploy/docs/deploy-app-run?hl=ja
# clouddeploy.jobRunner
resource "google_project_iam_member" "cloud_deploy_for_app_job_runner" {
  project = var.project_id
  role    = "roles/clouddeploy.jobRunner"
  member  = "serviceAccount:${google_service_account.cloud_deploy_for_app.email}"
}

# roles/run.developer
resource "google_project_iam_member" "cloud_deploy_backend_is_run_developer" {
  project = var.project_id
  role    = "roles/run.developer"
  member  = "serviceAccount:${google_service_account.cloud_deploy_for_app.email}"
}

# Cloud Deploy が Cloud Run サービスアカウントを利用できるように
resource "google_service_account_iam_member" "clouddeploy_is_backend_runner_user" {
  service_account_id = var.cloud_run_backend_service_account_name
  role               = "roles/iam.serviceAccountUser"
  member             = "serviceAccount:${google_service_account.cloud_deploy_for_app.email}"
}

resource "google_service_account_iam_member" "clouddeploy_is_frontend_runner_user" {
  service_account_id = var.cloud_run_frontend_service_account_name
  role               = "roles/iam.serviceAccountUser"
  member             = "serviceAccount:${google_service_account.cloud_deploy_for_app.email}"
}

Cloud Run のサービスアカウントがふたつあるのでそれぞれでCloud Deployが利用できるように google_service_account_iam_member も2つ追加。

IAMリソースを作ったら、あとは流れに沿ってやるだけ。

  • clouddeploy.yaml
  • run-dev.yaml
  • run-prod.yaml
  • skaffold.yaml

これらを用意して、コマンドを実行する。

# Cloud Deploy パイプラインを作成する
 gcloud deploy apply --file=clouddeploy.yaml --region=us-central1 --project=9999999999

# リリースを作成する
gcloud deploy releases create test-release-001 \ 
                                   --project=999999999 \
                                   --region=us-central1 \
                                   --delivery-pipeline=my-run-demo-app-1 \
                                   --images=my-app-image=gcr.io/cloudrun/hello

waddy_uwaddy_u

わかったこと

  • Cloud Run のサービスを作成できる
  • 任意のイメージを Cloud Run へデプロイできる
  • まず 動作確認用のサービスにデプロイしたあと、昇格という形で本番用のサービスにデプロイすることを想定しているようだ
waddy_uwaddy_u

Cloud Run のパラメータとかどやって設定するの

https://cloud.google.com/deploy/docs/run-targets?hl=ja#option_2_copy_a_serviceyaml_from_an_existing_service_using

デプロイ済みのCloud Runで手に入るマニフェストを参考にするらしい。これを kind: Service のやつとする模様。

たぶんこのへん。

spec:
  template:
    metadata:
      name: backend
      annotations:
        run.googleapis.com/client-name: gcloud
        client.knative.dev/user-image: asia-northeast1-docker.pkg.dev/***
        run.googleapis.com/client-version: 433.0.0
        run.googleapis.com/cloudsql-instances: ***
        run.googleapis.com/execution-environment: gen1
        autoscaling.knative.dev/maxScale: '3'
        run.googleapis.com/cpu-throttling: 'false'
    spec:
      containerConcurrency: 40
      timeoutSeconds: 300
      serviceAccountName: backend****
      containers:
      - image: asia-northeast1-docker.pkg.dev/***
        ports:
        - name: http1
          containerPort: 8080
        env:
        - name: RAILS_ENV
          value: production
        - name: WORKER_COUNT
          value: '1'
        - name: RAILS_MAX_THREADS
          value: '16'
        resources:
          limits:
            cpu: '1'
            memory: 2Gi
        startupProbe:
          timeoutSeconds: 240
          periodSeconds: 240
          failureThreshold: 1
          tcpSocket:
            port: 8080

上記は gcloud run deploy を使ってオプション指定したものだが、それで手に入るマニフェストが参考にできそう。

waddy_uwaddy_u

Cloud Deploy を使った方法に移行できるか?

できるかできないかでいうと、できる。たが、大幅なリリースフローの調整が必要。

そもそもいま、

  • 検証用の Google Cloud プロジェクト
  • 本番用の Google Cloud プロジェクト

に分かれている。ということで、Cloud Deploy の昇格機能をフルに活かすためにはまずここを同じ Cloud Deploy パイプラインにまとめなければならない。これを満たすためには、

  • クロスプロジェクトで Cloud Run サービスをデプロイできる必要あり
  • ソースコードのリポジトリマージフローも見直し(main, developブランチがあるがこれをmainに一本化する必要あり)

このような作業が必要になる。

waddy_uwaddy_u

DBマイグレーションどうする?

ドキュメントとしてはノータッチであった。まあ、「DBマイグレーションとアプリケーションは独立して最新版を apply できるべき」はそうなんだけど。いつかは同期するべきじゃない、ねえ奥様。最近のデプロイシステムはDBマイグレーションに関してノータッチのやつも多いけど、ちょっとわずかに言及があるだけでも嬉しいんだけどなー。

DBマイグレーションはアプリと密にするか疎にするかふたつの方法があると思っていて、密にするほうだと:

  • Cloud Run 起動時に自動でマイグレーションするように
  • Cloud Build のアプリビルドの中でマイグレーションを実行するように

こういったやり方がありそう。ただ、このやり方は実質的なロールバック禁止でもある。何か間違えたときは手運用でのDB操作はやらないほうがよくて、アプリケーションを修正して再リリースの流れが現実的。

疎結合にするやり方だと:

  • 独立したスクリプトを用意して、リリースフローのどこかで実行する

ことになる。しかしこれは、Cloud Build や Cloud Deploy を組み合わせてデプロイするときに考慮するポイントが増えることになる。Cloud Deploy の流れに載せられないので。

いまは、「スクリプトを任意のタイミングでCloud Buildで実行できる」というようにしていたので疑似的に Cloud Build にすべてまとまった状態となっていた。これを崩す場合は DBマイグレーションの実行環境と組み込み方を改めて再構築刷る必要がありそう。

理想:

Cloud Deploy のパイプラインで「カナリアリリース後、New環境で任意のコマンドが実行できる」機能があれば最強。

waddy_uwaddy_u

To: @sbogdantbl

Thanks for getting back to me, Cloud Deploy is a great service.

Users who are highly proficient with Cloud Run are either leveraging Cloud Build, gcloud scripts, or both. I think it will take some time to adapt as knative specs for GKE appear in this abstracted situation.

Cloud Deploy's ability to automatically collect metrics about the deployment cycle and the Promote feature are attractive, and I would suggest the following as a way to leverage them with Cloud Run.

Instead of using knative specs at each step of the pipeline, gcloud commands can be used.
Cloud Run users are accustomed to deploying with gcloud commands, and it would be more applicable if the DeliveryPipeline could be defined in yaml and any command could be executed in the serialPipeline stages.

An example of the envisioned pipeline:

  1. check if the Artifact Registry image generated by Cloud Build exists
  2. Deploy to Cloud Run service A
  3. Deploy to Cloud Run Service B
  4. approve it
  5. Perform DB migration
  6. Set the traffic of Cloud Run Service A to 100%.
  7. Increase traffic on Cloud Run service B to 100%
  8. Notify Slack that the deployment is complete

This may be beyond the scope of what we envision in Cloud Deploy, but we would be happy to cover it in Cloud Deploy.

Hidden comment
Hidden comment
Hidden comment
このスクラップは2023/06/01にクローズされました