🐧

act を使ってローカルマシンで CI/CD:Linux 使い(略)Advent Calendar 2024

2024/12/24に公開

はじめに

これは「Linux 使いになりたい人のための Advent Calendar 2024」の記事です。

筆者は、Web エンジニアを志望する人には、セルフホスト Git サービスを稼働させて利用することをオススメしています。もし Git を使ったことがないなら、Git を学ぶときに、セルフホスト Git サービスを稼働させることも視野に含めながら学習するのが効率的だと考えています。

セルフホスト Git サービスを稼働させると良い理由については、これまでもいくつか説明してきていますが、個人的に一番大きかったのは、個人開発でも CI/CD 環境が必須となる時代になっていると感じたからです。

そのため、個人開発で使える CI/CD 環境について、ここまで紹介してきたように、いろいろと調べてきたのですが、最近は act を採用するのも良いかもしれないと検討しているところです。

今回は、ローカルマシンで CI/CD を実行可能とする act について紹介します。

act を使ってローカルマシンで CI/CD

ここまで、GitBucket や GitLab で CI/CD 環境を用意する方法について紹介してきました。実際に動かすことで、CI/CD(継続的インテグレーションと継続的デリバリー)とはどういうものか、具体的なイメージが持てるようになったはずです。

ここで、世の中で普及している GitHub での CI/CD 環境としては「GitHub Actions」というものがあります。これは、GitHub でビルド、テスト、デプロイのパイプラインを自動化できる CI/CD のプラットフォームになります。

GitHub Actions では、Git リポジトリの .github/workflows/ ディレクトリーにあるワークフローファイルを使ってパイプラインの自動処理を実行する仕組みが導入されています。GitLab CI/CD の .gitlab-ci.yml ファイルと似たような感じです。

このワークフローファイルをローカルマシンでも実行可能とするツールが act です。次の URL で公開されています。

公式サイトでの act の謳い文句は Run your GitHub Actions locally! です。次の2つの理由で act は開発されているとのこと。

  • 高速なフィードバック
  • ローカルのタスクランナー

GitHub Actions 向けの処理を開発するにあたっては、ローカルマシンで、その処理を実行できる環境があった方が効率よく開発ができます。act を使うと、GitHub Actions 向けの処理について高速なフィードバックを得ることができます。

また、GitHub Actions 向けに処理の自動化ができたなら、それをローカルマシンでも再利用したくなるはずです。同じ処理をするコードについて、ローカルマシン環境と CI/CD 環境とで、別々に用意するのは無駄に感じることでしょう。act を使うと、GitHub Actions 用のワークフローファイルをローカルマシンで利用できるので、ローカルのタスクランナーとして活用可能となります。

なお、act を使うには Docker Engine がインストールされたマシンが必要なので用意しておいてください。ここでは Docker Engine のインストール方法については紹介しません。

用意するファイルのディレクトリー構成

ここで用意するファイルのディレクトリー構成は次のようになります。

act/
├── compose.yaml
└── script/
    ├── container/
    │   └── run.sh
    ├── install.sh
    └── setup_demo.sh

なお、ここでは act${ACT_DIR} と表記します。

act 試用のための Docker コンテナー

最初に、act 試用のための Docker コンテナーを用意します。${ACT_DIR}/compose.yaml は次のようになります。

name: act

services:
  act:
    image: ubuntu:24.04
    container_name: act
    hostname: act
    tty: true
    entrypoint: /bin/bash
    volumes:
      - type: bind
        source: /var/run/docker.sock
        target: /var/run/docker.sock

Docker を使うため、/var/run/docker.sock をバインドマウントしている点に注意してください。

compose.yaml を用意したら起動します。

cd ${ACT_DIR}
docker compose up -d

それから docker compose exec コマンドで act コンテナーへアタッチします。

docker compose -p act exec act bash

ここで、compose.yaml を使わずに docker container コマンドを使って、act コンテナーへアタッチするところまで一気に実行することもできます。

docker container run --rm -it \
    --name act \
    --hostname act \
    --volume /var/run/docker.sock:/var/run/docker.sock \
    ubuntu:24.04 bash

このコマンドは Docker に慣れてくると compose.yaml から簡単に変換して実行できるようになります。そのため、筆者はできるだけ compose.yaml で宣言的にコンテナーを定義しておいて、実際にコンテナーの起動が必要な場面で docker compose コマンドを使うか、docker container コマンドを使うか決めています。

入力が面倒なのでスクリプトファイル ${ACT_DIR}/script/container/run.sh にしておいても良いでしょう。

act のインストール

act をインストールするには、リリースされているバイナリーファイルをダウンロードするのが単純です。これを実行するスクリプトが公式サイトで用意されているので、これを使います。

Docker イメージの ubuntu:24.04 では、このファイルを実行するにあたって必要な curlgit コマンドが足りないので、apt コマンドでインストールします。また、今回作業時に tree コマンドも使うので、それもインストールします。

これらの作業をスクリプト ${ACT_DIR}/script/install.sh にすると、次のようなスクリプトになります。

#!/bin/sh

SCRIPT_URL=https://raw.githubusercontent.com/nektos/act/master/install.sh
apt-get update && apt-get -y install curl git tree
curl --proto '=https' --tlsv1.2 -sSf ${SCRIPT_URL} | bash

スクリプトを用意したらコンテナーへコピーして、コンテナー内で実行します。

cd ${ACT_DIR}
docker compose -p act cp ./script/install.sh act:/usr/local/src/
docker compose -p act exec act sh /usr/local/src/install.sh

インストールができると、act:/usr/bin/actact コマンドがインストールされます。次のように act コンテナー内で確認して実行してみましょう。

$ docker compose -p act exec act which act
/usr/bin/act
$ docker compose -p act exec act /usr/bin/act --version
act version 0.2.70

デモ用リポジトリのクローン

act コマンドの動作確認するには、デモ用リポジトリを利用します。具体的には act の公式サイトで紹介されている https://github.com/cplee/github-actions-demo にあるものを使います。これには Node.js のプロジェクトで使われる GitHub Actions 用のワークフローファイルの雛形が含まれています。

デモ用リポジトリのクローンをしてセットアップするスクリプトを ${ACT_DIR}/script/setup_demo.sh に次の内容で用意します。

#!/bin/sh

git -C /usr/local/src/ clone \
    https://github.com/cplee/github-actions-demo.git

スクリプトを用意したらコンテナーへコピーして、コンテナー内で実行します。

cd ${ACT_DIR}
docker compose -p act cp ./script/setup_demo.sh act:/usr/local/src/
docker compose -p act exec act sh /usr/local/src/setup_demo.sh

クローンができたら、tree コマンドでファイルの確認をしておきます。

docker compose -p act exec \
    --workdir=/usr/local/src/github-actions-demo act \
    tree -aI .git

実行結果は次のようになります。

.
|-- .eslintrc.yml
|-- .github
|   `-- workflows
|       `-- main.yml
|-- .gitignore
|-- LICENSE
|-- README.md
|-- index.js
|-- package-lock.json
|-- package.json
`-- tests
    `-- test-app.js

4 directories, 9 files

デモの実行

それでは、デモの実行をしてみましょう。

まず、どんな処理が実行されるのか、.github/workflows/main.yml の内容を確認します。

docker compose -p act exec \
    --workdir=/usr/local/src/github-actions-demo act \
    cat .github/workflows/main.yml

実行結果は次のようになります。

name: CI
on: push

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-node@v1
    - run: npm install
    - run: npm test

ここではジョブの test が用意されていて、実行環境は runs-on: ubuntu-latest と指定されています。steps: に実行する処理のステップが指定されています。各ステップについては、uses: を使って実行するアクション、run: を使って実行するコマンドが指定されています。

このことから、リポジトリからコードをチェックアウトし、Node.js 環境を用意し、npm install を実行、npm test を実行というステップを踏むことがわかります。

実行してみましょう。

docker compose -p act exec \
    --workdir=/usr/local/src/github-actions-demo act \
    act

使用する Docker イメージについて、LargeMediumMicro から選択するようにプロンプトが次のように表示されます。矢印キーの上下で > が移動するので、これで選択してから Enter キーで確定できます。ここではサイズが小さい Micro を指定します。

INFO[0000] Using docker host 'unix:///var/run/docker.sock' (略)
? Please choose the default image you want to use with act:
  - Large size image: ca. 17GB download + 53.1GB storage (略)
  - Medium size image: ~500MB (略)
  - Micro size image: <200MB (略)

Default image and other options can be changed manually in /root/.config/act/actrc (略)
  Large
  Medium
> Micro

すると、main.yml に指定した処理が実行されます。

[CI/test] 🚀  Start image=node:16-buster-slim
[CI/test]   🐳  docker pull image=node:16-buster-slim platform= username= forcePull=true
(略)
[CI/test]   ☁  git clone 'https://github.com/actions/setup-node' # ref=v1
[CI/test] ⭐ Run Main actions/checkout@v2
[CI/test]   🐳  docker cp src=/usr/local/src/github-actions-demo/. dst=/usr/local/src/github-actions-demo
[CI/test]   ✅  Success - Main actions/checkout@v2
[CI/test] ⭐ Run Main actions/setup-node@v1
[CI/test]   🐳  docker cp src=/root/.cache/act/actions-setup-node@v1/ dst=/var/run/act/actions/actions-setup-node@v1/
[CI/test]   🐳  docker exec cmd=[/usr/local/bin/node /var/run/act/actions/actions-setup-node@v1/dist/index.js] user= workdir=
(略)
[CI/test]   ✅  Success - Main actions/setup-node@v1
[CI/test]   ⚙  ::add-path:: /opt/hostedtoolcache/node/10.24.1/x64/bin
[CI/test] ⭐ Run Main npm install
[CI/test]   🐳  docker exec cmd=[bash -e /var/run/act/workflow/2] user= workdir=
| added 280 packages from 643 contributors and audited 280 packages in 2.989s
(略)
|   run `npm audit fix` to fix them, or `npm audit` for details
[CI/test]   ✅  Success - Main npm install
[CI/test] ⭐ Run Main npm test
[CI/test]   🐳  docker exec cmd=[bash -e /var/run/act/workflow/3] user= workdir=
(略)
|   1 passing (16ms)
| 
[CI/test]   ✅  Success - Main npm test
[CI/test] Cleaning up container for job test
[CI/test] 🏁  Job succeeded

使用する Docker イメージの指定

act コマンド実行時に Micro を指定した後に、/root/.config/act/actrc ファイルが作成されているので、中身を確認すると、次のようになっていました。

-P ubuntu-latest=node:16-buster-slim
-P ubuntu-22.04=node:16-bullseye-slim
-P ubuntu-20.04=node:16-buster-slim
-P ubuntu-18.04=node:16-buster-slim

このファイルで main.yml 内の runs-on: ubuntu-latest で指定したプラットフォームに対して実際に使用する Docker イメージを指定できるようです。

参考までに、Medium を指定した場合の /root/.config/act/actrc は次のようになっていました。

-P ubuntu-latest=catthehacker/ubuntu:act-latest
-P ubuntu-22.04=catthehacker/ubuntu:act-22.04
-P ubuntu-20.04=catthehacker/ubuntu:act-20.04
-P ubuntu-18.04=catthehacker/ubuntu:act-18.04

こちらについては、catthehacker/docker_images: GitHub を参照すると、次のタグが紹介されています。Docker Hub ではなく、GitHub の Docker レジストラを使うなら、修正しても良いでしょう。

  • ghcr.io/catthehacker/ubuntu:act-20.04
  • ghcr.io/catthehacker/ubuntu:act-22.04
  • ghcr.io/catthehacker/ubuntu:act-latest

使用する Docker イメージは、/root/.config/act/actrc で決まりますが、自分が作成したカスタムイメージを使うこともできます。その場合は、act コマンド実行時に -P オプションで指定します。 actrc ファイルにあるのと同じようにすれば良いです。

なお、Docker レジストラに push していない、ローカルでビルドしただけの Docker イメージを使うには --pull オプションを指定すれば良さそうです。

おわりに

act コマンドと Docker Engine 環境をローカルマシンに用意すると、GitHub Actions をローカルマシンでも実行できることがわかりました。なお、Gitea Act Runner や Forgejo Runner では、この act をベースとした CI/CD 用ランナーが採用されています。

筆者は GitHub、Gitea、Forgejo で使えるワークフローファイルがローカルマシンでも利用できるのなら、ローカルマシンでの CI/CD に act コマンドを採用するのは良さそうだと考えています。まだきちんと確認していませんが、GitBucket + CI Plugin でも利用できそうな印象です。

少し気になるのは git clone 'https://github.com/actions/setup-node' のように、uses: で指定されたアクションは git clone で取得している点です。ローカルマシンでは毎回 git clone がされることはないでしょうが、GitBucket + CI Plugin などで使用する場合には何か対策が必要だったりするかもしれません。

いずれにせよ、今後の CI/CD のワークフローファイルについては、デファクトスタンダードが何になるのかわからないところです。ですから、こうやって、いろいろなワークフローファイルを見ておくことは良いことだと考えています。

Discussion