見出し画像

self-hosted runnerをDockerイメージにする

はじめに

はじめまして。DAAE開発1グループの中本です。
self-hosted runnerをDockerイメージにしてみたので紹介します。

self-hosted runnerとは

一言で言うと、GitHub Actionsの実行環境を自分で用意できる機能です。
通常、GitHub ActionsのワークフローはGitHubが用意するホストランナー上で実行されます。GitHubのホストランナーは事前準備なしで使える一方、実行環境のカスタマイズ等はできません。
自社サーバー上でCI/CD実行したい、実行環境のスペックをもっと上げたい、などの要件があれば、自前で用意したサーバーにself-hosted runnerを構築することで実現できます。

そんなself-hosted runnerをコンテナ環境でも動かせるとCI/CD環境の選択肢がもっと広がるよね、ということでDockerイメージにしてみました。

self-hosted runnerをubuntu 22.04に構築する

まずはGitHubの手順通りにself-hosted runnerを構築してみます。

  • GitHub -> Settings -> Actions -> Runnerと移動し、 「New self-hosted runner」 をクリック

  • Create self-hosted runner で「Linux」 「x64(※)」を選択
    ※M1 Macの場合は「ARM64」と読み替えてください

手順の確認はコンテナ内で行います。コンテナのベースイメージはubuntu:22.04にしました。
手順でcurlコマンドが使われているので、Dockerfileでインストールしておきます。

  • Dockerfile

FROM ubuntu:22.04
RUN apt-get update && \
    apt-get install \
    curl \
    -y

Dockerfileをビルドし、コンテナに入ります。

$ docker build -t self-hosted-runner .
$ docker run --rm -it self-hosted-runner bash
#

このあとはGitHubの手順通りにコマンドを叩いていきます。

# mkdir actions-runner && cd actions-runner
#
# curl -o actions-runner-linux-x64-2.299.1.tar.gz -L https://github.com/actions/runner/releases/download/v2.299.1/actions-runner-linux-x64-2.299.1.tar.gz
・・・
#
# echo "147c14700c6cb997421b9a239c012197f11ea9854cd901ee88ead6fe73a72c74  actions-runner-linux-x64-2.299.1.tar.gz" | shasum -a 256 -c
bash: shasum: command not found

さっそくエラーが出ました。 「shasum -a 256」を「sha256sum」に置き換えて実行します。

# echo "147c14700c6cb997421b9a239c012197f11ea9854cd901ee88ead6fe73a72c74  actions-runner-linux-x64-2.299.1.tar.gz" | sha256sum -c
actions-runner-linux-x64-2.299.1.tar.gz: OK
# 
# tar xzf ./actions-runner-linux-x64-2.299.1.tar.gz
# 

以上で、Downloadはすんなりできました。
続いてConfigureに進みます。

# ./config.sh --url https://github.com/{オーナー名}/{リポジトリ名} --token {トークン}
Must not run with sudo

エラーが出ました。config.shを確認してみます。

# cat config.sh
・・・
if [ $user_id -eq 0 -a -z "$RUNNER_ALLOW_RUNASROOT" ]; then
    echo "Must not run with sudo"
    exit 1
fi
・・・ 

環境変数RUNNER_ALLOW_RUNASROOTを設定するとこのエラーを回避できそうです。

# export RUNNER_ALLOW_RUNASROOT=1
#

もう一度、config.shを実行します。

# ./config.sh --url https://github.com/{オーナー名}/{リポジトリ名} --token {トークン}
Libicu's dependencies is missing for Dotnet Core 6.0
Execute sudo ./bin/installdependencies.sh to install any missing Dotnet Core 6.0 dependencies.

またエラーが出ました。エラーメッセージのとおりinstalldependencies.shを叩きます。

# ./bin/installdependencies.sh
・・・
-----------------------------
 Finish Install Dependencies
-----------------------------

さらにもう一度、config.shを実行します。

# ./config.sh --url https://github.com/{オーナー名}/{リポジトリ名} --token {トークン}

--------------------------------------------------------------------------------
|        ____ _ _   _   _       _          _        _   _                      |
|       / ___(_) |_| | | |_   _| |__      / \   ___| |_(_) ___  _ __  ___      |
|      | |  _| | __| |_| | | | | '_ \    / _ \ / __| __| |/ _ \| '_ \/ __|     |
|      | |_| | | |_|  _  | |_| | |_) |  / ___ \ (__| |_| | (_) | | | \__ \     |
|       \____|_|\__|_| |_|\__,_|_.__/  /_/   \_\___|\__|_|\___/|_| |_|___/     |
|                                                                              |
|                       Self-hosted runner registration                        |
|                                                                              |
--------------------------------------------------------------------------------

# Authentication


√ Connected to GitHub

# Runner Registration

Enter the name of the runner group to add this runner to: [press Enter for Default] 

Enter the name of runner: [press Enter for b18b73aa37e7] 

This runner will have the following labels: 'self-hosted', 'Linux', 'X64' 
Enter any additional labels (ex. label-1,label-2): [press Enter to skip] 

√ Runner successfully added
√ Runner connection is good

# Runner settings

Enter name of work folder: [press Enter for _work] 

√ Settings Saved.

今度はランナーの設定ができました!
ランナー名などを対話で設定するプロンプトがいくつか出ましたが、全てデフォルトのままEnterしました。

GitHubにもランナーが設定されました。

続いてランナーを起動します。

# ./run.sh

√ Connected to GitHub

Current runner version: '2.299.1'
2022-12-06 23:30:02Z: Listening for Jobs

ランナー起動後はGitHubのランナーステータスがidleになりました。

最後に、ランナー上でサンプルワークフローが動作するかを確認します。

  • サンプルワークフロー

name: self-hosted runner🚀
on: [push]

jobs:
  build:
    runs-on: self-hosted
    steps:
      - uses: actions/checkout@v2
      - run: echo self-hosted runner working🎉

GitHubの手順にもありますがruns-on: self-hosted とするのがポイントです。

  • 実行結果

サンプルワークフローが動きました!
以上で手順の確認が出来たので、run.shをCtrl + Cで中断し、コンテナからexitします。

self-hosted runnerをDockerイメージにする

これまで確認した手順を元に、self-hosted runnerをDockerイメージにしたいと思います。
config.sh実行より前の手順は、Dockerfileにそのまま記述できます。

  • Dockerfile

FROM ubuntu:22.04

RUN apt-get update && \
    apt-get install \
    curl \
    -y
RUN mkdir actions-runner && cd actions-runner && \
    curl -o actions-runner-linux-x64-2.299.1.tar.gz -L \
    https://github.com/actions/runner/releases/download/v2.299.1/actions-runner-linux-x64-2.299.1.tar.gz && \
    echo "147c14700c6cb997421b9a239c012197f11ea9854cd901ee88ead6fe73a72c74  actions-runner-linux-x64-2.299.1.tar.gz" | sha256sum -c - && \
    tar xzf ./actions-runner-linux-x64-2.299.1.tar.gz && \
    ./bin/installdependencies.sh

あとは、config.shの実行をどうするかです。
config.shの--tokenオプションに設定するランナー設定用トークンの取得や、対話で設定するプロンプトへの対応が必要です。

ここはシェルスクリプトを作成します。
ランナー設定用トークンはregistration-token APIから取得できそうです。
対話で設定するプロンプトはexpectコマンドで対応できそうです。

最終的に、以下のシェルスクリプトが出来ました。これをexec-runner.shと名前を付けて保存します。

  • exec-runner.sh

#!/bin/bash

# repo scopeのあるアクセストークン
if [ -z "${GITHUB_ACCESS_TOKEN}" ]; then
  echo "GITHUB_ACCESS_TOKEN must be set" 1>&2
  exit 1
fi

if [ -z "${GITHUB_API_DOMAIN}" ]; then
  echo "GITHUB_API_DOMAIN must be set" 1>&2
  exit 1
fi

if [ -z "${GITHUB_DOMAIN}" ]; then
  echo "GITHUB_DOMAIN must be set" 1>&2
  exit 1
fi

if [ -z "${GITHUB_REPOSITORY_NAME}" ]; then
  echo "GITHUB_REPOSITORY_NAME must be set" 1>&2
  exit 1
fi

if [ -z "${GITHUB_REPOSITORY_OWNER}" ]; then
  echo "GITHUB_REPOSITORY_OWNER must be set" 1>&2
  exit 1
fi

# ランナー設定用トークンを取得する
export GITHUB_RUNNER_REGISTRATION_TOKEN=$(curl \
    -X POST \
    -H "Accept: application/vnd.github+json" \
    -H "Authorization: Bearer $GITHUB_ACCESS_TOKEN" \
    -H "X-GitHub-Api-Version: 2022-11-28" \
    https://$GITHUB_API_DOMAIN/repos/$GITHUB_REPOSITORY_OWNER/$GITHUB_REPOSITORY_NAME/actions/runners/registration-token \
    | jq .token | sed -e 's/"//g')

export RUNNER_ALLOW_RUNASROOT=1
runnerName=`hostname`

# config.shを実行する
expect -c "
set timeout 10
log_user 0
spawn ./config.sh --url https://${GITHUB_DOMAIN}/${GITHUB_REPOSITORY_OWNER}/${GITHUB_REPOSITORY_NAME} --token ${GITHUB_RUNNER_REGISTRATION_TOKEN} --ephemeral
log_user 1
expect  -re \"Enter the name of the runner group to add this runner to:.*\"
send \"\n\"
expect  -re \"Enter the name of runner:.*\"
send \"${runnerName}\n\"
expect  -re \"Enter any additional labels.*\"
send \"\n\"
expect  -re \"Enter name of work folder:.*\"
send \"\n\"
expect \"#\"
exit 0
"

./run.sh

補足として、config.sh実行時にephemeralオプションを付けています。
このオプションを付けるとジョブ終了時にGitHubのランナー設定も削除されます。
1回限りのCI/CD環境が欲しい場合に付けると便利なオプションです。

exec-runner.sh用の環境変数定義ファイルも用意します。

  • env.txt

GITHUB_ACCESS_TOKEN=(access token with repo scope)
GITHUB_REPOSITORY_OWNER=(repository owner name)
GITHUB_REPOSITORY_NAME=(repository name)
GITHUB_DOMAIN=github.com
GITHUB_API_DOMAIN=api.github.com

exec-runner.shをDockerfileのCMDで実行します。

  • Dockerfile

FROM ubuntu:22.04

RUN apt-get update && \
    apt-get install \
    curl \
    expect \
    jq \
    -y

RUN mkdir actions-runner && cd actions-runner && \
    curl -o actions-runner-linux-x64-2.299.1.tar.gz -L \
    https://github.com/actions/runner/releases/download/v2.299.1/actions-runner-linux-x64-2.299.1.tar.gz && \
    echo "147c14700c6cb997421b9a239c012197f11ea9854cd901ee88ead6fe73a72c74  actions-runner-linux-x64-2.299.1.tar.gz" | sha256sum -c - && \
    tar xzf ./actions-runner-linux-x64-2.299.1.tar.gz && \
    ./bin/installdependencies.sh

COPY exec-runner.sh /actions-runner/exec-runner.sh
RUN chmod +x /actions-runner/exec-runner.sh
WORKDIR /actions-runner

CMD ["/actions-runner/exec-runner.sh"]

これでDockerfileが完成しました!
それではself-hosted runnerコンテナを立ち上げてみます。

# docker build -t self-hosted-runner .
# docker run --rm -it --env-file=./env.txt self-hosted-runner
・・・

self-hosted runnerが立ち上がりました。
先ほどのサンプルワークフローをもう一度実行してみます。

・・・動きました!
サンプルワークフロー終了後、ephemeralオプションによりGitHubからランナー設定が削除されていました。

これにてself-hosted runnerをDockerイメージにすることができました!

参考情報

About self-hosted runners
Self-hosted runners

\もっと身近にもっとリアルに!DAAE公式Twitter/


\明日の記事もお楽しみに!/


執筆者プロフィール: 中本 浩太
DAAE部所属のエンジニア。現在はReact、NestJS、AWS等でWebシステムの開発をしている。
趣味は映画鑑賞とダイビング。好きな食べ物はたこ焼き。

お問合せはお気軽に
https://service.shiftinc.jp/contact/

SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/

SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/

SHIFTの導入事例
https://service.shiftinc.jp/case/

お役立ち資料はこちら
https://service.shiftinc.jp/resources/

SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/