【GitHub Actionsをもっとたくさん使いたい！】AWS CodeBuildでSelf-hosted Runnerできるようにした

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14794/7a563738-45be-b519-15e8-55b04bb775cb.png" alt="Logo" width="400"/>

GitHub Actionsとても便利ですよね。
コミットプッシュやPRマージだけではなく、Issueコメントやラベル追加をトリガーにしてワークフローを動かすことができるので、いろいろな定形処理を自動化できます。
あれもこれもといろいろなワークフローを追加したら、利用時間上限になってしまってワークフローのダイエットしないといけなくなった、、、なんてことも。

今回はそんなGitHub Actionsを、（有料だけど）もっとたくさん使えるようにと作った仕組みについての紹介です。

## 作った動機

主な理由としては１の時間のかかるジョブが増えてきたことですが、２や３の運用コスト、費用面でもメリットがありそうだと思って仕組みづくりをはじめました。

1. AWS ECSなどでdocker buildしないといけないことが多くなったので、実行時間が長くなり利用時間上限を気にしたジョブ構成を考えないといけなくなってきた
2. Jenkinsなどを動かしているEC2インスタンスのEOL対応や問題発生時の対応、依存ライブラリ追加・更新などの保守・運用がつらい
   <br>・ 実行環境がコンテナベースになると、アプリケーションごとに必要な環境を開発者が個別に用意しやすい（してもらえる）
3. CI実行待ちしないようにEC2インスタンス追加したり夜間停止したり、CIサービスでのメンバー数ベースの課金体系など（純粋に使った時間だけの課金にしたい）
   <br>・ 請求がAWSにまとまるほうが申請出しやすいという裏話

## Self-hosted Runner（セルフホストランナー）とは？

[セルフホストランナーについて](https://docs.github.com/ja/actions/hosting-your-own-runners/about-self-hosted-runners)

> 独自のランナーをホストし、GitHubActionsワークフローでジョブを実行するために使用する環境をカスタマイズできます。
>
> セルフホストランナーは、GitHubホストランナーが提供するよりも、ハードウェア、オペレーティングシステム、およびソフトウェアツールのより多くの制御を提供します。セルフホストランナーを使用すると、より多くの処理能力またはメモリを備えたカスタムハードウェア構成を作成して、より大きなジョブを実行したり、ローカルネットワークで利用可能なソフトウェアをインストールしたり、GitHubホストランナーが提供していないオペレーティングシステムを選択したりできます。セルフホストランナーは、物理、仮想、コンテナ、オンプレミス、またはクラウドのいずれでもかまいません。

GitHub Actionsのワークフローを実際に動かす環境を自分で用意したところにできるということです。しかも、セルフホストランナーは自由な環境に配置できます。
セルフホストランナーをdocker image化すればよさそうです。

> GitHubがホストするランナー：
> ・ GitHubによって管理および保守されています。
> ・ GitHubプランで無料の分を使用し、無料の分を超えた後に1分あたりの料金を適用します。
> セルフホストランナー：
> ・ 利用者がオペレーティングシステムと他のすべてのソフトウェアを更新する責任があります。
> ・ GitHub Actionsで自由に使用できますが、ランナーマシンのメンテナンス費用はお客様の負担となります。

セルフホストランナーならGitHub Actionsを自由に使えます。ただし、ランナーマシンが動く環境の利用料金は自己負担です。
docker image化したランナーマシンをAWS CodeBuildで動かせば使った時間だけ課金にできそうですね。

## 仕組み

[rvillage/self_hosted_runnerリポジトリ](https://github.com/rvillage/self_hosted_runner)に作ったものは全部公開してあります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14794/0e7d32c8-8ae5-90ec-e9ce-329f6c297a57.png" alt="System Configuration" width="600"/>

### 全体の流れ

| No |  |  |
| --- | :---: | :---: |
| 1. workflowがGitHubホストランナー上で<br>CodeBuildを起動する | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14794/b3437d4f-7532-9b37-e934-f21c623090fe.png" alt="1" width="400"/> | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14794/efd4868b-610b-44d3-cc55-bc06e3810bf4.png" alt="1" width="400"/> |
| 2. CodeBuild上でセルフホストランナーが<br>起動する | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14794/8b69adeb-9fc7-fdd6-18c7-2859fadecadc.png" alt="2" width="250"/> | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14794/3e7e4a6b-f0a8-d543-e1c0-b6f085c5e32e.png" alt="1" width="400"/> |
| 3. workflowがセルフホストランナー上で<br>メインジョブを実行する | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14794/67ff5041-9771-3993-1682-db393f8cd60d.png" alt="3" width="500"/> | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14794/3ec2bf58-e489-66fd-07a1-c4bc0f0587a7.png" alt="1" width="400"/> |
| 4. workflow実行終了、<br>CodeBuildも自動終了する | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14794/f6e32d4c-6bd8-cecf-4e69-10d70f801e2e.png" alt="4" width="400"/> | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14794/7e1611ed-b6f6-93a6-0f13-38acf3a40af2.png" alt="1" width="400"/> |

## できるようになったこと

- docker buildなどの時間がかかる処理をセルフホストランナーで動かすことで利用時間上限を気にしなくてよくなった
- CIサーバの保守・運用がセルフホストランナーのdocker imageを管理するだけになった
- 常時稼働するサーバをなくして純粋に利用する時間分だけ課金する仕組みにできた
- CI待ちを解消するための並列起動数をCodeBuild側の制約だけに絞り込めた

以上ができるようになったことです。
稼働後の運用では手がかかるところは減った印象ですが、最初の初期構築はもう少し簡略化できたらいいなと思っています。
また、課金体系はGitHub Actionsが\$0.008/minに対して、同程度のスペックのCodeBuildだと\$0.01/minなのでちょっと高くなってしまいました。1段階低スペックの料金は\$0.005/minなのでジョブの処理負荷に合わせて使い分けできれば利用料金としてはいい感じになるんじゃないかと思います。

## できるかまだ確認していないこと

`actions/checkout`といったほぼ毎回使うものは動作確認できていますが、`actions/cache`など動作未確認のものがたくさんあります。セルフホストランナーのdocker image自体にライブラリ追加すれば使えるものもあると思いますが、GitHubホストのランナーではないのでどうしても使えないものもあるかもしれません。
ちょっとずつですが、GitHubホストランナーと同じように使えるActionsを増やしていきたいと思います。

## 本当はECS Fargateを使いたかった話

最初に答えを言ってしまうと、`privileged`が設定できないからです。docker in docker環境でdocker buildできるようにするには`privileged`をONにする必要があるのですが、Fargateでは設定不可のためCodeBuildを選択しました。
ただ、docker buildは必要ないよという場合は、Fargateのほうがおすすめかも知れません。Fargate Spotを使ったときの料金が魅力的すぎなので。

- 1vCPUあたり$0.000343468/min
- 1GBメモリあたり$0.000037567/min
- GitHubホストランナー準拠のスペック（2vCPU,7GBメモリ）だと$0.000949905/min

## 参考

- [GitHub Actions Self-Hosted RunnerをDockerコンテナ内で動かしてみてわかったこと](https://qiita.com/mumoshu/items/02cd9a384d91ce0da198)
- [GitHub Actions の自己ホストランナーを手元の MacBook Pro 上の Docker Desktop で試す](https://inokara.hateblo.jp/entry/2020/12/23/003040)
- [GitHub Actions の self-hosted runners を AWS ECS で動かして、CI / CD パイプラインを作る](https://techblog.exawizards.com/entry/2020/10/22/080000)
- [[GitHub]ActionsのホストランナーをEC2でやってみた](https://dev.classmethod.jp/articles/hosted-runner-on-ec2/)