CNDT 2023 で紹介できなかったこぼれ話 ~ その自動化めんどくさいって思ってからでいいや ~
はじめに
この記事は 株式会社ビットキー Advent Calendar 2023 12日目の記事です。
本記事は CloudNative Days Tokyo 2023 で紹介した 「リリース速度10倍を実現したビットキー流DevOps - Argo CD との付き合い方 -」 のうち GitHub Actions を用いた実装に主眼を置いてご説明しようと思います。
https://event.cloudnativedays.jp/cndt2023/talks/2021
登壇資料はこちらです!
CNDT 2023 ではしれっと「ゼロから構築し破棄する Argo CD 環境」なんてお話をしましたがこの環境ができるまでにも紆余曲折がありました。(そうでもないかもしれない。) その環境が出来上がるまでのお話をします。
前提情報
この「ゼロから構築し破棄する Argo CD 環境」を実施しているのはビットキーにおけるプラットフォームチーム(通称BKP)です。 BKPはビットキーに関わるヒト・モノ・コトを扱うシステムです。 ほかにも顔情報であったりメッセージを配信するマイクロサービスも管理しています。 これらの機能は Google Kubenetes Engine (GKE) にデプロイし稼働しています。 Kubernetes へのアプリケーションのデプロイには Argo CD を活用しています。 BKPでは本番環境へのリリース前に本番同等の環境(本番ミラー環境)にて最終検証を実施します。 その際、こちらの環境をゼロから構築しているというのが「ゼロから構築し破棄する Argo CD 環境」のお話となります。
なぜ構築・整備した?
大きなエネルギーとなったのは「めんどくさい」という気持ちです。 Argo CD を導入した直後から本番ミラー環境はゼロから構築する方針になっていました。しかし当初はほぼ手動でこの環境を毎度構築していました。 この作業が圧倒的に、本当にめんどくさかった。 ドキュメントもほぼなく、Argo CD についてキャッチアップしたときの資料が手順書みたいな形で存在していました。 もう一度言います。これが本当にめんどくさいかった。うん。めんどくさかった。
どのように解決した?
GitHub Actions でピタゴラスイッチを頑張って組んだ。ただそれだけです。 いやいや、それまでの道のりが知りたいのよ。ごめんなさい。 ここから初期段階の仕組みから現在稼働している仕組みまでの変遷をご紹介していきます。
ちょっとその前に前提知識を共有
ピタゴラスイッチを組む上で重要なのは「ワークフローのトリガー」です。
https://docs.github.com/en/actions/using-workflows/about-workflows#triggering-a-workflow
ワークフロートリガーは以下の4つが存在します。
- ワークフローのリポジトリ内で発生するイベント 以下「イベント」と記載
- GitHub の外部で発生し、GitHub で repository_dispatch イベントをトリガーするイベント 以下「ディスパッチ」と記載
- スケジュールされた時刻 以下「クーロン」と記載
- マニュアル(手動実行) 以下「手動」と記載
ピタゴラスイッチを組む際はこれらのワークフロートリガーを組み合わせることになります。
version 0.0
Argo CD を導入したばかりの本番ミラー環境構築は以下のような手順でした。
- なにかしらの本番環境用のアプリケーション管理 manifest の yaml に変更があったら起動
- PR作成「イベント」にて起動
- 起動した CI にて Argo CD をインストール
- ここまでで Argo CD の GUI にログインできる状態
- E2E を実行 (???)
graph LR
um[1. update manifest]
ai[2. argocd install]
ee[3. execute e2e]
um-->ai-->ee
このとき私は大きなミスを犯しました。この構築は初回構築以降ずっと失敗します。 なぜか。E2Eテストが動かないのです。 というのも、CIを構築しE2Eテストを動作確認しているときは Argo CD によるアプリケーションデプロイが終わった前提で作っていました。(Argo CD GUI によるポチポチインストールが完了した状態でずっと CI を調整してました。) E2Eテスト動かないけどまあいいや。という感じでしばらくは CI 上でミラー環境に Argo CD をインストールしあとは GUI でログインしたポチポチ構築を続けていました。
ただ、これがまあめんどくさかった & 毎度実行する意味のないE2Eテストの失敗を見届けることの無意味さに嫌気がさしてきました。
改善しよう …
どういうきっかけで気づいたかは記憶の彼方へと消え去ってしまいましたがあるとき Argo CD CLI のドキュメントを見つけました。(たぶん Argo CD GUI へのログインスクリプトを整備しているときかな … ) 眺めているとこれまで GUI でポチポチしていたことが CLI でできそうでした。お、じゃあ検証してみよう。
Argo CD を検証だ!
まずは検証です。BKPチームには20%ルールというものがあります。 この時間を使って検証しました。 ただ、 GKE をこのために構築するのもめんどくさかったのでローカル環境で kind を構築して検証しました。 Argo CDのドキュメントを何気なく読んでいたらなんかいろいろコマンドあるじゃんって気づきました。 あれ、なんか自動化できそうじゃね? それが始まりです。
以下のリポジトリに私が検証していたサンドボックスを置いておきます。
https://github.com/otakakot/playground-argocd
Argo CD はいけそう、次は GitHub Actions だ!
これも以下のサンドボックスを使っていろいろ動作確認をしています。
https://github.com/otakakot/playground-github-actions
ゼロから環境構築するのでミスったら最初っからやり直ししなきゃです。 事前に動作確認できるものはしておきましょう。安心感を手に入れられます。
act というローカル環境で GitHub Actions を動かせるものもあるみたいですがそこまではしていないです。(あ、これ Go で実装されてるんだ。あとで見てみよ。)
version 1.0
いろいろ検証していけそうだなってなったので本番ミラー環境構築の自動化を試みました。 version 1.0 では以下のようなフローで構築しました。
- terraform apply にて Google Cloud へとデプロイ
- 「クーロン」で起動
- Argo CD を Kubernetes へインストール
- 「ディスパッチ」で起動
- リリース用タグを作成
- 「クーロン」で起動
- リリース用PRを作成
- 「ディスパッチ」で起動
- アプリケーションコンテナをビルド&プッシュ
- タグ作成「イベント」で起動
- リリース用タグへと manifest を更新
- 「ディスパッチ」で起動
- Argo CD にてアプリケーションをデプロイ
- 「ディスパッチ」で起動
graph LR
ta[1. terraform apply]
sa[2. setup argocd]
ct[3. create tag]
cp[4. create pr]
bp[5. container build & push]
up[6. update manifest]
aa[7. argocd apply]
ta-->sa
ct-->cp
ct-->bp
bp-->up
cp-->aa
ポイント
version 0 では Argo CD をインストールして終了でしたが Argo CD にてアプリケーションをデプロイするところまで調整しました。。
今回は便宜上アプリケーションコンテナをビルド&プッシュを実施する CI は一つしか記載していませんが、実際には複数存在します。つまり、複数のリポジトリから manifest 更新の「ディスパッチ」が発生します。
version 0 の段階では「PRがあれば作成して更新、なければ更新だけする」という処理にしていましたがコンフリクトなどが発生したり、同時にPRを作成しに行って片方が失敗したりして安定しませんでした。
manifest の更新を確実に実施するために4. リリース用PRを作成する処理を挟んでいます。
GitHub の仕様上、差分がないと PR を作成することはできません。そこでリリースタグを README.md に埋め込んで差分を作成しています
version 2.0
「リリースノート前日共有のほうがよくない?」
見直すきっかけとなった助言です。
なんで version 1.0 のようなフローにしてたかは忘れてしまいましたが、あのときはこれが最適だと思っていました … (特に create pr から argocd apply の流れ …)
リリース当日にリリースノートを作成し共有しこのあとすぐとリリースするので見てください。は急すぎました。 リリースに対して懸念点があった場合には我々 BKP チームもドタバタします。お互いにとってよくない状況でした。 なのでリリースノートは前日に共有するフローに変えました。 これが非常によかったです。 リリース PR を作成する流れと Argo CD を構築する流れの2つにきれいに分解することができました。
graph LR
ct[1. create tag]
cp[2. create pr]
bp[3. container build & push]
up[4. update pr]
ta[5. terraform apply]
sa[6. setup argocd and argocd apply & sync]
ct-->bp
ct-->cp
bp-->up
ta-->sa
ポイント
変更したポイントとしては Argo CD をインストールした直後 Argo CD によるアプリケーションデプロイを実行した点です。
version 1.0 ではディスパッチで呼び出す際に監視対象のブランチを指定していたのですが、今回は以下のようなコマンドにてリリース用ブランチもしくは main ブランチを指定するようにしています。
BRANCH=$(gh pr list --json title,url,createdAt,headRefName | jq '.[] | select(.headRefName | contains("production-release"))' | jq -s . | jq 'max_by(.createdAt) | .headRefName')
branch=${BRANCH}
if [ "${branch}" = "null" ]; then
branch="main"
fi
cat argocd/apps/*.yaml | ENVIRONMENT=production-mirror BRANCH=${branch} envsubst '${ENVIRONMENT}','${BRANCH}' | kubectl apply -f-
version 2.1 に向けて
次の目標は E2E テストの自動化です。本番ミラー環境構築は自動化できていますが、本番ミラー環境検証は自動化できていません。
やりたいと思ってはいるのですが、E2Eテストの実行は正直そんなにめんどくさくないです。ローカルPCからコマンド実行するだけなので。 また、やるためにはいくつか越えなければいけない課題がまだあります。 それはE2Eテストの実行タイミングを握ることです。
- Ingress が Healthy になるまで時間がかかります。
- 効率は悪いけどCIでずっと待機する
- (未検証) Argo CD のトリガーを使って通知を飛ばす
- Ingress に ジョブをくっつけているのですがこいつがコマンドでは成功せずGUIでリトライしています。
- 成功したかどうかをまだ正確に把握できていないので要調整
そこまで「めんどくさい」のパワーが溜まっていないのでしばらくは今のままの運用でいいかなって感じです。
おわりに
結果的にリリース作業にかかる時間も短縮することができましたが、きっかけは「めんどくさい」と思う気持ちでした。 ほんとうにその自動化必要ですか? いますぐ必要ですが? そのタスクのスコープに自動化まで入れる必要ありますか? 一旦手動でやってみましょう。 一旦手動で定期的に実施しましょう。 だんだんとめんどくさくなってきます。 そうしたら実装に対するモチベーション爆上がりです。
13日目の 株式会社ビットキー Advent Calendar 2023 は @undesicimo が担当します!