GitHub-hostedライクなself-hosted Runnerを管理するツールを作った

こんにちは、whywrite.it CI班のwhywaitaです。

この記事はCyberAgent Developers Advent Calendar 2020 20日目の記事です。
昨日の担当はdears31さんの社内勉強会を作ったはなしでした。
私も以前勉強会を立ち上げていたりするのですが、継続することは本当に大変ですよね。

私は普段プライベートクラウド(Cycloud)の開発運用を行っています。直近だとISUCON10のインフラ提供などをやっていました。

GitHub ActionsのGitHub-hosted Runner

GitHub Actionsを実行する環境(runner)には、GitHubが全てを管理してくれるGitHub-hosted Runnerと、自ら用意したサーバを利用するself-hosted Runnerの2種類があります。

GitHub hosted-runnerはフルマネージドなことに加えて、CIに必要なミドルウェアを docker run するだけで起動することができるなどの利点があります。
しかし、世の中には以下のような欲求があったりします。

  • スペックが足りない
    • 執筆時点では2core 7GBですが、もう少し大きいインスタンスを使いたいこともあるでしょう
    • もしくは、例えばFPGAやGPUのような特殊なハードウェアを利用したいこともあるでしょう
  • 料金が高い
    • GCPのPreemptible VMのような安価なインスタンスを使ったり、弊社のようにプライベートクラウドで安価に計算機資源を使えるならそちらを使いたいでしょう
  • GitHub Enterprise Server (GHES)だとまだ対応してない
    • Public Roadmapにはあるようですが実現はもう少し先になりそう

そのような要求のためにself-hosted runnerが用意されているのですが、こちらも一長一短GitHub-hostedにあった利点がなくなっていたりします。

  • 1台ずつrunnerプロセスを立ち上げてActions Jobを待ち受ける形式
    • オートスケールに非対応
    • apt-get install などのシステム全体に影響のあるActionを書くとCIシステムの冪等性が失われる
  • Dockerが動作している保証がない
    • GitHub-hosted で動いたサードパーティのActionが動かない可能性がある

それらの欠点を解決するツールであるmyshoesを本日リリースしました。

myshoes

自分の靴(=自分のクラウド、VM)で走る(=runner)でmyshoesです。
上記で書いたとおりself-hosted runnerに存在する欠点を埋めて、GitHub-hosted runnerのような使い心地を目指して作られています。

  • Actionsの実行を検知して自動でインスタンス作成 & 終了後は自動削除
  • 最新のrunnerを自動で取得して起動できる
  • VMを起動させるためDockerもネイティブに起動できる

インスタンス作成の実際の処理はprovider (shoesと呼んでいます)として別リポジトリに用意してあります。shoesバイナリを差し替えるだけでrunnerを起動する仮想化基盤を差し替えられるように設計しています。
現在はOpenStackとLXDに対応しています。AWSやGCPなんかも対応は容易だと思います。

詳細な使い方はREADMEを見ていただくことにして、ざっくりとした使い方を箇条書きで書いておきます。

  • GitHub Appsを作成する
  • myshoesバイナリを github.com or GHESから送信されるWebhookを受信できるところで起動
    • VPSとかでも良いですし、Kubernetesクラスタとかでも良いでしょう
    • このときどのようなshoesを利用するかも指定します、ビルド済みバイナリのファイルパスかHTTP URLを指定します
  • オートスケールする対象となるRepositoryかOrganizationを指定します、↓な感じ
# github.com/octocat/hello-world にauto scallしたい場合
$ curl -XPOST -d '{"scope": "octocat/hello-world", "ghe_domain": "", "github_personal_token": "xxx", "resource_type": "micro", "runner_user": "ubuntu"}' ${your_shoes_host}/target

# https://github.example.com/ghes-orgs にauto scallしたい場合
$ curl -XPOST -d '{"scope": "ghes-orgs", "ghe_domain": "https://github.example.com", "github_personal_token": "xxx", "resource_type": "micro", "runner_user": "whywaita"}' ${your_shoes_host}/target
  • offilineなrunnerを1つ作っておく
    • GitHub Actionsの制約上、Offlineが1台もないと即failするのでオートスケールされたrunnerが間に合いません
  • あとはJobを動かすだけ!

類似サービスとの比較

  • GitHub-hosted runner
    • 完全マネージドはやはり利点
    • とはいや制約もそれなりに
  • summerwind/actions-runner-controller
    • Kubernetes上でrunnerを起動させるプロダクトです
    • コンテナ上でrunnerプロセスを起動させるため、docker runなどは docker.sock を見せるなどの工夫が必要そうです
    • Kubernetesのみなので動作としては安定しています

deep dive

後々に社内的な事情が差し込まれる予定なので、内部的にいくつかのコンポーネントに分けた上でGolangのinterfaceを用いて実装を差し替えることができるようになっています。

例えば課金や在庫状況でインスタンスを無制限に作りたくないという要望に向けてSafetyというinterfaceを作っていたりします。標準状態だとUnlimitedが用意されているので何も考えずインスタンスの起動を指示しますが、他のチェック機構を差し込みたい時などはSafetyを満たすような関数を実装すれば良いでしょう。

cmd/server/cmd.go をコピペした上で自前の実装に切り替えるなどする予定です。(なっているはず……)

今後について

先日社内でクローズドベータを開始しました。最終的にはマネージドmyshoesサービスを提供出来れば良いなと思っています。
徐々にクローズドベータで様々なworkflowファイルを試しつつ、今後は安定稼働を目指して引き続き手を加えていく予定です(社内で興味のある方がいたらお声がけください)。

またContributionなどもぜひお待ちしております。

明日は

mayusyさんの「envoy-wasmで何か書きます」です。未来を感じますね。


コメントを残す