😃

Cloud Deployを使ったCloud Runのリリース

2023/09/13に公開

概要

Cloud RunのリリースにCloud Deployを使ってみます。

そもそもCloud Deployとは

https://cloud.google.com/deploy?hl=ja
GKE、Cloud Runのリリースを管理できるサービスになります。
リリースフローを記載したパイプラインの定義を作成し、パイプラインを作成したら、フローを管理できるようになります。各フローでは基本内部でskaffoldを通して、Cloud Buildが実行される形です。

Cloud Deployを使うと以下のような、リリースフローになるかと思います。

  • Cloud BuildでImageをBuild、Artifact RegistroryにPush、Cloud Deployのパイプラインを作成
  • Cloud Deployでリリースの管理
  • 検証環境にて確認が終わり次第Cloud Deployでプロモートして、公開

Cloud Deployで利用されている用語のまとめ

初めて触った際にどの言葉がどういう意味で使われているのかが分からなかった記憶が有るので、まとめておきます。

用語 説明
ロールアウト リリースとほぼ同義。イメージとしては、「ここから運用が始まるよー」という意味で使われるっぽい
パイプライン ロールアウトの一連の流れをまとめたもの。このパイプラインでは、このImageをロールアウトします。という感じ
レンダリング GKEやCloud Runの反映に使われるYamlに対して、変数を埋め込み、適応する. kubectl apply するような感じ
ターゲット ロールアウトが実行される環境
プロモート 「環境に反映する」とほぼ同義。対象のターゲットに対してレンダリングをする
ロールバック 現在の状況から特定のパイプラインのロールアウトまで戻す

使ってみる

今回は単純にNest.jsをdeployするアプリケーションをCloud Runでリリースするというケースでやってみます。
前準備などは以下を参考にしてください。

ファイルを作成する

今回 prod と dev という環境を用意します。
まずはCloud Runのserviceとしてprodとdevを作るようにします。

作る必要があるファイルは基本的には以下3つです

  • Cloud Deploy用のyaml
  • skaffold用のyaml
  • Cloud Run用のyaml

Cloud Deploy用のyaml(clouddeploy.yaml)

  • このファイルから、パイプラインの定義が作成されます
  • deploy.cloud.google.com/v1 の DeliveryPipelineTarget を記載します
  • ここを変更する場合はパイプラインの枠自体を更新をする方が良いです
    • あり得るのはTargetの変更や、承認などです
clouddeploy.yaml
apiVersion: deploy.cloud.google.com/v1
kind: DeliveryPipeline
metadata:
  name: my-run-app-1
description: main application pipeline
serialPipeline:
  stages:
    - targetId: run-qsdev
      profiles: [dev]
    - targetId: run-qsprod
      profiles: [prod]

---
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
  name: run-qsdev
description: Cloud Run development environment
run:
  location: projects/{projectId}/locations/asia-northeast1

---
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
  name: run-qsprod
description: Cloud Run production environment
run:
  location: projects/{projectId}/locations/asia-northeast1

skaffold用のyaml(skaffold.yaml)

  • こいつから、パイプラインが作成されます
  • 上記のCloud Deploy用のyamlに対応する profiles を定義し、 その際に利用されるrun-dev.yaml または run-prod.yaml を指定します。
  • skaffoldは本来buildなど色々機能がありますが、Cloud Deployでは diagnosisrenderverifyの機能を利用するようです。
    • もし、imageのbuildをしてからパイプラインを作成してほしい場合は、最初に書かせていただいた通り、Cloud Buildと組み合わせるのが良いようです。
skaffold.yaml
apiVersion: skaffold/v3
kind: Config
metadata:
  name: cloud-run-application
profiles:
  - name: prod
    manifests:
      rawYaml:
        - run-prod.yaml
  - name: dev
    manifests:
      rawYaml:
        - run-dev.yaml
deploy:
  cloudrun: {}

Cloud Run用のyaml(run-dev.yaml, run-prod.yaml)

  • 実際にCloud Runに対してレンダリングされるyamlで、ファイル名はskaffold.yamlで指定します(ワイルドカードも使える)
run-dev.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  annotations:
    run.googleapis.com/launch-stage: BETA
  name: deploy-qs-dev
  labels:
    cloud-deploy-target: run-dev
spec:
  template:
    spec:
      containers:
        - image: my-app-image
          name: app
          env:
            - name: ENVIRONMENT
              value: dev
run-prod.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  annotations:
    run.googleapis.com/launch-stage: BETA
  name: deploy-qs-prod
  labels:
    cloud-deploy-target: run-prod
spec:
  template:
    spec:
      containers:
        - image: my-app-image
          name: app
          env:
            - name: ENVIRONMENT
              value: prod

パイプラインの定義を作成

上記ファイルを用意して、以下コマンドでパイプラインの定義を作成します。

gcloud deploy apply --file=clouddeploy.yaml

パイプラインを作成

パイプラインの作成は以下のとおりです. --skaffold-file optionを使ってファイル指定もできます

gcloud deploy releases create {パイプライン名} \
  --project={projectId} \
  --region=asia-northeast1 \
  --delivery-pipeline={clouddeploy.yamlのmetadata.name} \
  --images {run-dev.yaml,run-prod.yamlのspec.template.spec.containers[].image}={ロールアウトしたいImage}

パイプライン定義の修正は以下のとおり、作成と同じで良いです

gcloud deploy apply --file=clouddeploy.yaml 

Cloud Deployのメリット

ここまで見ている限り、単純にリリースであれば、GitHubのPRに合わせて、Cloud Buildを動かす(build and deploy command実施)という流れでもいいじゃないかと思うでしょう。(私もそうでした
Cloud Deployにおけるメリットには単純に以下のようなものがあります

  1. ロールアウトの頻度やエラー割合が自動で集計されており、「Four Keys」における指標の「デプロイ頻度」「デプロイ失敗率」が可視化できる
  2. devとprodがパイプラインで繋がっているので、リリース管理が容易である
    • 複数案件走っている際にどのブランチがーとかを気にしなくても良い
    • 戻すとかも、再度プロモートするだけでいける
  3. 履歴として残っているパイプラインからロールバックが手軽にできる
  4. 承認をしてロールアウトというフローを作ることができる

また、カナリアリリースができるなどの機能も入ってくるため、よりメリットが見えてくるかと思います。

デメリットというかちょっと使いにくいなと思う点

  1. なにか起きた際のデバッグが少し難しくなる
    • 後述しますがちょっとずつノウハウ貯めるしか無いかもです。
  2. パイプラインがたくさん溜まってくるので、そこのID管理を考える必要がある
    • 動作確認などではCloud Deployのパイプラインを作らないほうが良いかと
    • PRの際に修正したら前のパイプラインを削除するなどができれば良いかなと

まとめ

Cloud Deploy使ってのリリース管理はスタートアップとかでは利用しにくいかもしれませんが、フローをちゃんとしていこう、けど、ArgoCDとか管理すんのめんどいっすなぁ、みたいな、ちょっと組織が出来上がってきているチームには良いサービスかと思いました。
以下の「動かんときに見る部分」のとおり、癖がありますが慣れれば大丈夫(沼に入りましょう)!
今度は、Cloud Deployによるカナリアリリースと、デプロイフックについてまとめたいと思いますー。

Cloud Deployが動かんときに見る部分

そもそもCloud Runがデプロイできるか?をまず確かめてみましょう。
先ほど作成した run-dev.yaml を使ってdeployするのが良いです。 my-app-imageの部分を変更するのを忘れず。

gcloud run services replace run-dev.yaml

それでも、よくわからんエラーログがでて、パイプラインの作成ができない

よくわからんエラーというのは、わりと致命的な気もしているのですが、とりあえず私が遭遇したエラー

getting client config for Kubernetes client 〜〜〜

getting client config for Kubernetes client: error creating REST client config in-cluster: unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined

Cloud Runに対してrenderしてもらおうというのに、なぜ KUBERNETES_SERVICE_HOST と言われるのか。というエラー。
skaffoldに対して以下のattributeがないといけないです。

deploy:
  cloudrun: {}

unable to unmarshal Cloud Run Service config

unable to unmarshal Cloud Run Service config

こちらはCloud Runのyamlでエラーになっているというエラー。
ただ、これがどこでエラーになっているかがわかりません。デフォルトで埋められる可能性のある場所を外してみるのが良いかもです。
例えば、以下の spec.template.spec.containers.ports 部分が有るとエラーになりました。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  annotations:
    run.googleapis.com/launch-stage: BETA
  name: deploy-qs-dev
  labels:
    cloud-deploy-target: run-dev
spec:
  template:
    spec:
      containers:
        - image: my-app-image
          name: app
          ports:
	    - containerPort: "8080"
	  env:
            - name: ENVIRONMENT
              value: dev

参考

Discussion