Dockerコンテナ上でセルフホステッドランナー(self-hosted runner)を動かすには、いろいろハードルがあると聞いていたのですが、実際にやってみるとそんなことも無くなっていたので、令和最新版としてDocker Composeで手っ取り早く構築方法をメモっておきます。
ランナーのバージョンは2.320.0時点の記事になります。
事前に把握していた問題について
- rootユーザーでランナーを実行できない
- Dockerコンテナ上で実行できない
- コンテナジョブ内でusesを使ったステップが実行できない
上記のような面倒がありそうだったのですが、Docker Composeで構築してみたところ割とストレートにできてしまい、これといった不都合もありませんでした。ランナーのアップデートで状況が変わったのかな?
なお、今回は以下の記事を参考にさせていただいてます。
必要なもの
こちらのスニペットから一式ダウンロードできます。
- 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がリポジトリに登録されていても、ビジー状態のランナーに平気でジョブをキューしてしまい、均等に分散してくれたりしません。
ランナーグループを作成すればいい感じになる?らしいですが、前述のフォールバックと両立させるとなると一工夫必要な気がしています。
これらの問題が解決できたら、また執筆したいと思います。
以上!
コメント