GitHub Actions のセルフホステッドランナーでDockerコンテナを使用する

## 前書き

私はGitHub Actionsのワークフローをセルフホステッドランナーで運用しているのですが、

1. インストール系のアクションを使用すると古いバージョンのツールが残る
1. ログファイルが溜まる

上記2点のようなログやらファイルやらがディスクを使用することで、ランナーがディスクフルになりワークフローが実行できなくなる事象に遭遇しています。

マネージドイメージの様に毎回初期化状態になっていてくれないかな〜と思い、*「セルフホストテッドランナー上でDockerコンテナーアクション使えばホストOSにファイルを残さないようにできるんじゃないか？」* と思い立ったので検証してみることにしました。

## 結論

- コンテナーアクションの場合は実行時にコンテナを作成しワークフロー終了時に削除するため、ホストOS側に残るのはコンテナーアクションで指定したDockerイメージだけ
- セルフホステッドランナー内でDockerイメージをビルドしてローカルイメージを作成しても、必ず`docker pull`を実行するようになっているため、使用されない

## 検証環境

ハードウェア: M1 Mac
OS: mac OS Sonoma 14.2.1
ソフトウェア: Docker Desktop 4.28.0

## 検証手順

以下の手順で進めていきます。

1. 検証用セルフホステッドランナーの準備
1. セルフホステッドランナーの登録
1. GitHub Actions 実行

### 検証用セルフホステッドランナーの準備

今回はホストOSを汚したくないので、セルフホステッドランナー自体をDocker Containerで作成します。
セルフホステッドランナー内でDockerを使用するのが目的なので、dind（docker in docker）用のコンテナを作成することになります。

![arch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730831/3170350d-81e6-2d24-dc12-ee8e9fbeb4bf.png)

今回はUbuntuのイメージを使用してコンテナを作成していきます。

#### dind用Ubuntuコンテナ作成手順

1. Docker Hubの[Ubuntuの公式イメージ](https://hub.docker.com/_/ubuntu)を使用してDockerfileを作成します
    ```Dockerfile
    FROM ubuntu:22.04

    RUN apt-get update \
    && apt-get install -y init systemd
    ```
    UbuntuでDockerを使用したいので、initとsystemdを追加してsystemctlを使用できるようにしておきます。
1. Dockerイメージをビルドします
    ```Shell
    docker build -t local/ubuntu:22.04-dind .
    ```
1. イメージからコンテナを起動します
    ```Shell
    docker run -it --rm --privileged --name github-self-host-runner -d local/ubuntu:22.04-dind /sbin/init
    ```
1. コンテナ内でBashを実行します
    ```Shell
    docker exec -it github-self-host-runner bash
    ```
1. [DockerをUbuntuにインストールする手順](https://docs.docker.com/engine/install/ubuntu/)を参考にDockerをインストールして起動します
    ```Shell
    apt-get update
    apt-get install ca-certificates curl
    install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
    chmod a+r /etc/apt/keyrings/docker.asc
    echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
      $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
      tee /etc/apt/sources.list.d/docker.list > /dev/null
    apt-get update
    apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    systemctl start docker
    ```
これでコンテナの準備ができました！
今思い返すと、Dockerのインストール部分もDockerfileに書くべきでしたね…

### セルフホステッドランナーの登録

前の手順で作成したセルフホステッドランナーコンテナをGitHub Actionsに登録します。
前回の手順の続きから作業するので、セルフホステッドランナーコンテナでbashを使用している状態から手順を始めます。

1. 必須コマンドをインストールします
    ```Shell
    apt install sudo
    ```
    Ubuntuのイメージにはsudoが入っていないのでインストールします。
1. セルフホステッドランナー用のユーザーを作成します
    ```Shell
    useradd -m actions-runner -s /bin/bash
    passwd actions-runner
    gpasswd -a actions-runner docker,sudo
    ```
1. 上記手順で作成したユーザーにスイッチしてセルフホストランナーを登録します
    ```Shell
    su actions-runner
    cd
    curl -o actions-runner-linux-arm64-2.314.1.tar.gz -L https://github.com/actions/runner/releases/download/v2.314.1/actions-runner-linux-arm64-2.314.1.tar.gz
    tar xzf ./actions-runner-linux-arm64-2.314.1.tar.gz
    ./config.sh --url https://github.com/${username}/${repos} --token ${token}
    
    # サービスのインストール及び起動
    sudo ./svc.sh install
    sudo ./svc.sh start
    ```

    ![スクリーンショット 2024-03-27 23.54.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730831/58eab91c-f66b-a3d7-6249-676d88ee9422.png)
    無事にセルフホステッドランナーとして登録できました。

### GitHub Actions 実行

今回は検証用に`aws-cli`をダウンロードしてバージョンを表示するだけの単純なワークフローを作成して実行後のセルフホステッドランナーに何が残るのかを確認していきたいと思います。

そのため、[install-aws-cli-action](https://github.com/marketplace/actions/install-aws-cli-action)を使用したワークフローを作成します。

#### 検証用ワークフロー

今回は以下のワークフローを使用します。
内容は前述した通り`aws-cli`を使用するのに必要最低限なパッケージのインストールとツールのインストール&バージョンコマンドで使えることの確認という構成です。

```yaml
name: ContainerActions
on:
  workflow_dispatch:
jobs:
  container-test-job:
    runs-on: self-hosted
    container:
      image: ubuntu:22.04
      volumes:
        - my_docker_volume:/volume_mount
      options: --cpus 1
    steps:
      - run: apt update && apt install -y sudo wget unzip
        shell: bash
      - name: aws cli install test
        id: install-aws-cli
        uses: unfor19/install-aws-cli-action@master
        with:
          version: 2
          arch: arm64
      - run: aws --version
        shell: bash
```

#### Dockerコンテナーアクションの検証

それでは実際にワークフローを実行していきます。
実際に成功したワークフローが以下です。

![スクリーンショット 2024-03-29 18.56.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730831/69a2c102-e89e-7344-f345-807f5133683e.png)

ちゃんとバージョンが表示されているのでcliは使える状態になっています。

![スクリーンショット 2024-03-29 23.16.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730831/83b96e2f-e8d2-407a-4201-8472a480e1d2.png)

`Initialize containers`ステップを確認してみると、ワークフロー用のネットワークの作成及び、イメージのpullからコンテナの作成/開始まで一通り行っています。

![スクリーンショット 2024-03-29 18.59.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730831/d5bef5f2-6b29-8fe6-b47e-5d1617c70e93.png)

ユーザーが定義したワークフローの内容が終わった後は`Stop conteiners`ステップでコンテナとネットワークの削除を行ってくれています。

![スクリーンショット 2024-03-29 23.28.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730831/7156d00a-c6b5-1aaa-ca14-b6bc52245071.png)

ワークフロー実行後のセルフホステッドランナーのDockerの使用状況を確認してみたところ、
コンテナーアクションで使用するイメージが増えただけでした。
イメージの容量に気をつければビルド系のワークフローを使い続けてもディスクフルになる心配はなさそうです。

![スクリーンショット 2024-03-29 23.34.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730831/2b3cc8f2-0bef-7801-2e58-bf59e0380e6d.png)

#### ローカルのDockerイメージは使えるのか

これならセルフホステッドランナー内にDockerイメージ作っておけばそれを使えるのでは？と気になったので、それも確認してみました。

![スクリーンショット 2024-03-29 23.51.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730831/0eb10331-a278-f85b-b88d-075993313306.png)

セルフホステッドランナーコンテナ内でさらにdindイメージを作成してみました。

![スクリーンショット 2024-03-30 0.02.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730831/23ac7149-0728-a4f1-4ab3-f81b24814c9d.png)

実行してみましたが、こちらは失敗しました…

![スクリーンショット 2024-03-30 0.04.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730831/74e51972-fb2e-cf58-53cf-4c8d67b54571.png)

必ずpullコマンドを実行するため、どこかのリポジトリに入れておかないと実行できなさそうです…

セルフホステッドランナー上にローカル`Docker Registry`を構築すればいけるかな？とも思いましたが、その検証はまた別で実施しようと思います。

## 最後に

セルフホステッドランナーのホストOSを直に使うよりもディスクの管理が楽なので、
今後は積極的にコンテナーアクションを使っていこうと思いました。

最後までお読みいただきありがとうございます！
誤りがあればご連絡頂けると幸いです！