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
AWS re:Invent 2024で発表された コードを書く開発者向け機能について
maruto
0
190
C++26 エラー性動作
faithandbrave
2
740
kargoの魅力について伝える
magisystem0408
0
210
マルチプロダクト開発の現場でAWS Security Hubを1年以上運用して得た教訓
muziyoshiz
3
2.3k
UI State設計とテスト方針
rmakiyama
2
600
社外コミュニティで学び社内に活かす共に学ぶプロジェクトの実践/backlogworld2024
nishiuma
0
260
podman_update_2024-12
orimanabu
1
270
watsonx.ai Dojo #5 ファインチューニングとInstructLAB
oniak3ibm
PRO
0
170
Wantedly での Datadog 活用事例
bgpat
1
470
Amazon Kendra GenAI Index 登場でどう変わる? 評価から学ぶ最適なRAG構成
naoki_0531
0
110
Oracle Cloudの生成AIサービスって実際どこまで使えるの? エンジニア目線で試してみた
minorun365
PRO
4
280
LINE Developersプロダクト(LIFF/LINE Login)におけるフロントエンド開発
lycorptech_jp
PRO
0
120
Featured
See All Featured
Intergalactic Javascript Robots from Outer Space
tanoku
270
27k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
29
2k
A better future with KSS
kneath
238
17k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
6
520
How to Ace a Technical Interview
jacobian
276
23k
A Modern Web Designer's Workflow
chriscoyier
693
190k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
48
2.2k
GitHub's CSS Performance
jonrohan
1030
460k
Writing Fast Ruby
sferik
628
61k
Statistics for Hackers
jakevdp
796
220k
Rebuilding a faster, lazier Slack
samanthasiow
79
8.7k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
232
17k
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/ テックブログも見てください
ご清聴ありがとうございました