GitHub Actionsをローカル環境で実行する「act」(KLabTechBook Vol.12)
この記事は2023年11月11日から開催された技術書典15にて頒布した「KLabTechBook Vol.12」に掲載したものです。
現在開催中の技術書典17オンラインマーケットにて新刊「KLabTechBook Vol.14」を頒布(電子版無料、紙+電子 500円)しています。 また、既刊も在庫があるものは物理本をオンラインマーケットで頒布しているほか、 KLabのブログからもすべての既刊のPDFを無料DLできます。 合わせてごらんください。
GitHub Actions と act
GitHub ActionsはGitHubに統合されたCI/CDプラットフォームです。 リポジトリへのPushやPull Requestなどのイベントと関連付けて、自動テストやビルド、デプロイといったさまざまなワークフローを自動実行できます。
しかし、GitHub Actionsのワークフローを起動するには、コードをコミットしてリポジトリにPushしなければなりません。 このため、新しいワークフローを作成するときなど、動作確認のために毎回Pushする必要があり煩雑です。 また、単純なエラー、例えばタイポやコーディングスタイルのミスなどは、リポジトリにPushする前に検出したいところです。
そこで登場するのが「act」というツールです。 actを使えばGitHub Actionsのワークフローの各ジョブをローカル環境で実行でき、 リポジトリへコミットやPushをすることなく、事前にエラー検知できるようになります。 これにより、大人数での開発プロジェクトで起こりがちなジョブのランナーの枯渇も軽減できるでしょう。
この章では、GitHub Actionsをローカル環境で実行する「act」について、 基本的な使い方と制限事項、便利に使うためのTipsを紹介します。
actのインストール
Dockerの用意
actはGitHub ActionsのジョブのランナーをDockerコンテナによって再現するため、事前にDockerをインストールしておく必要があります。 Docker Desktop、またはその他のDocker環境をセットアップしてください。
actのインストール
actのインストールはパッケージマネージャを使うと簡単です。 macOSやLinuxでよく使われているHomebrew、WindowsのChocolateyやWingetの他、 多くのパッケージマネージャに登録されています1。 ご自身の環境にあわせて選ぶとよいでしょう。 リスト1とリスト2にHomebrewとChocolateyの例を示します。
▼リスト1 Homebrewによるインストール(Linux、macOS)
brew install act
▼リスト2 Chocolateyによるインストール(Windows)
choco install act-cli
また、actはGo言語で実装されているため、Goの開発環境が整っている場合はリスト3のようにインストールすることもできます。
▼リスト3 Goによるインストール
go install github.com/nektos/act@latest
コンテナイメージの準備
actがインストールできたのでさっそく動かしたいところですが、その前に使用するコンテナイメージを準備しましょう。
actによって自動生成される設定では若干不都合があるので、リスト4のように設定ファイル.actrc
を用意します2。
▼リスト4 .actrc
-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest
-P ubuntu-22.04=ghcr.io/catthehacker/ubuntu:act-22.04
-P ubuntu-20.04=ghcr.io/catthehacker/ubuntu:act-20.04
このファイルはact実行時に毎回指定するコマンドラインオプションを記載するもので、
-P
(--platform
)オプションでジョブを実行するコンテナのイメージを指定しています。
また、actの実行によってコンテナイメージをダウンロードした場合、その進捗が表示されません。
あらかじめdocker
コマンドでダウンロードしておく方が安心できます。
▼リスト5 dockerコマンドでのイメージのダウンロード
docker pull ghcr.io/catthehacker/ubuntu:act-latest
docker pull ghcr.io/catthehacker/ubuntu:act-22.04
docker pull ghcr.io/catthehacker/ubuntu:act-20.04
actの実行
ジョブの一覧
それでは、actを使ってみましょう。
最初にジョブ一覧を表示する-l
(--list
)オプションを紹介します。
リポジトリのルートディレクトリでact -l
としてみます。
▲図1 ジョブ一覧
これはKLabのOSS、WSNet2のジョブ一覧です。
リポジトリの.github/workflow
以下のyamlファイルを読み取り、一覧化してくれます。
actでジョブを実行するときは、ここに表示されているJob IDやWorkflow file、Eventsの値を指定することになるので、 このコマンドで確認するとよいでしょう。
ジョブの実行
act
をパラメータなしで実行すると、すべてのジョブが実行されます。
しかし、これではログが見にくいことに加え、ローカルでの確認ではGitHubのイベントやJob IDを指定して必要なジョブだけ実行したいケースが多いでしょう。
たとえば、WSNet2で.NETアプリのビルドとテストを行うdotnet
ジョブを実行するにはリスト6のようにします。
▼リスト6 actでdotnetジョブを実行
act pull_request -j dotnet -W .github/workflow/wsnet2-dotnet.yml
パラメータのpull_request
でイベントを指定し、-j
(--job
)オプションでジョブを指定しています。
この場合dotnet
ジョブを起動するイベントはpull_request
しか定義されていないため、イベントの指定は省略できます。
また、-W
(--workflows
)オプションは複数のyamlファイルでワークフローを定義しているときに、どのyamlファイルのジョブかを識別するために必要になります。
WSNet2ではwsnet2-dotnet.yml
の他にwsnet2-dashboard.yml
、wsnet2-server.yml
が存在するため指定が必要です。
ここで、dotnet
ジョブの中身をリスト7に示します。
▼リスト7 wsnet2-dotnet.yml
name: WSNet2 dotnet ci
on:
pull_request:
branches: [ main ]
paths:
- '.github/workflows/wsnet2-dotnet.yml'
- 'wsnet2-dotnet/**'
- 'wsnet2-unity/**'
jobs:
dotnet:
runs-on: "ubuntu-latest"
defaults:
run:
working-directory: wsnet2-dotnet
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: "6.x"
- name: dotnet build
run: dotnet build WSNet2.sln
- name: dotnet test
run: dotnet test WSNet2.sln
まず注目していただきたいのが13行目のruns-on: "ubuntu-latest"
です。
この行でジョブのランナーを指定しています。
ここで、.actrc
に記載した-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest
を思い出してください。
この-P
オプションが、runs-on
に指定されたubuntu-latest
でのジョブの実行に使うコンテナイメージの指定になっています。
こうして指定されたイメージのコンテナを起動したら、actはyamlの17行目以降に指定された各ステップを順に実行していきます。
▲図2 ジョブの実行
actは基本的にはsteps
に定義されたアクションやコマンドをそのまま実行しますが、actions/checkout
だけは例外です。
デフォルトではローカルのファイルをdocker cp
でコンテナ内に転送します3。
これによりローカルの変更をリポジトリにコミットやPushしなくても、そのまま実行されるジョブの対象とできるわけです。
▲図3 ジョブの完了
ジョブが完了すると、Job succeeded
のログが表示されてコンテナも終了します。
エラーが発生したときはコンテナが消えずに残るため、アタッチして原因を究明できます。
もしエラー時にもコンテナを削除したい場合は--rm
オプションを指定してください。
このほか詳しい使い方はユーザーガイドをご覧ください。
actの制限
ここまで紹介したように、actはDockerコンテナによってジョブの実行環境を再現します。 GitHubがホストするランナーはUbuntuだけでなくWindowsやmacOSも提供されていますが、 Dockerコンテナは基本的にはLinuxであるため、actではUbuntuのみをサポートします4。 加えて、GitHubが提供するランナーと完全に同じ環境ではないため、動かないアクションもあるかもしれません。
また、サービスコンテナやジョブのタイムアウトなどいくつか未実装の機能があります。
サービスコンテナについては、手動でコンテナを起動することで一応対処できます。
ジョブ実行コンテナのネットワークモードはhostになっているため、
サービスコンテナ起動時に-p
(--publish
)オプションでポートをホストに公開しておくことで、
ジョブ実行コンテナからもlocalhost
の該当ポートでサービスコンテナにアクセスできます。
その他のTips
ここで、actで使える便利なTipsをいくつか紹介します。
シークレットの受け渡し
GitHub上で保存したシークレットの値やGITHUB_TOKEN
は、当然ながらactからは参照できません。
これらの値を必要とするジョブを実行するには、-s
(--secret
}または--secret-file
オプションによって値を受け渡します。
このとき、コマンドラインでact -s MY_SECRET=value
のように値を指定してしまうと、
コマンド履歴ファイルなどにシークレットの値が保存されてしまう可能性があり好ましくありません。
代わりにact -s MY_SECRET
のようにして、コマンドラインでは値を指定せずにセキュアな対話インターフェイスで値を入力する方法が推奨されています5。
actでの実行ではスキップする
actで実行しているときは特定のジョブやステップをスキップしたいこともあるでしょう。
actはジョブを実行するときに環境変数ACT=true
を設定します。
これを利用して、リスト8のようにジョブやステップにif
条件文を書くことでスキップできます。
▼リスト8 actでの実行時はスキップする
jobs:
my-job:
runs-on: ubuntu-latest
steps:
- run: echo "スキップされない"
- if: ${{ !env.ACT }}
run: echo "スキップされる"
- run: echo "スキップされない"
セルフホステッドランナーへの対応
GitHub Actionsでは、自身で用意したマシンでジョブを実行するセルフホステッドランナーもサポートされています。
セルフホステッドランナーでジョブを実行するには、runs-on
にself-hosted
を指定します。
actでセルフホステッドランナーに対応するには、まずランナーとなるコンテナイメージを用意します。
そのうえで、act実行時に-P self-hosted=イメージ名
のようにコンテナイメージを指定します。
このとき、actは指定のイメージの最新版がないかオンラインのコンテナリポジトリを確認するのですが、
リポジトリ上にイメージが存在しない場合はエラーになってしまいます。
ローカルにしかないイメージを使うときは--pull=false
オプションを指定して、最新版の確認をスキップする必要があります。
docker
コマンド使用時の注意点
actで実行されるコンテナ内でもdocker
コマンドを使用できます。
ただし、接続するDockerデーモンはコンテナ内ではなくactを実行しているホストで動いているものです6。
このため、ポートなどのリソースの競合やバインドマウントするときのパスなどに注意する必要があります。
Dockerでuserns-remapを有効にしている場合
前巻 KLabTechBook Vol.11 第1章「Dockerを使うなら当然userns-remapしてるよね!」で紹介したように、
LinuxでDockerを利用するときはuserns-remap
を有効にして一般ユーザーの名前空間でコンテナを動かすことをお勧めしています。
一方、actはコンテナをホストの名前空間で実行することを要求するので、コンテナ起動時に--userns=host
オプションを指定する必要があります。
actでのジョブ実行時のオプションに--container-options --userns=host
を追加することでこれを実現できます。
この設定を.actrc
ファイルに記載しておくとよいでしょう。
おわりに
この章では、GitHub Actionsをローカル環境で実行する「act」というツールについて、基本的な使い方を紹介しました。
GitHub Actionsはそれ自体でも十分すぎるほど強力なツールですが、 actを活用することでより効率的に使用できるでしょう。 ぜひ活用してみてください。
コラム: デフォルトのコンテナイメージ
コンテナイメージを何も指定せずにジョブを実行しようとすると、 図4のようにデフォルトのコンテナイメージを選択する画面が表示されます。
▲図4 デフォルトイメージの選択画面
act version 0.2.52において、この表示内容は古く、実際のイメージと乖離しています。
- Large
- 利用されうるほぼすべてのツールがインストールされていますが、サイズは20GBどころか50GB以上あります。 また現在はUbuntu 20.04と22.04がサポートされています。
- Medium
- アクションの起動に必要なツールのみインストールしてサイズは1.5GB以下に抑えられています。ほとんどのアクションが動作します。
- Micro
- 表示のとおり、アクションを起動するためのNode.jsだけのイメージです。サイズも200MB未満です。
これらのイメージはDocker Hubにホストされています。
Large | catthehacker/ubuntu:full-latest など |
Medium | catthehacker/ubuntu:act-latest など |
Micro | node:16-buster-slim など |
actはジョブ実行時に最新のイメージがあるかを確認して自動的にpullするのですが、
このときDocker Hubのダウンロード率制限に引っかかることがあります。
catthehacker/ubuntu
のイメージと同じものがGitHubコンテナレジストリにも登録されているので、
ghcr.io/catthehacker/ubuntu
のイメージを指定することで、この制限を回避できます。
-
Homebrew、MacPorts、Chocolatey、Scoop、Winget、AUR、COPR、Nix など ↩
-
LinuxやmacOSでは
$HOME
(つまり/home/ユーザ名/
)、Windowsでは%USERPROFILE%
(つまりC:\USER\ユーザ名\
)に配置します ↩ -
-b
(--bind
)オプションを指定すると、バインドマウントによってファイルを同期するようにできます。 ↩ -
筆者は試していませんが、実行環境が整っていればWindowsコンテナを使用してWindowsランナーを再現できるかもしれません。 ↩
-
このとき環境変数@{MY_SECRET}が定義されているとそちらが優先されることに注意が必要です。 ↩
-
ホストの
/var/run/docker.sock
がコンテナにバインドマウントされています。 ↩