技術開発部の相原です。
今回は、2019年末にリリースされたGitHub ActionsのSelf-hosted runnersをKubernetes上で動かして自動化に取り組んでいる事例を紹介します。
背景
LIFULLではプライベートネットワーク上に存在するRDBMSなどのリソースを利用したアプリケーションのテストを実行するといった用途で、古くからJenkinsが運用され続けてきています。
こういったテストの実行などはプライベートネットワークに疎通できないCircleCIやGitHub Actionsでは実行することができず、プライベートネットワーク上に構築されたJenkinsなどのサーバがリポジトリの更新を検知して実行する必要があります。
そのためLIFULLでもJenkinsを運用し続けてきたわけですが、ご多分に漏れずこれまでにバージョンアップやJenkins職人問題・スケーラビリティの問題に悩まされてきました。
そこで、我々はこれらの問題を解決すべくGitHub Actions Self-hosted runnersに着目しました。 GitHub Actions Self-hosted runnersとは、GitHub ActionsをGitHub hostedな環境ではなく自分たちのインフラで動かすための2019年末にリリースされたランタイムです。
これを利用してプライベートネットワーク上でGitHub Actionsを動かすことで前述のテストをJenkinsから移行することができ、Jenkinsサーバを撤廃できるのではないかと考えました。
GitHub Actions Self-hosted runners on Kubernetes
前回のLIFULLが主要サービスの(ほぼ)全てをKubernetesに移行するまでで紹介しましたが、現在LIFULLでは大部分のアプリケーションがKubernetes上で動いています。
当然そのKubernetesクラスタはプライベートネットワーク上で稼働しているため、以下のようなメリットを期待してGitHub Actions Self-hosted runnersをこのKubernetes上で稼働させることにしました。
- 日々の運用の余剰リソースを利用してrunnerを動かすことでのコストカット
- 待ち時間のないジョブ実行
- 柔軟なリソース確保
- Kubernetesの宣言的なAPIを利用することによる脱Jenkins職人
しかし、Kubernetes上で動かすといっても公式からのサポートが受けられるわけではありません。
そこで、KubernetesのCustom Resource DefinitionsというKubernetesのAPIを拡張して任意のリソースを定義することのできる機能を利用してGitHub Actions Self-hosted runnersを動かすためのソフトウェアを余暇の時間で開発して導入しました。
このソフトウェアを利用すると以下のようなKubernetes Manifestをデプロイするだけで任意のイメージのGitHub Actions Self-hosted runnersが指定したリポジトリに紐づけられて起動します。
apiVersion: github-actions-runner.kaidotdev.github.io/v1 kind: Runner metadata: name: example spec: image: ********.dkr.ecr.ap-northeast-1.amazonaws.com/homes repository: lifull/homes tokenSecretKeyRef: name: credentials key: TOKEN
本来、GitHub Actions Self-hosted runnersはGitHubから提供されているランタイムをサーバにインストールして利用することを前提とされています。
ref. セルフホストランナーの追加
そのためこれをコンテナとして動かすことを考えると、あらかじめこのランタイムがインストールされたイメージを用意して利用することになってしまいますが、アプリケーションのテストをrunnerに実行させたいといったケースで毎回そのアプリケーションのイメージを再ビルドしてランタイムをインストールするということは現実的ではありません。
そこでこの問題を解決するため、少々いびつではありますがkaidotdev/github-actions-runner-controllerは以下のような動きをします。
これらの動きは全てコントローラの裏に隠されていて、利用者は適当なイメージをKubernetes Manifestに書いてデプロイするだけでそれが透過的にrunner入りのイメージとして再ビルドされて起動するようになっています。
そのため、通常のアプリケーションのデリバリーパイプラインをそのまま利用してこのマニフェストをデプロイすることで、runnerのイメージを最新のアプリケーションに追従させることが可能となりました。 Spinnakerを利用している場合はイメージのタグをSpinnakerが勝手にいじってくれるのでそのままこのマニフェストを加えるだけですし、GitOpsなデリバリーパイプラインを使っている場合もタグ更新のワークフローを同様にこのマニフェストにも適用するといった感じです。
不自由なくGitHub Actions Self-hosted runnersを使うために必要な機能は大体備えているはずで、環境変数やファイルのマウント、コンテナリソースの定義に加えてkaidotdev/github-actions-exporterを利用してin-queueなジョブの数を公開しているため、カスタムメトリクスを利用したスケールアウトによってin-queueなジョブの数に応じたコンテナの増減も可能です。
詳しい使い方に関してはREADMEをご覧ください。
GitHub Actions Self-hosted runners on Kubernetesによる自動化
こうしてLIFULLは誰もが自由にGitHub Actions Self-hosted runnersを起動できる環境を手に入れました。
GitHub ActionsはGitHubのあらゆるイベントを元にジョブを実行することができ、様々な自動化タスクへの適用が期待できます。
そして、誰もが自由にGitHub Actions Self-hosted runnersの導入が可能になったことによって、多くの開発者がそれぞれで気軽に自動化に取り組むことができるようになりました。 これは今までのJenkinsの運用や、クラウドサービスとしてのCircleCIやGitHub Actionsの利用では実現できないことでした。
我々のチームとしてもこの仕組みを利用して以下のような自動化に取り組んでいます。
- アプリケーションのリリースパッケージでのテスト実行
- アプリケーションのデプロイ
- コンピューティングリソースを利用する解析処理
クラウドサービスを利用すると待ち時間が長かったり利用できるコンピューティングリソースに制限があったりしますが、この仕組みに載ることで格安で待ち時間なく大量のコンピューティングリソースを使えるようになりました。
同じことを実現できるソフトウェアは多くありますが、Kubernetesの宣言的なAPIの利用によって簡単に自分たちのインフラで動かすことができ、GitHub Actionsという開発者に慣れ親しんだフォーマットで自動化タスクを記述できる安価でスケーラブルかつ柔軟なこの仕組みには一定の価値があると考えています。
自動化タスクにお悩みの方は試してみてはいかがでしょうか。