本資料は、2022年11月に開催された『Jenkins Day Japan 2022』における「モンスターストライクとJenkins」の講演資料です。
モンスターストライク とJenkins2022/11/2モンスト事業本部 モンストサーバチーム松原 信忠
View Slide
モンストサーバチーム2
サーバーチームはモンストのバックエンドの「開発」と「運用」の両方を行う開発環境や開発を支援するツールも開発・運用している(Jenkinsもその一つ)モンストの開発に関わるチーム3
リポジトリに応じてジョブが何種類かある(以下に一部抜粋)1. モンストのバックエンド本体のリポジトリテストの実行(Ruby)ソースコードのデプロイ(開発環境のみ)マスターデータのインポート2. 本体以外の周辺ツールをまとめたモノレポジトリテストの実行(主にGo)Goの依存パッケージのVendoring独自 apt パッケージのビルドとリリース3. Google Cloud DNS や AWS Security Group などを IaC しているリポジトリ設定の適用サーバチームでの Jenkins 用途4
リポジトリに応じてジョブが何種類かある(以下に一部抜粋)1. モンストのバックエンド本体のリポジトリテストの実行(Ruby)ソースコードのデプロイ(開発環境のみ)マスターデータのインポート2. 本体以外の周辺ツールをまとめたモノレポジトリテストの実行(主にGo)Goの依存パッケージのVendoring独自 apt パッケージのビルドとリリース3. Google Cloud DNS や AWS Security Group などを IaC しているリポジトリ設定の適用サーバチームでの Jenkins 用途5
リポジトリに応じてジョブが何種類かある(以下に一部抜粋)1. モンストのバックエンド本体のリポジトリテストの実行(Ruby)ソースコードのデプロイ(開発環境のみ)マスターデータのインポート2. 本体以外の周辺ツールをまとめたモノレポジトリテストの実行(主にGo)Goの依存パッケージのVendoring独自 apt パッケージのビルドとリリース3. Google Cloud DNS や AWS Security Group などを IaC しているリポジトリ設定の適用サーバチームでの Jenkins 用途6
リポジトリに応じてジョブが何種類かある(以下に一部抜粋)1. モンストのバックエンド本体のリポジトリテストの実行(Ruby)ソースコードのデプロイ(開発環境のみ)マスターデータのインポート2. 本体以外の周辺ツールをまとめたモノレポジトリテストの実行(主にGo)Goの依存パッケージのVendoring独自 apt パッケージのビルドとリリース3. Google Cloud DNS や AWS Security Group などを IaC しているリポジトリ設定の適用サーバチームでの Jenkins 用途7
サーバチームでの Jenkins 構成8
Jenkins コントローラーは GKE 上で動かしているJenkins 公式の Helm Chart を利用しているサーバチームでの Jenkins 構成https://github.com/jenkinsci/helm-charts9
Jenkins へのアクセスは Webhook も含めて自作ゼロトラストプロキシを介すjwt-auth-plugin を使ってゼロトラストプロキシを介してきたかを確認サーバチームでの Jenkins 構成https://github.com/jenkinsci/jwt-auth-plugin10
Jenkins エージェントは GCE で動かしているPacker でベースイメージを作り、Ansible でプロビジョニングするサーバチームでの Jenkins 構成11
生じた課題と解決方法12
モンストの機能開発では「QA期間」というのがあるそのため、QA期間まで(締め日)に機能をある程度完成させる必要がある締め日にコミットが集中して、テスト用のジョブが大量に発生して滞留するエージェントを一時的に足せば良いが、その都度行うのは大変課題:ジョブが滞留する時期がある13
Go製・GKE上で動作させている当時、内定者アルバイトで来てた方にフルスクラッチしてもらった解決:エージェントのオートスケーラーの開発14
(1) 現在の Jenkins エージェントの状態を API から取得エージェントのラベル毎にオートスケールのための設定を分けている解決:エージェントのオートスケーラーの開発15
(2) 閾値以上のエージェントがジョブを実行している場合はエージェントを追加エージェントは GCE のインスタンステンプレートから生成解決:エージェントのオートスケーラーの開発16
(3) 追加したエージェントがジョブを実行していない場合はエージェントを削除これらを数分おきに繰り返す解決:エージェントのオートスケーラーの開発17
Jenkins はサーバーチームのメンバー以外も使っているマスターデータのインポート(実行は Slack Bot から)マスターデータの静的解析(GitHub Webhook から)マスターデータの翻訳(海外版)しかしWeb UIからできる設定を、サーバーメンバー以外にはやってほしくない課題:Jenkins の細かいアクセス制御をしたい18
モンスト開発では自作のゼロトラストプロキシを運用していたので、これを利用するGo製・GKE上で動作させている会社の Google アカウントで認証・ユーザーの識別を行うユーザー毎にロールを与えて、ロール毎にアクセスできる Webサービスを制限解決:自作ゼロトラストプロキシによる制御19
Webサービスのパスや Read Only かどうかの制御も可能GitHub や Slack からのアクセスを許可するかどうかも制御可能社員以外はクライアント証明書を渡してアクセス制限をかけることも可能サーバーチームのロールでは「Read/Write」にし、それ以外では Read Only にした解決:自作ゼロトラストプロキシによる制御20
Jenkins では独自 apt パッケージのビルドとリリースをしており、これらのジョブは別々になっているビルド:PRがマージされた時点で差分に応じて自動実行リリース:サーバーにプロビジョニングをかけてるときには避けたいので手動実行しかし、欲を出すとビルドの終わった時点で「リリースして良いか」を Slack に投稿して手動実行を促してほしい(いわゆる「Manual Approval」みたいなことがしたい)課題:ジョブの後に別のジョブを手動実行したい21
Go製・GKE上で動作する自作 Slack Bot に機能を追加したSlack Bot は GitHub Webhook も受け取れるようになっている解決:Slack Bot でジョブの終了を待つ22
1. 独自 apt パッケージのPRがマージされるのを Slack Bot が検知2. ビルドのジョブが終わるのを Jenkins の Web API を定期的に呼んで待つ3. ビルドが終わったら Slack に通知し Add Reaction を待つ4. Add Reaction されたらリリースのジョブを Jenkins の Web API から実行解決:Slack Bot でジョブの終了を待つ23
Jenkins でクラウドサービスの設定の適用しているため、秘匿情報の管理をしているGoogle Cloud のアクセスキーAWS のアクセスキー(用途やリージョン毎に分けている)しかし、Jenkins の秘匿情報管理で設定できるスコープが「グローバル」と「システム」しか基本的にはなく、リポジトリ毎に設定することができないまた、大量の秘匿情報を何個も登録するのが大変課題:秘匿情報をリポジトリ毎に管理したい24
Amber という OSS を利用するリポジトリには Amber で生成した公開鍵と暗号化した秘匿情報を保存Jenkins には Amber で生成した秘密鍵だけを保存リポジトリと秘密鍵が揃う場合(ジョブ)でだけ、元の秘匿情報を利用できる解決:Amber の導入https://github.com/fpco/amber25
モンストサーバーチームでは Jenkins を自前運用して利用しているテストの実行やデータインポート、IaC の適用などで利用しているコントローラーは GKE 上で動作させて、Helm を使って構成管理エージェントは GCE 上で動作させて、Packer と Ansible を使って構成管理生じた課題は主に、自作ツールやOSSを利用して Jenkins の外から解決しているジョブが時期によって滞留するので、エージェントのオートスケーラーを自作細かいアクセス制御をするために自作ゼロトラストプロキシを利用Slack から Manual Approval をするために Slack Bot を自作リポジトリ毎に秘匿情報を管理するために Amber という OSS を導入まとめ26