Cloud Run とは
GCP が提供するサーバレスのコンピュートサービス。コンテナイメージを指定してデプロイすると、url が割り当てられ、http や grpc のリクエストが受けられる。
スケーリングも勝手に行えるので、Kubernetes でいう HPA や Cluster Autoscaler に気を遣う必要がない。
PipeCD とは
GitOps で Deploy できる Deploy tool。
過去回。
blog.chaspy.me
blog.chaspy.me
blog.chaspy.me
前回までは Terraform を試していたが、今回は Cloud Run を Deploy してみる。
事前準備
http request に対して hello を返す go のアプリを書き、CI で Artifact Registry に push するところまで整えた。
PipeCD は「Deploy」をするツール(CDだし)なので、それ以前の Image Build まではやる必要がある。
blog.chaspy.me
github.com
PipeCD の準備
PipeCD は Example の「canary」を参考にし、ほぼそのまま使った。
github.com
service.yaml はこんな感じ。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: canary
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/maxScale: '2'
spec:
containerConcurrency: 80
containers:
- args:
- server
image: asia-northeast1-docker.pkg.dev/hello-cloudrun-336811/hello-cloudrun/hello-cloudrun:a50a3aae930b07c5ce46851fd04d4e2278c12c68
ports:
- containerPort: 8080
resources:
limits:
cpu: 1000m
memory: 128Mi
.pipe.yaml はこんな感じ。
apiVersion: pipecd.dev/v1beta1
kind: CloudRunApp
spec:
pipeline:
stages:
- name: CLOUDRUN_PROMOTE
with:
percent: 10
- name: WAIT
with:
duration: 30s
- name: CLOUDRUN_PROMOTE
with:
percent: 50
- name: WAIT
with:
duration: 30s
- name: CLOUDRUN_PROMOTE
with:
percent: 100
これは example そのまんまですね。
これを repository に push し、control plane で application を作成する。
ちなみに CloudRun を Deploy するためには piped 側に Provider の設定が必要。
こういう piped.yaml を使って
apiVersion: pipecd.dev/v1beta1
kind: Piped
spec:
projectID: pipecd
pipedID: piped-id
pipedKeyData: piped-key
apiAddress: control-plane-fqdn:443
webAddress: https://contol-plane-fqdn
syncInterval: 1m
git:
sshKeyFile: /etc/piped-secret/ssh-key
repositories:
- repoId: chaspy-test
remote: git@github.com:org/repo.git
branch: main
chartRepositories:
- name: pipecd
address: https://charts.pipecd.dev
cloudProviders:
- name: kubernetes-default
type: KUBERNETES
- name: terraform-dev
type: TERRAFORM
config:
vars:
- "project=pipecd-dev"
- name: cloudrun-dev
type: CLOUDRUN
config:
project: hello-cloudrun-336811
region: asia-northeast1
credentialsFile: /etc/piped-secret/cloudrun-sa
- name: lambda-dev
type: LAMBDA
config:
region: ap-northeast-1
profile: default
- name: ecs-dev
type: ECS
config:
region: ap-northeast-1
profile: default
secretManagement:
type: KEY_PAIR
config:
privateKeyFile: /etc/piped-secret/secret-management-private-key
publicKeyFile: /etc/piped-secret/secret-management-public-key
こういうふうにいくらかは local file を渡して helm で deploy している。
#!/bin/bash
helm upgrade -i dev-piped pipecd/piped \
--version=v0.22.0 \
--namespace=pipecd \
--set-file config.data=piped.yaml \
--set-file secret.data.ssh-key="/Users/chaspy/.ssh/id_rsa" \
--set-file secret.secretManagementKeyPair.publicKey.data=./public-key \
--set-file secret.secretManagementKeyPair.privateKey.data=./private-key \
--set-file secret.data.cloudrun-sa=cloudrun/canary/sa.json
GCP 側の準備
Cloud Run の API の有効化などは必要だと思うが、必要なのは Service Account とその Key。
もともと Artifact Registry に Push するための Service Account があったので、それに Key を発行しました。
権限としては Cloud Run 管理者
と サービス アカウント ユーザー
の2つのロールをつけています。
Cloud Run は多分管理者じゃなくてもっと小さくてもいいと思う。
特にハマったのがここで、
cloud.google.com
servive accout user role は
iam.serviceAccounts.actAs
iam.serviceAccounts.get
iam.serviceAccounts.list
resourcemanager.projects.get
resourcemanager.projects.list
を持っていて、特に iam.serviceAccounts.actAs
が必要。これは何かというと、特定のサービスにおいては、SA がそれらのサービスを触る権限に加えて、その SA を使うことそのものを許可する必要があるようだ。
以下のエラーでハマっていた。(しかもなぜかこの時の ID が compute engine default account がでていてさらに混乱した。ci-build という別の ID の SA を使っていたのに。)
googleapi: Error 403: Permission 'iam.serviceaccounts.actAs' denied on service account 1111111111111-compute@developer.gserviceaccount.com (or it may not exist)., forbidden
cloud.google.com
によると App Engine とか Cloud Composer がそうだと言っているように見えるけど Cloud Run は書いてない。まぁとにかく最近のサービスはこれが必要ということにしておこう。
Let's Deploy
こういう Image を更新する PR を作ります。
初回だったので plan-preview は何も言っていません。
初回デプロイ終了後はこういう状況で、
PR をマージすると PipeCD の UI で Deploy が進んでいます。CloudRunApp で設定したように、10% -> 30秒待つ -> 50% -> 30秒待つ -> 100% という風に Rollout していきます。
10% Deploy 完了
さらに Pipeline は進んで
50% 完了
最後まで終わりました
最終バージョンにトラフィックが 100% 割り振られています。
Cloud Run が持つ Canary Release の仕組み
PipeCD がこのような Canary Release をなぜ実現できるのかというと、そもそも Cloud Run 自体が Traffic Splitting の機能を持っているからです。
Cloud Run の実態は Knative が動いているようで、今回用意したservice.yaml もそうですが、Cloud Run を Deploy するとそれを表現した yaml を確認することができます。
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: canary
namespace: '111111111111'
selfLink: /apis/serving.knative.dev/v1/namespaces/111111111111/services/canary
generation: 3
creationTimestamp: '2022-01-01T03:18:48.557008Z'
labels:
cloud.googleapis.com/location: asia-northeast1
annotations:
serving.knative.dev/creator: ci-build@hello-cloudrun-111111.iam.gserviceaccount.com
serving.knative.dev/lastModifier: ci-build@hello-cloudrun-111111.iam.gserviceaccount.com
run.googleapis.com/ingress: all
run.googleapis.com/ingress-status: all
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/maxScale: '2'
spec:
containerConcurrency: 80
timeoutSeconds: 300
containers:
- image: asia-northeast1-docker.pkg.dev/hello-cloudrun-336811/hello-cloudrun/hello-cloudrun:a50a3aae930b07c5ce46851fd04d4e2278c12c68
args:
- server
ports:
- name: http1
containerPort: 8080
resources:
limits:
cpu: 1000m
memory: 128Mi
traffic:
- revisionName: canary-a50a3aae930b07c5ce46851fd04d4e2278c12c68-246c0b4
percent: 50
- revisionName: canary-787644e4f49946792ff4044b7da399874a377269-d60586c
percent: 50
status:
observedGeneration: 3
conditions:
- type: Ready
status: 'True'
lastTransitionTime: '2022-01-01T03:34:57.321507Z'
- type: ConfigurationsReady
status: 'True'
lastTransitionTime: '2022-01-01T03:34:57.321507Z'
- type: RoutesReady
status: 'True'
lastTransitionTime: '2022-01-01T03:34:54.385969Z'
latestReadyRevisionName: canary-n9jvd
latestCreatedRevisionName: canary-n9jvd
traffic:
- revisionName: canary-a50a3aae930b07c5ce46851fd04d4e2278c12c68-246c0b4
percent: 50
- revisionName: canary-787644e4f49946792ff4044b7da399874a377269-d60586c
percent: 50
url: https://canary-jqu5pzsjea-an.a.run.app
address:
url: https://canary-jqu5pzsjea-an.a.run.app
apiVersion: serving.knative.dev/v1
の Service
という kind に traffic というものが存在し、これで Revision に対するトラフィックの割合を指定できます。PipeCD は CloudRunApp に従ってこれを操作していると思われます。
kind は他に Route, Revision, Configuration があるようです。
knative.dev
Test in Production
Cloud Run は Traffic 0% でデプロイして、タグを付与することで特別な url でアクセスすることができます。本番の実トラフィックに影響を与えることなく、本番相当の環境でテストできる Test In Production を実現できます。
例えば新規でデプロイした Revision に test タグをつけると、https://test---canary-jqu5pzsjea-an.a.run.app/ という url でアクセスが可能です。
この機能は Knative の機能ではなく Cloud Run の拡張機能のようで、PipeCD 側からもこの設定をすることは残念ながらできないようです。
これ自体は gcloud run deploy で実現可能です。--tag と --no-traffic を組み合わせれば Preview URL を発行することができます。
cloud.google.com
PipeCD は Analysis という、対象の url へのヘルスチェックの機能があるため、個人的にはせっかく CloudRun が 0% Deploy & preview url (tag) をサポートしているので、0% でリリースし、そこへアクセスして成功率が問題ないことを確認しながら徐々にロールアウト、ということが実現できればかなり安全にアプリケーションのリリースができるだろうと思いました。
pipecd.dev
他のデプロイ方式との比較
もっともストレートなのは Google Cloud Build を使った継続的デプロイだと思います。
それ以外にも GitHub Actions でも gcloud auth/cli を使うための actions が用意されている&Workload identity Federation もあることから、良い選択肢かと思います。Image の Build と Push は https://github.com/chaspy/hello-cloudrun でしたように簡単ですし、デプロイは gcloud run deploy をすれば実現可能です。
PipeCD を使う優位性は WAIT や APPROVE を使った Pipeline が実現可能という点だと思います。また、ANALYSIS によって、徐々に展開しながらエラーが増えたらすぐ戻すということも実現できます。
GitHub Actions などで自前でやる場合は、Rollout の Promotion は別途何か自分で仕組みを書いてあげる必要があります。
おわりに
Cloud Run の準備に手間取りましたがよくできていると思いましたし、PipeCD が Canary Release をサポートしている Cloud Run のサポートに目をつけたのは賢いなと思いました。