🦋

GitHub Actions のデバッグをローカルで行う

2021/06/05に公開

概要

GitHub Actions で GitHub ホストランナーを使用する場合、パブリックポジトリは無料ですがプライベートリポジトリは従量課金(無料枠あり)です。
ワークフローを編集する際にデバッグしていると結構な時間を消費してしまいます。
そこでデバッグ時は GitHub ホストランナーを使わずに無料で実行する方法を 3 種類紹介します。

nektos/act

言わずと知れたローカル実行ツールです。
すべてを再現することはできませんがコミットを増やさずにデバッグができます。
https://github.com/nektos/act

注意点

  • ubuntu-* のみサポート
  • ソフトウェアは指定する Docker イメージ依存、デフォルトのイメージだと色々足りないので -P で指定
  • secrets.GITHUB_TOKEN が未定義なので Personal Access Token を発行し設定が必要
  • サービスコンテナ services が使えない
  • $ACT を使うと本番との差異が大きくなる

ubuntu-* しかサポートされていませんが Docker コンテナ上で動かしてくれるのでローカル PC が Windows や Mac でも ubuntu-* のワークフローが動かせるのはメリット。

セルフホストランナー

ローカル PC に セルフホストランナー をインストールして利用します。
コミットは増えてしまいますが最後に git rebase -i したらいいでしょう。
正式なランナーなので完全に動作します。

runs-on を一時的に書き換えて [ self-hosted ] を指定します。
既存のセルフホストランナーがある場合はラベルを付けると区別できます。

.github/workflows/build.yml
jobs:
  build:
    runs-on: [ self-hosted, pc ]

注意点

  • runs-on に設定している OS とローカル PC の OS が異なると実行できないコマンドが多い
  • ソフトウェアはインストールする必要がある
  • ランナー登録用のトークンまたは Personal Access Token を発行し設定が必要
  • Windows は PowerShell の実行ポリシーを変更する必要がある
  • ランナーにある制約はそのまま(uses での Docker コンテナアクションあるいは services でのサービスコンテナを使うなら Linux が必要
  • OS が同じでもディストリビューションが一致しているとは限らない

ランナーの制約を受けてしまうのが曲者でローカル PC が Windows や Mac だと ubuntu-* のワークフローを動かせないのがデメリット。

Windows

Windows の場合デフォルトシェルが PowerShell になっています。
スクリプトの実行が許可されていないので 実行ポリシー を変更する必要があります。

現在の値を確認
Get-ExecutionPolicy
ポリシーを変更(要管理者権限)
Set-ExecutionPolicy -ExecutionPolicy Bypass

デバッグが終わったら元の値に戻しておきましょう。

セルフホストランナー in Docker

前項のデメリットを解消できないか試みます。
ランナーを含んだ Docker イメージが公開されているのでこちらを利用します。

myoung34/github-runner

Ubuntu ベースのようなので GitHub ホストランナーの ubuntu-* との差異は少なそうです。
Enterprise にも対応してます。

docker-compose.yml を作成して実行します。
Docker in Docker になるのでホストの Docker daemon を共有しているようですね。
追加のソフトウェアをインストールしたい場合は Dockerfile を定義して imagebuild に変更しましょう。

docker-compose.yml
version: "3.9"

services:
  runner:
    image: myoung34/github-runner:latest
    environment:
      REPO_URL: https://github.com/<org>/<repo>
      ACCESS_TOKEN: <Personal Access Token>
      RUNNER_WORKDIR: /tmp/runner/work
      LABELS: pc
    # SELinux システムでは docker コンテナが
    # 他の docker コンテナを管理するのを許可するために必要
    # security_opt:
    #   - label:disable
    volumes:
      - '/var/run/docker.sock:/var/run/docker.sock'
      - '/tmp/runner:/tmp/runner'
      # docker-in-docker では同じパスがホストとコンテナ内に必要
      # docker の mgmt コマンドは docker の外側で走るがパスは内側を期待する

各項目を自分の環境に合わせて書き換えます。
その他オプションは公式ドキュメントを参照してください。
どこかへコミットするなら .env に定義して環境変数で参照しましょう。

実行コマンド
docker-compose run --rm runner
# or
docker-compose up -d

後者でバックグラウンド実行する場合は docker-compose logs -f runner でログを確認できます。

Windows の Hyper-V モードや Mac の場合 File Sharing の設定が必要な場合があります。
ホストの Docker -> Preferences... -> Resources -> File Sharing に /tmp がなければ足してください。

コンテナにインストールされている Docker バージョン。

バージョン情報
root@c58ce4c18ba7:/actions-runner# grep PRETTY_NAME /etc/os-release
PRETTY_NAME="Ubuntu 20.04.2 LTS"
root@94591e171112:/actions-runner# docker -v
Docker version 20.10.7, build f0df350
root@94591e171112:/actions-runner# docker-compose -v
docker-compose version 1.27.4, build 40524192

Ctrl+C または docker-compose down で終了します。
自動的にランナーの登録を解除してくれます。

Docker コンテナアクションや docker コマンドは動かせるのですが、サービスコンテナを動かすことはできないようで Initialize containers で失敗します。
ランナーのロジックで弾いてるみたいですね。(このロジック削除してほしい…)

Check whether we are inside a container.
Our container feature requires to map working directory from host to the container.
If we are already inside a container, we will not able to find out the real working direcotry path on the host.
https://github.com/actions/runner/blob/ebadce7958e3f1651b7d956c6a4969e2fc4bd48f/src/Runner.Worker/ContainerOperationProvider.cs#L54-L70

tcardonne/github-runner

tcardonne/github-runner

Ubuntu ベースのようなので GitHub ホストランナーの ubuntu-* との差異は少なそうです。
myoung34/github-runner と比べると機能が少なかったりバージョンが古かったりするようです。

docker-compose.yml
version: "3.9"

services:
    runner:
      image: tcardonne/github-runner:latest
      environment:
        RUNNER_REPOSITORY_URL: ${RUNNER_REPOSITORY_URL}
        GITHUB_ACCESS_TOKEN: ${GITHUB_ACCESS_TOKEN}
        RUNNER_LABELS: pc
      volumes:
        - /var/run/docker.sock:/var/run/docker.sock

${***} の部分を自分の環境に合わせて書き換えます。
.env に定義しても良いですしデバッグ用途であれば直接書き換えてしまっても良いでしょう。

Mac の場合これだけだとコンテナ内で docker コマンドを実行したときにエラーになります。
ローカルで動かしている Docker の File Sharing の設定に /home/runner を追加します。

root@31e878a24a08:/home/runner# docker run --rm -it -v $PWD:/app composer help   
docker: Error response from daemon: Mounts denied: 
The path /home/runner is not shared from the host and is not known to Docker.
You can configure shared paths from Docker -> Preferences... -> Resources -> File Sharing.
See https://docs.docker.com/docker-for-mac for more info.
ERRO[0000] error waiting for container: context canceled

コンテナ内で使用できる Docker のバージョンは少し古いみたいですね。

バージョン情報
root@bb8b1afef2f7:/home/runner# grep PRETTY_NAME /etc/os-release 
PRETTY_NAME="Ubuntu 20.04.1 LTS"
root@bb8b1afef2f7:/home/runner# docker -v
Docker version 19.03.13, build 4484c46d9d
root@bb8b1afef2f7:/home/runner# docker-compose -v
docker-compose version 1.27.4, build 40524192

Ctrl+C で終了した際にランナーの登録が解除されないので手動で強制削除する必要があります。

注意点

  • ランナー登録用のトークンまたは Personal Access Token を発行し設定が必要
  • サービスコンテナ services が使えない
  • Windows や Mac も可能かもしれませんがイメージの自作からしないといけないので大変そう
  • Windows ホストで WSL 1 モードの場合 File Sharing ができず docker-compose.yml に定義している /tmp/runner:/tmp/runner がマウントされない。そのためディレクトリが生成されずマウントを利用する Docker コンテナアクションが動作しない(Hyper-V モードや WSL 2 モードなら動作しそうだが未検証。Mac だと正常に動作する)

その他注意点

GitHub ホストランナー以外の環境では一部のアクションが動かないことがあります。
(GitHub ホストランナーに依存した絶対パスを使ってしまっているケース等、アクション側のバグである可能性あり)

まとめ

機能 nektos/act セルフ
ホストランナー
セルフ
ホストランナー
in Docker
GitHub
ホストランナー
OS runs-on Linux Linux
Win
Mac
Linux Linux
Win
Mac
ローカル PC と
異なる OS runs-on
⭕️ ⭕️ ⭕️
コミット&プッシュ 不要 必要 必要 必要
JavaScript アクション
uses
⭕️ ⭕️ ⭕️ ⭕️
Docker コンテナアクション
uses
⭕️ ⭕️ Linux
❌ Win, Mac
⭕️ ⭕️ Linux
❌ Win, Mac
サービスコンテナ services ⭕️ Linux
❌ Win, Mac
⭕️ Linux
❌ Win, Mac
docker コマンド
docker-compose コマンド
⭕️ ⭕️ ⭕️ ⭕️
GitHub ホストランナー
との差異
-
料金 無料 無料 無料 従量課金

Discussion