Upgrade to Pro — share decks privately, control downloads, hide ads and more …

大規模レガシーテストを 倒すための CI基盤の作り方 / #CICD2023

大規模レガシーテストを 倒すための CI基盤の作り方 / #CICD2023

KONDO Uchio

March 20, 2023
Tweet

More Decks by KONDO Uchio

Other Decks in Technology

Transcript

  1. Uchio Kondo @ Mirrativ, Inc. 

    大規模レガシーテストを
    倒すための
    CI基盤の作り方
    CI/CD Conference 2023 @ Shinbashi


    View Slide

  2. 株式会社ミラティブ

    インフラ・ストリーミングチーム

    2022/5 〜株式会社ミラティブ

    インフラ、ミドルウェア、社内ツールなどの
    開発と運用をしている

    Ruby育ち、現在はGopher

    クラウドネイティブ技術の傍ら

    tcpdumpとstraceも好き

    Twitter/GitHub @udzura

    近藤宇智朗


    View Slide

  3. ミラティブについて

    ● 「わかりあう願いをつなごう」をミッションに、

    ゲーム配信プラットフォーム「Mirrativ(ミラティブ)」を開発・運営

    ● スマホ一つで簡単ゲーム配信+アバター(エモモ)作成ができる

    ● ライブゲーム開発に積極投資中!

    ライブゲーミングについて: https://prtimes.jp/main/html/rd/p/000000074.000033025.html

    View Slide

  4. ミラティブの技術スタック

    ● ライブ配信+アバター(Unity)+ゲームという感じで、

    スタートアップの中でもかなり変わったことができるかも


    View Slide

  5. https://speakerdeck.com/hr_team/engineers-handbook
    大事なお知らせ

    ● インフラ/

    ストリーミング/

    バックエンド基盤/

    ライブゲーム開発

    ● Go、Google Cloudユー
    ザーに近い開発に

    興味のある方歓迎!


    View Slide

  6. アジェンダ

    今日お話しすること

    ● ミラティブにおける CI

    ● Google Cloud + Cloud Buildを選んだ理由

    ● Cloud Build を使う上での課題と対応実装

    ○ GitHub との連携

    ○ skip ciの罠の回避

    ○ 大規模なテスト移行に際し挑戦したこと、他

    ● まとめ

    ○ CI基盤を作った上での学び

    ○ ここでも推測するな、計測せよ


    View Slide

  7. ミラティブにおける CI


    View Slide

  8. 前提: ミラティブの歴史

    意外とコードに歴史がある

    ・開発のスタートは2015年

    ・開発の当初は Perl をベースに構築

    ・元々あった別の配信サービスを土台になるべく高速にリリースした

    ・その後: サービスや人員の拡大とともに、Goの割合を増やす


    View Slide

  9. ミラティブにおけるCI

    今回のスコープ=アプリケーションサーバのチームのCI

    定期実行するもの:
    ・☑ Go のテスト

    ・☑ E2E テスト

    ・☑ Perl のテスト(prove)

    ・☑ Lint (Go, perlcritic, YAML諸々)

    ・☑ フロントエンド系 (assetsのビルド)

    リリース時に実行するもの:
    ・☑ イメージ作成+GitHub Release


    View Slide

  10. CI/CDに求められていること

    ・色々な言語/目的があるがいい感じにCIしたい

    ・ある程度汎用的かつ、カスタマイズできて欲しい

    ・たくさんあるテストケースをいい感じに回したい

    ・特にPerlのテスト(prove)がたくさんある

    ・Goなどもテストは多いが、proveは以下の特徴があった

    1) 並列実行が簡単でない

    2) e2e 相当のテストも多く複雑


    View Slide

  11. Cloud Build を選んだ背景


    View Slide

  12. ここまでの話に加えての課題

    プラットフォームをまとめたい話

    ・ミラティブでは色々な経緯で様々なSaaS、プラットフォームを利用

    ・無論有用なものはそのまま使うが、そうは言っても統一できるものはしたい

    ・統一の目的については後述

    ・今回の場合、インフラ全般を動かしているところ(Google Cloud)と

    CIで利用しているサービスが異なっていた

    そのCIサービスのコスト面+

    ミラティブの事情で移行の話に


    View Slide

  13. プラットフォームを統一したい

    綺麗にまとめたい

    ・利用をある程度集約させるメリット

    ・各所にアカウントが分散する管理コストを下げる

    ・一定以上のボリュームを出したい

    ・相互連携やレイテンシ、通信費の問題を解決しやすくなる

    ・特に、ストレージの通信量問題

    ・e.g. Google Cloudの場合、Container Registory(GCS)と

     サービス実行リージョンを両方US multi regionにすると

     通信が無料になる


    View Slide

  14. そもそも、Cloud Buildとは?

    意外と知られていない...ような

    ・Google Cloudのマネージドなビルド環境

    ・基本機能

    ・GitHub/Gitlabなどソースコードリポジトリとの連携

    ・pushやP/Rに応じたビルド

    ・Pub/Sub を受け取ってのビルド

    ・イメージやアーティファクトのpush

    ・Cloud Function/Runのデプロイの内部(Buildpack)も実はこれ


    View Slide

  15. CI基盤にCloud Buildを選んだ理由

    CIもサーバレスでいこう

    ・例えば Jenkins on Compute、Tekton on GKE のような選択肢もあるが...

    ・今回はCloud Buildを軸に構築した:

    ・実行基盤の管理はマネージドにしたい

    ・細かい機能(トリガー、GitHub checksの更新等)を任せる

    ・従量課金で実行したい


    View Slide

  16. Cloud Build、内部的には...

    Google Cloudは組み合わせ

    ・内部的には、どうやら

    ・Compute Engineで特定のサイズのインスタンスを立ち上げ

    ・内部でDocker、その他デーモンをいい感じに立ち上げ

    ・step定義に応じてジョブをコンテナとして実行

    ・となっている。したがってdockerでホストのnamespaceに

     アタッチすると色々見えたりする。

    ・実質Compute Engineの時間貸し(?)


    View Slide

  17. 具体的な課題と実装の話


    View Slide

  18. 1) GitHubとの連携周り


    View Slide

  19. GitHub との連携上の課題

    ・前提として、開発はGitHub (Enterprise Cloud)

    ・CBはGitHub Actionのように最初からトークンを

     裏で発行してくれるわけではない

    ・(特にGo)複数のプライベートモジュールにアクセスできる権限が

     トークンに欲しい

    ・上記のような要件を解決するには...


    View Slide

  20. 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

    View Slide

  21. GitHub App でのトークン発行の流れ

    JWTを
    作ってサイン
    JWTで
    APIにアクセス
    Permissionなど
    指定可能

    View Slide

  22. Cloud Functionを最初に叩いて発行

    ・Cloud Functionを経由してトークンを発行する

    🤖



    Function 起動
 Secret Key->JWT

    -> Token API

    Token 発行

    出力

    保存して

    その後の

    stepで利用

    Cloud Build Cloud Functions
    GitHub App

    View Slide

  23. GitHub App でのトークン発行後

    ・Goのプロジェクトの場合、以下の感じで url.*insteadOf を定義すると

     そのまま `go get/go mod download` ができて便利



    ・チェックアウトはもちろん、Permissionsを適切に設定して

     例えばreviewdogのトークンにも使える


    View Slide

  24. 2) “skip ci” の扱い


    View Slide

  25. CDを動かし始めて出てきた課題

    ・アプリケーションサーバのイメージビルド+pushのジョブを

     別のプラットフォームからCloud Buildに移行した

    ・イメージビルドは特定の tag を push したら動くようになっていた

    ・「なんか動いてない時があるみたいなんですけど」

    ・そんな... 事実を受け止め調査してみる

    スムーズに動き始めているように見えたが...


    View Slide

  26. 原因: 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

    View Slide

  27. 回避策: Cloud BuildのPub/Subトリガー

    ・これを使うと、コミットの内容に関係なくトリガーを走らせることができる

    💻
    リリース作成

    = Tag Push

    Webhook で

    Push eventを
    送る

    Cloud Function で
    受け取って

    Pub/Subに投げる

    Cloud Build

    TriggerでPub/Subを
    選択

    Cloud Pub/Subは本当に便利


    View Slide

  28. checks を上書きすることもできる

    ・GitHub Appに checks: write のPermissionを付与する

    ・GitHub PR → Webhook → Cloud Function → Checks API でできる


    Webhook で

    PRのeventを
    送る

    1) GitHub Appから

    トークン発行

    2) Checks API経由で更
    新


    View Slide

  29. 3) 大規模テストの課題向き合い


    View Slide

  30. 課題: Perl のテスト (prove) 移行

    ・最初に説明した通り、創業当初からあるコード+テスト

    ・むしろテストはしっかり書いている。しかしどうしても:

    ・古くなる

    ・多くなる ← 特にこれが大変

    ・だが、テストがある程度サービスを守ってくれたことも事実。

     どうにかして現実的に運用し続ける方法を考えたい

    ただレガシーと片付けるのではなく向き合う


    View Slide

  31. 課題を一歩一歩進める

    ・そもそもたくさんあるテストが現実的な時間で終わるのか?

    → どうにかしてたくさんのテストを実行する仕組みを考える

    ・まずは一通り走る状態にして、チューニングしようと考えた

    → 後述するが、ややアバウトすぎるアプローチではあったかも


    View Slide

  32. たくさんのテスト実行の方法

    ・単純にトリガーを分ける?(それで対応したものもある)

    → 今回はテストケースが多すぎるので難しい...

     checks が溢れかえるのは開発者体験が...

    ・こういう作戦

    ・トリガーからPub/Sub Topicをワーカ数発行する

    ・ワーカでテスト実行

    ・ワーカの実行結果もPub/Subで取得、集計して表示/成功失敗


    View Slide

  33. 具体的な流れ

    PRの

    作成

    PRトリガー

    の起動

    ソースコードを

    一度GCSに固める

    テスト対象ファイルを

    Payloadに含めて

    Topic Publish

    Topicの数だけ

    テストジョブが起動

    コード、実行イメージを
    GCSから落とす

    ……

    View Slide

  34. 具体的な流れ(テスト終了後)

    check

    更新

    テスト結果のTopicを 

    Subscribeして

    結果を待つ→

    集計、成功失敗判定 

    テストの結果は

    勝手にPub/Subに

    流れる

    (cloud-builds)




    View Slide

  35. ちなみに: 通知もPub/Subで

    ・Cloud Buildのジョブのキュー、開始、終了など、全てのイベントはcloud-builds というト
    ピックにpublishされる





    ・Cloud Functionでsubscribeして、中身を検査して通知したい時だけ

     Slackに送る、ということをしている


    View Slide

  36. ワーカー作戦のまとめ

    ・ワーカーをたくさん作る→一回のテストは短くなる→全体は短くなる

    たくさんあるテストをなんとか回すことはできるようになった

    けれど... 新たな課題が
    ・並行しすぎることによる様々なオーバーヘッドが発生した

     =不要にBuild時間を使っているようだ

    ・実際、何度か走らせてみるとコストがかかりすぎる

    →ちゃんと必要十分な計算リソースを割り当てたい

    なんとか全件走るようになったが


    View Slide

  37. どれくらいのコストが適切か見積もる

    ・元のプラットフォームのテストの所要時間を把握、分析する

    ・Cloud Buildで同等のテストを実行できるようにする

    ・それらを比べる

    ・パフォーマンス劣化をしていないか

    ・劣化している場合何がボトルネックか

    ・現実的なコストで収められるか

    ・その上で、ボトルネックは解消するか、他に縮める方法がないかを調べる


    View Slide

  38. 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 で同じテストケースで計測 


    View Slide

  39. 2) CPUの割り当てを最適化

    ・テスト実行には当然MySQL、memcachedなどいろいろなサービスが

     サイドカーで立ち上がる

    ・なのでperlのプロセスだけでなく

     プラスアルファでそこそこの数のプロセスが立ち上がってくる

    ・色々試すと、そもそも実行時間自体が安定しない

    ・なるべく少ないCPUでたくさんのプロセスを回そうとする

    ・そうするといい感じにCPUが割り当たっていない場合がある?

    この辺からクラウドを使い倒してる感じに


    View Slide

  40. CPUの割り当て、どう最適化?

    ・dockerのcpuスケジューリング周りのオプションを調整した




    ・値をいくつか変えり、オプションを比べた感じ

    → MySQLに優先してCPUが割り当たるようにすると時間が改善

    コンテナが使うCPUを固定する(pinning) 

    コンテナのCPU割り当てのweightを上げる 

    (デフォルト = 1024) 


    View Slide

  41. 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

    View Slide

  42. 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

    View Slide

  43. 現在の進捗

    定期実行するもの:
    ・✅ Go のテスト

    ・✅ E2E テスト

    ・🚧 Perl のテスト(prove)

    ・✅ Lint (Go, perlcritic, YAML諸々)

    ・✅ フロントエンド系 (assetsのビルド)

    リリース時に実行するもの:
    ・✅ イメージ作成+GitHub Release

    Perl はもう少し開発基盤チームと

    チューニングしてから移行予定

    View Slide

  44. まとめ+学びなど


    View Slide

  45. Cloud Build 導入でやったこと

    ・GitHub といい感じに連携できるようにする

    GitHub App と Cloud Functions を使い倒す

    ・skip ciの際の挙動の罠を上手に回避する

    ・数の多いテストを回す仕組みを作る

    ・色々とチューニングをして、コストを最適化する

    もちろんテスト時間の短縮は開発生産性にダイレクトに効く

    今日お話ししたことのまとめ


    View Slide

  46. 学び: Cloud Build の扱い方

    CIのための一種のフレームワーク

    ・Cloud Buildには、ある程度最低限のものはあるが、One-Size-Fits-All に

     全て揃っているとは考えるべきではない

    ・逆に、周辺のサービスを小さく組み合わせることで色々なことができる

    ・Cloud Functions

    ・Cloud Pub/Sub

    ・Cloud Run, GCS...

    ・アプリケーション基盤を含めた大きな観点で組み合わせる


    View Slide

  47. 学び2: 推測するな、計測せよ

    基本だが難しい

    ・初め、とにかく並行化して速くすればいいと考えて、ジョブを大量に実行するような
    アーキテクチャにしていた

    ・結果的にコストが余計にかかりすぎることに→何のための移行?

    ・現状を把握する+現在のボトルネックを見つけ出す

    ・それがシステムの改善にとって一番重要

    ・そして、考えられるチューニングポイントは一通り試すべき

    ・クラウドネイティブだからこそ計算機と仲良く


    View Slide

  48. https://speakerdeck.com/hr_team/engineers-handbook
    大事なお知らせ(2)

    ● インフラ/

    ストリーミング/

    バックエンド基盤/

    ライブゲーム開発

    ● Go、Google Cloudユー
    ザーに近い開発に

    興味のある方歓迎!


    View Slide

  49. https://tech.mirrativ.stream/
    テックブログも見てください


    View Slide

  50. ご清聴ありがとうございました


    View Slide