Docker

サイドカーDinDでGitHub Actionsのセルフホステッドランナーを構築する

Dockerコンテナ上でセルフホステッドランナー(self-hosted runner)を動かすには、いろいろハードルがあると聞いていたのですが、実際にやってみるとそんなことも無くなっていたので、令和最新版としてDocker Composeで手っ取り早く構築方法をメモっておきます。

ランナーのバージョンは2.320.0時点の記事になります。

スポンサーリンク

事前に把握していた問題について

  • rootユーザーでランナーを実行できない
  • Dockerコンテナ上で実行できない
  • コンテナジョブ内でusesを使ったステップが実行できない

上記のような面倒がありそうだったのですが、Docker Composeで構築してみたところ割とストレートにできてしまい、これといった不都合もありませんでした。ランナーのアップデートで状況が変わったのかな?

なお、今回は以下の記事を参考にさせていただいてます。

コンテナのセルフホストランナーの中でコンテナを使えるようにするrunner-container-hooks
self-hosted runnerをDockerイメージにする|SHIFT Group 技術ブログ
はじめに はじめまして。DAAE開発1グループの中本です。 self-hosted runnerをDockerイメージにしてみたので紹介します。 self-hosted runnerとは 一言で言うと、GitHub Actionsの実行環境...
Deploying Self-Hosted GitHub Actions Runners with Docker
This tutorial looks at how to deploy self-hosted GitHub Actions runners with Docker and Docker Swarm to DigitalOcean.

必要なもの

こちらのスニペットから一式ダウンロードできます。

サイドカーDinDでGitHub Actions Self-Hosted Runner (59301) · Snippets · GitLab
GitLab.com
  • Dockerfile
  • compose.yaml
  • entrypoint.sh
  • runner.env

構築方法はスニペット付属の説明をご覧ください。

簡単な解説

Dockerfile

ディストリビューションはあまり自由が無い

ベースOSはrunnerに同梱のinstalldependencies.shの都合で、使用可能なディストリビューションが限定されています。

# Determine OS type               
# Debian based OS (Debian, Ubuntu, Linux Mint) has /etc/debian_version
# Fedora based OS (Fedora, Red Hat Enterprise Linux, CentOS, Oracle Linux 7) has /etc/redhat-release
# SUSE based OS (OpenSUSE, SUSE Enterprise) has ID_LIKE=suse in /etc/os-release

自分は容量が最も少なく済む、AlmaLinuxを採用しましたが、yumコマンドが必須なので、pythonがオミットされているminimalイメージは使えません。

root実行可にする

通常はrootユーザーで実行すると怒られますが、RUNNER_ALLOW_RUNASROOT=1を環境変数にセットしておけば無視できます。

DinDコンテナにもランナーのファイルコピーする

DinDを利用してジョブをコンテナ実行すると、ジョブコンテナにDinDコンテナ内のファイルがバインドされます。
よって、ランナーのコンテナにだけ必要なファイルがあっても事足りず、かといってボリューム経由で共有するのも手間なので、手っ取り早く/actions-runner以下の静的なファイルは最初からDinDイメージに含めてしまいます。
その為、マルチステージビルドを利用して、ランナー用とDinD用それぞれのイメージを作成できるようにしています。

entrypoint.sh

コンテナ起動時に自動登録&終了時に自動削除

起動時にconfig.shを使ってGitHubにランナーを登録するようになっています。
この際、repositoryの権限を持つPersona access tokenが必要なので、別途取得して.envに記入しておく必要があります。
他所の記事を参照したところでは、GitHub APIを使って一時的なトークンを取得する必要があるとなっていましたが、--patオプションにアクセストークンを直接指定すれば、その必要はありませんでした。

また、コンテナ終了時は自動でランナー登録を削除してくれるようにしたのでゴミが残りません。

ワーキングディレクトリの指定がキモ

config.shのオプションで--workを指定しています。
これはジョブ実行時に利用されるワーキングディレクトリで、/actions-runnerディレクトリから相対パスです。
デフォルトでは__workとなっています。
コンテナを使用したジョブではこのディレクトリの一部がマウントされるので、コンテナとDinDコンテナでボリュームを介した共有が必要になります。

ランナーとDinDを1:1で動かすのであれば、デフォルトの__workを利用しても問題ありませんが、複数インスタンスでDinDを共有する場合はそれぞれ異なるパスを指定しないと、DinDコンテナ内でパスがバッティングしてしまいます。
だから個別にパスを設定する必要があったんですね。

compose.yaml

1つのDinDに対して、2つのランナーを構成する例になっています。
必要に応じてランナーの数を増やすことができます。
環境変数GITHUB_WORKDIRで先述のとおりワーキングディレクトリを個別に指定しています。
それぞれに対してボリュームを定義して、DinDとランナーにマウントしてファイルの共有を行います。

課題点

フォールバックと分散実行

GitHub Actionsは現在のところ、self-hosted runnerがダウンしている場合、GitHub hosted runnerにフォールバックして実行してくれるような機能がありません。
手動で切り替えたり、フォールバック判定をするジョブを作れば一応は可能なようです。

また、複数のself-hosted runnerがリポジトリに登録されていても、ビジー状態のランナーに平気でジョブをキューしてしまい、均等に分散してくれたりしません。
ランナーグループを作成すればいい感じになる?らしいですが、前述のフォールバックと両立させるとなると一工夫必要な気がしています。

これらの問題が解決できたら、また執筆したいと思います。

以上!

スポンサーリンク
記事を書いた人

システムえんじにゃー🐈
趣味はエレキギター、自転車など。作曲したい。
World of Warshipsやってます。
記事に関する質問はお気軽にどうぞ。

surface0 (さーふぇす)をフォローする

コメント

タイトルとURLをコピーしました