Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
大規模レガシーテストを 倒すための CI基盤の作り方 / #CICD2023
Search
KONDO Uchio
March 20, 2023
Technology
5
2.3k
大規模レガシーテストを 倒すための CI基盤の作り方 / #CICD2023
@ CI/CD Conference 2023
https://event.cloudnativedays.jp/cicd2023/talks/1773
KONDO Uchio
March 20, 2023
Tweet
Share
More Decks by KONDO Uchio
See All by KONDO Uchio
Ruby x BPF in Action / RubyKaigi 2022
udzura
0
200
Narrative of Ruby & Rust
udzura
0
180
開発者生産性指標の可視化 / pepabo-four-keys
udzura
3
1.6k
Talk of RBS
udzura
0
400
Re: みなさん最近どうですか? / FGN tech meetup in 2021
udzura
0
710
Dockerとやわらかい仮想化 - ProSec-IT/SECKUN 2021 edition -
udzura
2
680
Device access filtering in cgroup v2
udzura
1
780
"Story of Rucy" on RubyKaigi takeout 2021
udzura
0
730
生産性を可視化したい! / SUZURI's four keys
udzura
11
5.3k
Other Decks in Technology
See All in Technology
TSKaigi 2024 の登壇から広がったコミュニティ活動について
tsukuha
0
160
How to be an AWS Community Builder | 君もAWS Community Builderになろう!〜2024 冬 CB募集直前対策編?!〜
coosuke
PRO
2
2.8k
GitHub Copilot のテクニック集/GitHub Copilot Techniques
rayuron
23
11k
Postman と API セキュリティ / Postman and API Security
yokawasa
0
200
生成AIをより賢く エンジニアのための RAG入門 - Oracle AI Jam Session #20
kutsushitaneko
4
210
権威ドキュメントで振り返る2024 #年忘れセキュリティ2024
hirotomotaguchi
2
730
どちらを使う?GitHub or Azure DevOps Ver. 24H2
kkamegawa
0
600
サービスでLLMを採用したばっかりに振り回され続けたこの一年のあれやこれや
segavvy
2
360
5分でわかるDuckDB
chanyou0311
10
3.2k
開発生産性向上! 育成を「改善」と捉えるエンジニア育成戦略
shoota
1
230
LINE Developersプロダクト(LIFF/LINE Login)におけるフロントエンド開発
lycorptech_jp
PRO
0
120
NilAway による静的解析で「10 億ドル」を節約する #kyotogo / Kyoto Go 56th
ytaka23
3
370
Featured
See All Featured
Practical Orchestrator
shlominoach
186
10k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.1k
The Art of Programming - Codeland 2020
erikaheidi
53
13k
Building Better People: How to give real-time feedback that sticks.
wjessup
365
19k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
A Tale of Four Properties
chriscoyier
157
23k
Scaling GitHub
holman
458
140k
GitHub's CSS Performance
jonrohan
1030
460k
KATA
mclloyd
29
14k
Building Your Own Lightsaber
phodgson
103
6.1k
No one is an island. Learnings from fostering a developers community.
thoeni
19
3k
Automating Front-end Workflow
addyosmani
1366
200k
Transcript
Uchio Kondo @ Mirrativ, Inc. 大規模レガシーテストを 倒すための CI基盤の作り方 CI/CD
Conference 2023 @ Shinbashi
株式会社ミラティブ インフラ・ストリーミングチーム 2022/5 〜株式会社ミラティブ インフラ、ミドルウェア、社内ツールなどの 開発と運用をしている Ruby育ち、現在はGopher クラウドネイティブ技術の傍ら tcpdumpとstraceも好き Twitter/GitHub
@udzura 近藤宇智朗
ミラティブについて • 「わかりあう願いをつなごう」をミッションに、 ゲーム配信プラットフォーム「Mirrativ(ミラティブ)」を開発・運営 • スマホ一つで簡単ゲーム配信+アバター(エモモ)作成ができる • ライブゲーム開発に積極投資中! ライブゲーミングについて: https://prtimes.jp/main/html/rd/p/000000074.000033025.html
ミラティブの技術スタック • ライブ配信+アバター(Unity)+ゲームという感じで、 スタートアップの中でもかなり変わったことができるかも
https://speakerdeck.com/hr_team/engineers-handbook 大事なお知らせ • インフラ/ ストリーミング/ バックエンド基盤/ ライブゲーム開発 • Go、Google Cloudユー
ザーに近い開発に 興味のある方歓迎!
アジェンダ 今日お話しすること • ミラティブにおける CI • Google Cloud + Cloud
Buildを選んだ理由 • Cloud Build を使う上での課題と対応実装 ◦ GitHub との連携 ◦ skip ciの罠の回避 ◦ 大規模なテスト移行に際し挑戦したこと、他 • まとめ ◦ CI基盤を作った上での学び ◦ ここでも推測するな、計測せよ
ミラティブにおける CI
前提: ミラティブの歴史 意外とコードに歴史がある ・開発のスタートは2015年 ・開発の当初は Perl をベースに構築 ・元々あった別の配信サービスを土台になるべく高速にリリースした ・その後: サービスや人員の拡大とともに、Goの割合を増やす
ミラティブにおけるCI 今回のスコープ=アプリケーションサーバのチームのCI 定期実行するもの: ・☑ Go のテスト ・☑ E2E テスト ・☑
Perl のテスト(prove) ・☑ Lint (Go, perlcritic, YAML諸々) ・☑ フロントエンド系 (assetsのビルド) リリース時に実行するもの: ・☑ イメージ作成+GitHub Release
CI/CDに求められていること ・色々な言語/目的があるがいい感じにCIしたい ・ある程度汎用的かつ、カスタマイズできて欲しい ・たくさんあるテストケースをいい感じに回したい ・特にPerlのテスト(prove)がたくさんある ・Goなどもテストは多いが、proveは以下の特徴があった 1) 並列実行が簡単でない 2) e2e
相当のテストも多く複雑
Cloud Build を選んだ背景
ここまでの話に加えての課題 プラットフォームをまとめたい話 ・ミラティブでは色々な経緯で様々なSaaS、プラットフォームを利用 ・無論有用なものはそのまま使うが、そうは言っても統一できるものはしたい ・統一の目的については後述 ・今回の場合、インフラ全般を動かしているところ(Google Cloud)と CIで利用しているサービスが異なっていた そのCIサービスのコスト面+ ミラティブの事情で移行の話に
プラットフォームを統一したい 綺麗にまとめたい ・利用をある程度集約させるメリット ・各所にアカウントが分散する管理コストを下げる ・一定以上のボリュームを出したい ・相互連携やレイテンシ、通信費の問題を解決しやすくなる ・特に、ストレージの通信量問題 ・e.g. Google Cloudの場合、Container
Registory(GCS)と サービス実行リージョンを両方US multi regionにすると 通信が無料になる
そもそも、Cloud Buildとは? 意外と知られていない...ような ・Google Cloudのマネージドなビルド環境 ・基本機能 ・GitHub/Gitlabなどソースコードリポジトリとの連携 ・pushやP/Rに応じたビルド ・Pub/Sub を受け取ってのビルド
・イメージやアーティファクトのpush ・Cloud Function/Runのデプロイの内部(Buildpack)も実はこれ
CI基盤にCloud Buildを選んだ理由 CIもサーバレスでいこう ・例えば Jenkins on Compute、Tekton on GKE のような選択肢もあるが...
・今回はCloud Buildを軸に構築した: ・実行基盤の管理はマネージドにしたい ・細かい機能(トリガー、GitHub checksの更新等)を任せる ・従量課金で実行したい
Cloud Build、内部的には... Google Cloudは組み合わせ ・内部的には、どうやら ・Compute Engineで特定のサイズのインスタンスを立ち上げ ・内部でDocker、その他デーモンをいい感じに立ち上げ ・step定義に応じてジョブをコンテナとして実行 ・となっている。したがってdockerでホストのnamespaceに
アタッチすると色々見えたりする。 ・実質Compute Engineの時間貸し(?)
具体的な課題と実装の話
1) GitHubとの連携周り
GitHub との連携上の課題 ・前提として、開発はGitHub (Enterprise Cloud) ・CBはGitHub Actionのように最初からトークンを 裏で発行してくれるわけではない ・(特にGo)複数のプライベートモジュールにアクセスできる権限が トークンに欲しい
・上記のような要件を解決するには...
A. GitHub App を使う https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-an-installation-access-token-for-a-github-app
GitHub App でのトークン発行の流れ JWTを 作ってサイン JWTで APIにアクセス Permissionなど 指定可能
Cloud Functionを最初に叩いて発行 ・Cloud Functionを経由してトークンを発行する 🤖 Function 起動 Secret Key->JWT ->
Token API Token 発行 出力 保存して その後の stepで利用 Cloud Build Cloud Functions GitHub App
GitHub App でのトークン発行後 ・Goのプロジェクトの場合、以下の感じで url.*insteadOf を定義すると そのまま `go get/go mod
download` ができて便利 ・チェックアウトはもちろん、Permissionsを適切に設定して 例えばreviewdogのトークンにも使える
2) “skip ci” の扱い
CDを動かし始めて出てきた課題 ・アプリケーションサーバのイメージビルド+pushのジョブを 別のプラットフォームからCloud Buildに移行した ・イメージビルドは特定の tag を push したら動くようになっていた ・「なんか動いてない時があるみたいなんですけど」
・そんな... 事実を受け止め調査してみる スムーズに動き始めているように見えたが...
原因: skip ci の際の挙動に問題が ・コミットなどに `skip ci` の文字列が含まれていると、 Cloud Buildのトリガーが走らない...
> [skip ci] または [ci skip] を commit メッセージに追加すると、ビルドは呼び出されません。 ・運用上あえてskip ciにしてるコミットがあった(マスタだけ更新等) →そのコミットがデプロイ対象の場合、tag pushしても動かない 普通は問題ないけどたまに困るやつ https://cloud.google.com/build/docs/automating-builds/create-manage-triggers?hl=ja#skipping_a_build_trigger
回避策: Cloud BuildのPub/Subトリガー ・これを使うと、コミットの内容に関係なくトリガーを走らせることができる 💻 リリース作成 = Tag Push Webhook
で Push eventを 送る Cloud Function で 受け取って Pub/Subに投げる Cloud Build TriggerでPub/Subを 選択 Cloud Pub/Subは本当に便利
checks を上書きすることもできる ・GitHub Appに checks: write のPermissionを付与する ・GitHub PR
→ Webhook → Cloud Function → Checks API でできる Webhook で PRのeventを 送る 1) GitHub Appから トークン発行 2) Checks API経由で更 新
3) 大規模テストの課題向き合い
課題: Perl のテスト (prove) 移行 ・最初に説明した通り、創業当初からあるコード+テスト ・むしろテストはしっかり書いている。しかしどうしても: ・古くなる ・多くなる ←
特にこれが大変 ・だが、テストがある程度サービスを守ってくれたことも事実。 どうにかして現実的に運用し続ける方法を考えたい ただレガシーと片付けるのではなく向き合う
課題を一歩一歩進める ・そもそもたくさんあるテストが現実的な時間で終わるのか? → どうにかしてたくさんのテストを実行する仕組みを考える ・まずは一通り走る状態にして、チューニングしようと考えた → 後述するが、ややアバウトすぎるアプローチではあったかも
たくさんのテスト実行の方法 ・単純にトリガーを分ける?(それで対応したものもある) → 今回はテストケースが多すぎるので難しい... checks が溢れかえるのは開発者体験が... ・こういう作戦 ・トリガーからPub/Sub Topicをワーカ数発行する ・ワーカでテスト実行
・ワーカの実行結果もPub/Subで取得、集計して表示/成功失敗
具体的な流れ PRの 作成 PRトリガー の起動 ソースコードを 一度GCSに固める テスト対象ファイルを Payloadに含めて Topic
Publish Topicの数だけ テストジョブが起動 コード、実行イメージを GCSから落とす ……
具体的な流れ(テスト終了後) check 更新 テスト結果のTopicを Subscribeして 結果を待つ→ 集計、成功失敗判定 テストの結果は
勝手にPub/Subに 流れる (cloud-builds) ✅ ✅ ❌
ちなみに: 通知もPub/Subで ・Cloud Buildのジョブのキュー、開始、終了など、全てのイベントはcloud-builds というト ピックにpublishされる
・Cloud Functionでsubscribeして、中身を検査して通知したい時だけ Slackに送る、ということをしている
ワーカー作戦のまとめ ・ワーカーをたくさん作る→一回のテストは短くなる→全体は短くなる たくさんあるテストをなんとか回すことはできるようになった けれど... 新たな課題が ・並行しすぎることによる様々なオーバーヘッドが発生した =不要にBuild時間を使っているようだ ・実際、何度か走らせてみるとコストがかかりすぎる →ちゃんと必要十分な計算リソースを割り当てたい なんとか全件走るようになったが
どれくらいのコストが適切か見積もる ・元のプラットフォームのテストの所要時間を把握、分析する ・Cloud Buildで同等のテストを実行できるようにする ・それらを比べる ・パフォーマンス劣化をしていないか ・劣化している場合何がボトルネックか ・現実的なコストで収められるか ・その上で、ボトルネックは解消するか、他に縮める方法がないかを調べる
1) インスタンス、並行数を決定 ・何も考えずにたくさん詰め込むと遅くなる ・所要時間もだが、LAなどリソースのメトリックも見て決定 1分程度の劣化で収まり、 LA1が5を恒久的に超えない(8コアで) 1 step 2 steps
3 steps 4 steps 5 steps 6 steps 所要時間 4m42s 5m10s 5m53s 6m06s 6m59s タイムアウト 増分 +28s +43s +13s +53s LA1 3 ~ 4 4 ~ 5.5 4 ~ 5 5 ~ 6 6 ~ 7.5 メモリ不足 ※ n1-highcpu-8 で同じテストケースで計測
2) CPUの割り当てを最適化 ・テスト実行には当然MySQL、memcachedなどいろいろなサービスが サイドカーで立ち上がる ・なのでperlのプロセスだけでなく プラスアルファでそこそこの数のプロセスが立ち上がってくる ・色々試すと、そもそも実行時間自体が安定しない ・なるべく少ないCPUでたくさんのプロセスを回そうとする ・そうするといい感じにCPUが割り当たっていない場合がある? この辺からクラウドを使い倒してる感じに
CPUの割り当て、どう最適化? ・dockerのcpuスケジューリング周りのオプションを調整した ・値をいくつか変えり、オプションを比べた感じ → MySQLに優先してCPUが割り当たるようにすると時間が改善 コンテナが使うCPUを固定する(pinning)
コンテナのCPU割り当てのweightを上げる (デフォルト = 1024)
CPU周りを調整した比較 設定なし CPU cpuset CPU shares #1 7m56s 7m33s 7m21s
#2 9m14s 7m24s 7m36s #3 7m24s 7m08s 7m37s AVG. 8m11s 7m21s 7m31s ※ n1-highcpu-8 で同じテストケース/3 stepsで計測 ※ cpuset = MySQL に3コア、 perl テストに 5コア ※ shares = MySQL は shares=4096、perlは shares=2048
3) ホストネットワークの利用 ・cloud buildはデフォルト、 cloudbuildという内部ネットワークにアタッチしてstepを起動 ・MySQLなど追加サービスを利用する場合は、docker composeなどで cloudbuildにアタッチさせて起動 ・vethという仮想ネットワークを作るので 少しだけオーバーヘッドがある
→ --network=host で比べてみる ・普通は気にならないが MySQLのボトルネックを無くしたら 少し差が出た ※ n1-highcpu-8 で同じテストケースで計測 net=host net=cloudbuild #1 7m21s 7m52s #2 7m36s 7m37s #3 7m37s 8m28s AVG. 7m31s 7m59s
現在の進捗 定期実行するもの: ・✅ Go のテスト ・✅ E2E テスト ・🚧 Perl
のテスト(prove) ・✅ Lint (Go, perlcritic, YAML諸々) ・✅ フロントエンド系 (assetsのビルド) リリース時に実行するもの: ・✅ イメージ作成+GitHub Release Perl はもう少し開発基盤チームと チューニングしてから移行予定
まとめ+学びなど
Cloud Build 導入でやったこと ・GitHub といい感じに連携できるようにする GitHub App と Cloud Functions
を使い倒す ・skip ciの際の挙動の罠を上手に回避する ・数の多いテストを回す仕組みを作る ・色々とチューニングをして、コストを最適化する もちろんテスト時間の短縮は開発生産性にダイレクトに効く 今日お話ししたことのまとめ
学び: Cloud Build の扱い方 CIのための一種のフレームワーク ・Cloud Buildには、ある程度最低限のものはあるが、One-Size-Fits-All に 全て揃っているとは考えるべきではない ・逆に、周辺のサービスを小さく組み合わせることで色々なことができる
・Cloud Functions ・Cloud Pub/Sub ・Cloud Run, GCS... ・アプリケーション基盤を含めた大きな観点で組み合わせる
学び2: 推測するな、計測せよ 基本だが難しい ・初め、とにかく並行化して速くすればいいと考えて、ジョブを大量に実行するような アーキテクチャにしていた ・結果的にコストが余計にかかりすぎることに→何のための移行? ・現状を把握する+現在のボトルネックを見つけ出す ・それがシステムの改善にとって一番重要 ・そして、考えられるチューニングポイントは一通り試すべき ・クラウドネイティブだからこそ計算機と仲良く
https://speakerdeck.com/hr_team/engineers-handbook 大事なお知らせ(2) • インフラ/ ストリーミング/ バックエンド基盤/ ライブゲーム開発 • Go、Google Cloudユー
ザーに近い開発に 興味のある方歓迎!
https://tech.mirrativ.stream/ テックブログも見てください
ご清聴ありがとうございました