33.9K Views
May 26, 23
スライド概要
2023.05.26 CI/CD Test Night #6 開発者体験を改善し続けるための Self-hosted runner 運用基盤 クックパッド株式会社 技術部 SRE グループ Takamasa Saichi (@s4ichi) © 2023 Cookpad Inc.
About me ● Takamasa Saichi / 齋地 崇大 / s4ichi ○ https://s4ichi.com ○ https://twitter.com/s4ichi ○ https://github.com/s4ichi ● クックパッド株式会社 技術部 SRE グループ ● 業務/関心事 ○ CI/CD(基盤, DX) ○ アプリケーションの Observability ○ パフォーマンスチューニング ○ プログラム言語処理系 © 2022 Cookpad Inc. 2
毎日の料理を楽しみにする https://cookpad.careers/ © 2023 Cookpad Inc. 3
Table of contents 1. クックパッドの CI 環境(GitHub Actions 以前) 2. Self-hosted runner を提供する仕組み 3. Self-hosted runner の用途拡張 4. 改善に向けた計測の仕組み 5. 基盤の開発を通して開発者体験を改善 © 2023 Cookpad Inc. 4
https://techlife.cookpad.com/entry/2022/11/07/124025 © 2023 Cookpad Inc. 5
クックパッドの CI 環境(GitHub Actions 以前) © 2023 Cookpad Inc. 6
クックパッドの CI 環境 ● GitHub Enterprise Server/Cloud(以後 GHES, GHEC)上のリポジトリで開発 ● 社内のアプリケーション総数(国内)が 1,000 程度 (*) ● ○ Amazon ECS 上にデプロイされるアプリケーションが大半 ○ 一部 Lambda function としてデプロイされるアプリケーションも CI 環境は以下から選択される ○ Jenkins(provisioning された EC2 のノード) ○ Jenkins + AWS CodeBuild(ECS Fargate ノードから CodeBuild を起動) (*) staging, batch 用, internal 向けなどの細かいアプリケーション含む社内の基盤換算 © 2023 Cookpad Inc. 7
クックパッドの主流な開発フロー ● Jenkins + CodeBuild の構成が主流 ○ ● ● 時間単位課金とクリーンな環境、ビルドキューの待ち時間から CodeBuild が推奨 CI を実行するまでの手順 ○ CodeBuild project を terraform で作成 ○ Jenkins job を GUI から作成(CodeBuild Project と紐づけ) ○ webhook の設定(GitHub への push に応じて job が起動するように) 開発によってアプリケーションに変更が加わると、 ○ Jenkins ノードが Fargate タスクで起動し、 CodeBuild project をキック ○ CodeBuild 上でテストやビルドを実行し、成果物を ECR Repository に保存 ○ あとは ChatOps を通じて Rundeck からデプロイ © 2023 Cookpad Inc. 8
CI 環境の抱える課題 ● ● Jenkins の GUI 設定が難しい ○ プラグインごとに設定の組み合わせの一貫性が無いので見たい設定が見つからない ○ 変更のレビューが不可能なのでナレッジが属人化される AWS CodeBuild project のメンテナンスが必要 ○ ● ベースイメージ古い場合は provisioning 時間が長くなる傾向 全て動かすまでに関わるコンポーネントが多い ○ e.g., Jenkins job(GUI), CodeBuild project(terraform), webhook(GitHub) CI の関心事に集中しやすい環境を提供したい © 2023 Cookpad Inc. 9
当時の GitHub Actions の利用状況 ● ● GHES(オンプレミス)には GitHub-hosted runner が提供されていない ○ つまり Actions を利用するために Self-hosted runner の利用が必須 ○ Actions: GitHub Enterprise Server can use GitHub-managed runners with GitHub Connect GHEC では Actions の利用が進んでいる ○ GHEC を利用しているのは主に日本国外の Cookpad を開発する Global のチーム ○ 国内のチームはバックオフィス含めて GHES を活用しているため GHEC はほぼ使わない © 2023 Cookpad Inc. 10
Self-hosted runner を提供する仕組み © 2023 Cookpad Inc. 11
導入のモチベーション ● 既存の CI 環境(Jenkins + CodeBuild)にある課題を解決したい ● GitHub Actions へ代替することで解決できること ● ○ GUI による設定ではなく GitHub Flow が適用できる開発スタイル ○ 実行環境が基板側で管理 /運用されるので CodeBuild project のようにメンテナンスが不要 ○ 動かすまでの設定が YAML を書くだけで済む GHES でも GitHub Actions を運用する最低限の機能がリリースされた ○ GHES 3.3 系から autoscaling のために workflow_job webhook を購読できるように ○ Ephemeral な runner を実行するためのオプションに対応 © 2023 Cookpad Inc. 12
Self-hosted runner 導入の要件 ● Self-hosted runner となるホストで actions/runner が実行できる ● 社内のユースケースを広く満たす汎用的な runner が提供できる ● 実行環境は Amazon Web Services(AWS)上で完結することが好ましい ● インフラのコスト 💸 や運用の手間をできる限り削減できる ○ Autoscaling や Spot instance の活用は必須 © 2023 Cookpad Inc. 13
Self-hosted runner をどこで動かすのか問題 ● ● ● Amazon EC2 ○ philips-labs/terraform-aws-github-runner を利用する? ○ もしくは Auto Scaling Group など合わせて基盤を構築 Amazon ECS ○ EC2, Kubernetes などと比べて前例がほぼ無い ○ 社内は ECS を使い倒しているため検証次第では可能 Kubernetes(Amazon EKS) ○ actions/actions-runner-controller を利用する? ○ Kubernetes の利用前例が社内(国内)に無いので腰が重い © 2023 Cookpad Inc. 14
Self-hosted runner の内容物をどうするか問題 ● 素の ubuntu に actions/runner をインストールするだけ ○ ● actions/runner を actions/runner-images の上で起動 ○ ● 何もないのは困る runner-images の ubuntu はサイズがかなり大きい ■ 様々な言語処理系全部入りの巨大環境 ■ 金銭的コストと運用は大変になるけど利用者は便利 必要なパッケージを順次入れて育てる環境 ○ actions/runner が入っている初期状態から利用傾向の高いパッケージを選択して同梱 © 2023 Cookpad Inc. 15
検証、実装、決定 ● ● ● Self-hosted runner をどこで動かすのか → ECS on EC2 で実行 ○ EC2 は起動時間や AMI の管理の手間から断念 ○ Kubernetes は今回のために Cluster を用意するのは難しそうと断念 ○ ECS でコンテナを利用( on EC2 の理由は後述) Self-hosted runner の内容物はどうするか → 必要なパッケージを取捨選択 ○ GitHub-hosted runner の体験に近似させることよりも社内利用に特化させる ○ 典型的なビルドパターンを満たすパッケージを選択して同梱 運用の手間を極限まで減らす → Serverless かつデータストアを持たない設計 ○ GHES の webhook からイベント駆動で完結させる © 2023 Cookpad Inc. 16
ghe-actions: Self-hosted runner 提供基盤 ● Organization に インストールした GitHub App から webhook を 受けて ECS Task を起動するシンプルな構成 ● 開発者は GitHub App を Organization にインストールして 有効にするリポジトリを選択 © 2023 Cookpad Inc. 17
ghe-actions: Self-hosted runner 提供基盤 ● GitHub App は `workflow_job` の webhook を受けて Lambda `webhook` を invoke(Lambda function URL 経由) ● Lambda `webhook` は body のパースと `workflow_job` の webhook から必要な情報をフィルタリング ● パースした payload を SQS `build-queue` へ © 2023 Cookpad Inc. 18
ghe-actions: Self-hosted runner 提供基盤 ● Lambda `controller` は SQS `build-queue` から dequeue ● Lambda `controller` が一定回数失敗したら DLQ へ payload を送り人間が問題の解決へ(監視) © 2023 Cookpad Inc. 19
ghe-actions: Self-hosted runner 提供基盤 ● Lambda `controller` は payload からリポジトリや Label を取得 ● Repository の Registration Token を GitHub App 経由で発行 ● 必要な runner の ECS Task を決定して ecs:RunTask 実行 ○ サイズ, Security Group の設定, コスト管理用のタグ © 2023 Cookpad Inc. 20
ghe-actions: Self-hosted runner 提供基盤 Q. ECS Task の中身は? © 2023 Cookpad Inc. 21
actions/runner を ECS Task(Docker コンテナ)として起動 ● Docker コンテナで actions/runner を起動する挑戦 ○ 当時 myoung34/docker-github-actions-runner でコンテナ化は既に実現済 ○ 一部 Actions の機能に制限が入るが大きく困ることはない ○ 公式には未だ非対応、ということになっている © 2023 Cookpad Inc. 22
actions/runner を ECS Task(Docker コンテナ)として セキュア に起動 ● 既存の実現方法は Docker コンテナの起動に特権( privilaged: true)が必要 ○ dockerd をコンテナ内から利用可能にするため ■ Docker-in-Docker: dockerd をコンテナ内で起動する ■ Docker-outside-of-Docker: コンテナ外の dockerd をコンテナ内から参照する ● ● ● ホストの dockerd を参照するなどで特権は不要だがそもそもホストが見える 今回は用途的に特権付きのコンテナは動かしたくない ○ Self-hosted runner は特定の用途だけでなく汎用化して運用するため ○ ホストや他のコンテナに干渉できる状態は避ける ECS Fargate は特権コンテナとして Task を実行できないのでこの時点で on EC2 が確定 ○ 社内の ECS 環境は on EC2 が主流なので運用の知見も有る © 2023 Cookpad Inc. 23
actions/runner を ECS Task(Docker コンテナ)として セキュア に起動 ● コンテナ内で dockerd を rootless-mode で起動する案 ○ Docker には non-root user で dockerd を起動する仕組みが提供されている ○ ただし、dockerd を動かすホストのコンテナは特権が必要 …… © 2023 Cookpad Inc. 24
actions/runner を ECS Task(Docker コンテナ)として セキュア に起動 ● actions/runner が起動するコンテナと dockerd が起動するコンテナを分割 ○ ECS Task の sidecar コンテナとして起動して actions/runner から dockerd を参照 ○ Task を awsvpc mode で起動することで localhost で起動したコンテナにアクセス可能 © 2023 Cookpad Inc. 25
インフラコストを抑えつつ ECS Task を実行する ● ECS Task を起動する EC2 インスタンスは Spot instance で起動し ASG で台数を管理 ● EC2 の AMI は社内の ECS 運用で利用している イメージと合わせて既存の資産を活用 ● ECS の Target tracking scaling を使って 必要な台数だけ起動して Task を実行 ● 集積率を上げて CodeBuild より安く ○ CodeBuild(general1.large): $0.02 / min ○ EC2(spot) : $0.002445 / min (*) (*) 実際に利用している m6i.2xlarge を spot 価格 $0.1467 /1 時間 として計算して比較 © 2023 Cookpad Inc. 26
最小構成で Self-hosted runner を提供する基盤 © 2023 Cookpad Inc. 27
Self-hosted runner の用途拡張 © 2023 Cookpad Inc. 28
複数アーキテクチャ & サイズの runner を提供 ● controller 内で labels を参照して runner のスペックを決定 ● ecs:RunTask の段階で Task definition を overrides し 実行する ECS Cluster や割り当てる vCPU/Memory を指定 jobs: awesome-arm64-test: # 1 cores CPU, 2 GiB of RAM, 10 GiB of Storage (ARM64) runs-on: [ self-hosted, ecs-runner-micro, ARM64 ] awesome-amd64-test: # 8 cores CPU, 15 GiB of RAM, 20 GiB of Storage (AMD64) runs-on: [ self-hosted, ecs-runner-large, x64 ] © 2023 Cookpad Inc. 29
AWS VPC Internal なリソースにアクセス可能な runner ● Security groups の ID を whitelist 形式で設定できるように拡張 ○ RDS 等 VPC 内へのリソースのアクセス制御の文脈で、特定の用途で必要 ■ ○ 基本的には aws-actions/configure-aws-credentials による IAM Role でのアクセス制御 ECS Task を awsvpc mode で起動しつつ ecs:RunTask 時に SG を overrides して実行 jobs: redshift-accessible-test: # 1 cores CPU, 2 GiB of RAM, 10 GiB of Storage, ARM64, attached `sg-12345` runs-on: [ self-hosted, ecs-runaner-micro, ARM64, sg-12345 ] © 2023 Cookpad Inc. 30
改善に向けた計測の仕組み © 2023 Cookpad Inc. 31
runner に関連するメトリクスの収集・可視化 ● workflow_run の webhook を受けて completed な workflow のメトリクスを収集 ○ CI の各ステップの実行時間が時系列 DB や Redshift からクエリできる状態 © 2023 Cookpad Inc. 32
運用にまつわるメトリクスの可視化と監視 ● runner の provisioning 時間 ○ ● completed な job の status ごとの数 ○ ● 高速化の改善の指標 利用傾向の把握と異常検知 EC2 台数の可視化 ○ 不自然な Autoscaling の把握 ○ 必要に応じてアラートの設定 © 2023 Cookpad Inc. 33
Inspired by Kesin11/CIAnalyzer © 2023 Cookpad Inc. 34
計測の仕組みを含めた全体像(説明割愛) © 2023 Cookpad Inc. 35
基盤の開発を通して開発者体験を改善 © 2023 Cookpad Inc. 36
やっていくだけ ● ● 既存の CI 環境で課題にあることを解決する準備が整ってきた ○ 実用に耐えうる Self-hosted runner の提供基盤 ○ 開発や運用のメトリクスから改善指標の可視化 やっていってる ○ ● Jenkins にある大量の job を Actions に移行 → 開発体験の支援および集積率向上 やっていきたい ○ Provisioning 時間の改善 → workflow 実行までの待ち時間を最小に ○ ECS Cluster の Autoscaling を改善 → コンテナの集積率を向上させ金銭的コストを抑える ○ job ごとの CPU/Memory 使用率の可視化 → 適切なサイズの runner の発見を支援 ○ docker-container driver を使ったビルド → Amazon Linux 2 の rootless-dind 環境下で動かない ○ ECS のイメージを定期的に更新する → ビルド時間の削減 , vulnerability の対処 © 2023 Cookpad Inc. 37
Provisioning 時間の改善 ● job が実行するまでの待ち時間が長い ● ecs:RunTask から実行までが 40s ● ECS Cluster の scaleout が実行されると 40s + 数分かかる(EC2 起動時間) ● Self-hosted runner を pool する仕組み ● サイズやアーキテクチャごとに pool を 用意しておきリクエストごとに払い出す ● 実行に失敗して放棄された job も救済 © 2023 Cookpad Inc. 38
ECS Cluster の Autoscaling を改善 ● 過剰な Autoscale でインスタンスが 余分に起動することでコスト増 💸 ● 多少の待ち時間を犠牲にしても 集積率を上げることで節約したい ● Self-hosted runner の pool と…? ● job 数の傾向を見て pool サイズの調整 © 2023 Cookpad Inc. 39
毎日の料理を楽しみにする https://cookpad.careers/ © 2023 Cookpad Inc. 40
© 2022 Cookpad Inc. 41