Cloud Deploy 実践編: CI との連携
前回『デプロイに全集中!新サービス Cloud Deploy』では、Cloud Deploy (現在プレビュー段階です)の背景にある思想 & 基本的な使い方をご紹介しました。今回は少し視野を広げ CI との関係を知り、連携して動かすことをゴールに、その過程で考慮すべきポイントも併せてご紹介します。
TL;DR
- CI と CD の管理主体が分かれます、改めて理想を検討しましょう
- git リポジトリでテスト・ビルド・デプロイ “方法” を管理
- CI でテストし、ビルドし、成果物をまとめる
- CD で成果物とデプロイ先の管理 & ロールアウト / ロールバック
- この 3 つを繋ぐのは Skaffold
ローカルから実行環境までの様々な環境差異
視野を広げつつも、今回も Google はどんなことを課題と捉え、何を解決しようとしているのかを一緒に考えてみたいと思います。
CI / CD パイプライン
パイプラインの構築、好きですか?
わたしは結構好きです。が、つらくもある。パイプラインの構築・運用をされたことがあれば、こんなことに共感いただけると思います。
- CI 環境依存への対処、ツール類のインストールは本質的でなく不毛
- 技術スタックが異なると CI スクリプトにはそれほど汎用性がない
- ローカルと CI と CD でスクリプトを一貫させるのは意外と難しい
- 結果、結局新しいパイプライン作る度に試行錯誤している
ここで大事なのは、CI / CD はモダンな開発・運用にはひじょーーーに重要で必須といえるものなのに、管理工数が相応にかかる代物だということです。ではその作業負荷を減らすには?それが Skaffold に繋がる理由です。
Skaffold 採用の背景
Cloud Deploy 単体でみると、なぜ学習コストのかかる Skaffold をその下地にしたのかがよくわかりません。しかし実際に使ってみると、実は上記課題を緩和する優れた手段であることに気付けます。
特徴を 3つ紹介させてください。
1 つ目はツールのラッパーであること。私自身ラッパーにあまりいい思い出はないものの、Skaffold はバランスが絶妙です。
skaffold build
> docker build, pack build, jib build, bazel build, ..skaffold render
> kustomize build, helm template, kpt fn render, ..
これにより、プロジェクトが採用するビルドシステムや k8s のパッケージング システムに差異があろうと、skaffold.yaml さえおいてあれば CI / CD 側ではプロジェクト依存を軽減したパイプラインが構築できます。
2 つ目は扱う課題の範囲が CI / CD ととても相性がいいことです。この絵をご覧ください。
実はこれ、Skaffold のローカル開発環境での動作を説明する絵なのですが、CI / CD のことと思いませんでしたか?だとすればそれは素晴らしいことで、本来はそれが理想とも思えます。一貫性大事ですよね。実際、Cloud Deploy は内部的にこの絵でいう Render と Deploy を Skaffold に頼っていますし、CI では Build ~ Push を skaffold build
1 コマンドで済ませることもできます。
そして 3つ目は環境差異をプロファイルとして扱えるということです。Skaffold には大きく build と deploy に関する設定項目があるのですが
apiVersion: skaffold/v1
kind: Config
build:
...
deploy:
...
profiles:
- name: dev
deploy:
...
- name: prod
deploy:
...
上記の通り、環境差異はプロファイルとして差分をもたせることができるため、ひとつの git リポジトリでもスマートに設定を保持できます。
(余談ですが。Google Cloud には Cloud Run というものすごーーーく簡単にアプリケーションをホストできるサーバーレス製品があるのですが、Knative という OSS の API ベースなんですね。で、Knative は Kubernetes ベースなのです。ということは・・・そう、Cloud Run アプリケーションも、実は skaffold.yaml を用意しておくと捗ります。実例はいつかブログで・・)
CI との連携
すみません、ようやく本題です。まず前回お伝えした Cloud Deploy の特徴を思い出してみてください。
- 同時にデプロイしたい成果物を “リリース” としてまとめる
- パイプラインは複数の “ターゲット” を持ち、順にデプロイしていく
- 同一のリリースが展開されるので、都度のビルドは不要
ハンズオン集
こちらの設定をベースに実際の連携をご説明します。
Cloud Deploy の特徴を前提にしたとき、CI ですべきこと
テストはもちろんですが、成果物のビルド と Cloud Deploy でのリリース作成 の 2 つが CI の担当すべき範囲です。コマンドでは以下です。
skaffold build --default-repo <repo> --file-output build.out --push
gcloud deploy releases create --build-artifacts build.out
Cloud Deploy を使うだけならリリース作成コマンドだけでいいのですが、 Skaffold を使ったビルドもあわせてお勧めします。一押しの理由は “ビルド アーティファクト” が扱いやすくなるからです。こちらの画像をご覧ください。
Cloud Deploy でリリースを作ると、このような情報 + ロールアウトの履歴が管理されるようになります。このリリースに含まれるコンテナイメージ(成果物)の一覧は “ビルド アーティファクト” として保存されていますよね。--build-artifacts
オプション、使っておいたほうがお得です。
skaffold build
は--file-output
オプションをつけると、そのまま Cloud Deploy に渡せる JSON を出力します。GitHub Actions でいえばこのあたりがその実装です。
また、おまけながら Skaffold の --default-repo
オプションも有用です。Kubernetes のマニフェスト上の image 名はこのように単純に app とだけ書いておいて
kind: Deployment
apiVersion: apps/v1
spec:
..
containers:
- image: app
skaffold.yaml 側でそれに一致する名前にしておくと、
apiVersion: skaffold/v1
kind: Config
build:
artifacts:
- image: app
--file-output
オプションで出力されるイメージ名が「--default-repo
+ Skaffold の設定に従ったタグ」になり、最終的にデプロイされる k8s マニフェストでは都度、適切な名前に置換されます。もうイメージ名のためだけに、それを書き換えるようなコマンドは CI / CD 内に不要です!
開発環境、CI / CD 環境を改めて考える
git のブランチ戦略、デプロイ戦略の再考
そもそもの課題として、CD を CI から行うとリードタイムが長いといったものもありました。Cloud Deploy 単独なら API を蹴って 1 分以内にロールアウト完了といった未来が見えてきます。また、成果物のテストとビルドは本質的には main ブランチで 1 度だけに変わります。
振り返ると、いまあるブランチ戦略は “CI で” 複数環境へデプロイすることを前提としたものになっていないでしょうか?CI と CD の分離によって選択肢が広がった今、そもそもどのような形でデプロイするのが理想なのかを考えていただくとよさそうです。
Cloud Deploy の成熟度
すでに Argo CD などをお使いの方からすると、現時点での Cloud Deploy がいわゆる Weaveworks 社の提唱する GitOps ベースではないことが気になるかもしれません。その点は今後の Cloud Deploy の機能追加なども踏まえ・・ぜひご意見、ご相談ください。
また CI と分離されることで不安な面もあるかと思います。今日は踏み込みませんが、実は Slack などへの通知 や デプロイ後の自動テスト は現時点でもすでに実装方法が提供されています。安心してお試しください!
ハンズオン
CI に GitHub Actions を使ったチュートリアルが 3 つあります。
Cloud Deploy をさっと試すなら上の 2 つのいずれか、もしお時間許せば以下画像でいう “1. 以下をクリックし、Cloud Shell 環境を起動してください” から始まる 3 つ目をお試しください。Skaffold だけでも便利な Kubernetes 開発が、Cloud Code と組み合わせるとさらに便利な様子をあわせてご確認いただけます!
“Kustomize で環境差異を管理する” 例
1 つ目のハンズオンについて、少し解説します。
手順 1 ~ 3 で、まずこのハンズオンは GitHub Actions を前提にしているため、それが利用できるリポジトリ作成し、そこに
をダウンロードしてきています。このチュートリアルでは、k8s リソースの環境差異は Kustomize で差分管理しています。base をベースに、overlays で環境別の差分を保持しており、Skaffold 側では profile として環境ごとのフォルダを指定しています。
手順 4 では Cloud の以下のリソースを作ります。
- デプロイ先の GKE クラスタ
- コンテナのイメージを管理する Artifact Registry リポジトリ
- GitHub に権限を渡すための IAM サービスアカウント (SA)
手順 5 では GitHub リポジトリの Secrets に Google Cloud のプロジェクト ID と、手順 4 で作った SA の JSON 鍵を登録します。よりセキュアにしたい場合はこちらの OSS の利用をご検討ください。
手順 6 で Cloud Deploy のパイプラインを作成、
そして 手順 7 と 8。手順 3 までで用意したコンテンツを git push
することで、Cloud Deploy による リリースの作成 と dev 環境へのデプロイ が実行されます。Actions の定義例は release.yaml に書かれたこちら、実際の流れは比較的直線的で、こんな感じです。
手順 9 では プロモーション、つまり dev 環境にデプロイされたリリースを、そのまま prod 環境へデプロイする設定となっています。Actions の定義例は promotion.yaml のこちらです。ただ、そもそもこれは GitHub を通す理由は弱いので、リードタイムを考えれば下の図でいう管理者相当の方の Approve のみでプロモーションされるよう、ChatOps などを用意してもいいかもしれません。
まとめ
Cloud Deploy は継続的デリバリーだけかと思いきや、ローカル環境をも考慮して製品が設計されているのは感じていただけましたでしょうか。
- Skaffold を使うことでビルドとデプロイを抽象化できる
- CI では本来不要なテストやビルドの時間・費用が削減できる
- CD 側は極力、同一の成果物を展開する仕組みがある
- 結果 CI / CD のプロセス全体を見直す価値はあるかもしれない
これを機に、ぜひみなさんの理想もお聞かせください。
よき継続的デリバリーライフを〜