Cloud Deployを使ったCloud Runのリリース
概要
Cloud RunのリリースにCloud Deployを使ってみます。
そもそもCloud Deployとは
リリースフローを記載したパイプラインの定義を作成し、パイプラインを作成したら、フローを管理できるようになります。各フローでは基本内部で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 の
DeliveryPipeline
とTarget
を記載します - ここを変更する場合はパイプラインの枠自体を更新をする方が良いです
- あり得るのはTargetの変更や、承認などです
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では
diagnosis
、render
、verify
の機能を利用するようです。- もし、imageのbuildをしてからパイプラインを作成してほしい場合は、最初に書かせていただいた通り、Cloud Buildと組み合わせるのが良いようです。
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で指定します(ワイルドカードも使える)
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
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におけるメリットには単純に以下のようなものがあります
- ロールアウトの頻度やエラー割合が自動で集計されており、「Four Keys」における指標の「デプロイ頻度」「デプロイ失敗率」が可視化できる
- devとprodがパイプラインで繋がっているので、リリース管理が容易である
- 複数案件走っている際にどのブランチがーとかを気にしなくても良い
- 戻すとかも、再度プロモートするだけでいける
- 履歴として残っているパイプラインからロールバックが手軽にできる
- 承認をしてロールアウトというフローを作ることができる
また、カナリアリリースができるなどの機能も入ってくるため、よりメリットが見えてくるかと思います。
デメリットというかちょっと使いにくいなと思う点
- なにか起きた際のデバッグが少し難しくなる
- 後述しますがちょっとずつノウハウ貯めるしか無いかもです。
- パイプラインがたくさん溜まってくるので、そこの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