🍓

Raspberry Pi OS で構築する CI/CD(Forgejo Runner) - Linux 使いになりたい人向け

2024/03/03に公開

はじめに

この記事は Forgejo Runner という CI/CD(Continuous Integration / Continuous Delivery)用のソフトウェアについて説明しています。

Forgejo Runner は Git リポジトリ管理システム Forgejo と簡単に連携させることができるので、手軽に CI/CD 環境を構築したいと考えている場合に使ってみることを検討してみると良いでしょう。ただし、現時点ではアルファバージョンのものなので、個人で不具合も含めて楽しみながら使うものだと思ってください。

ここでは Raspberry Pi 5 の Raspberry Pi OS にインストールして動かしてみます。一般的には CI/CD のシステムでは実行時にそれなりの負荷が発生するので、負荷分散の観点から Git リポジトリ管理システムとは別マシンとして動かします。

ここでは個人用に使うものを想定しているのと、そんなにたくさんのマシンを用意するのも大変なので、Git リポジトリ管理システムと CI/CD のシステムは同じマシンで稼働させることにします。

つまり、Forgejo Runner をインストールするマシンには、事前に HTTPS/SSH 対応の Forgejo のインストールと設定がしてあるとします。

ちなみに、今回、動作確認をした Raspberry Pi 5 の仕様は次の通りです。

項目 内容
OS Raspberry Pi OS 2023-12-05 版
メモリ 8 GB
microSD 16 GB
ホスト名 pi5
FQDN pi5.local

なお、FQDN の pi5.local については、通常は mDNS により自動で使えるようになるものですが、Forgejo Runner は mDNS による名前解決に対応していません。そのため、これについてはインストールするマシン(ここでは pi5)の /etc/hosts ファイルに登録しておく必要があります。その点に注意してください。

/etc/hosts
127.0.0.1	pi5.local

インストールするソフトウェア

基本は Forgejo Runner のインストールと設定となりますが、CI/CD では Docker Engine を使うことも多くあります。そのため、Docker Engine もインストールします。

ソフトウェア名 説明
Forgejo Runner CI/CD 用ソフトウェア
Docker Engine コンテナーソフトウェア

CI/CD とは

ここで、CI/CD(Continuous Integration / Continuous Delivery)について簡単に説明しておきます。

CI/CD は、継続的インテグレーション(Continuous Integration) と 継続的デリバリー(Continuous Delivery)の略称です。ソフトウェア開発において、コード変更からリリースまでのプロセスを自動化し、迅速かつ確実に高品質なソフトウェアを提供するための手法や機能を指します。CI/CD を導入することで、ソフトウェア開発の効率化、ソフトウェア品質の向上などのメリットを得られます。

CI は、開発者がコード変更を頻繁に Git リモートリポジトリに統合し、自動テストを実行することや、それを実現する機能を指します。この機能を利用することによる主なメリットは次の通りです。

  • コードの品質向上: コード変更を頻繁に統合・テストすることで、問題の早期発見・修正が可能
  • 開発効率の向上: 手動による統合・テスト作業を減らすことで、単純作業による開発リソースの浪費を減少
  • 開発環境の統一: 共通のリポジトリとテスト環境を使用することで、開発者間の環境差異による問題を排除

CD は、CI でテストされたコードを自動的に本番環境にデプロイすることや、それを実現する機能を指します。この機能を利用することによる主なメリットは次の通りです。

  • リリース時間の短縮: 手動によるデプロイ作業を減らすことで、新しい機能を迅速にユーザーへ提供
  • リリースの信頼性向上: 自動化されたデプロイプロセスにより、手動によるデプロイ作業によるミスやエラーの排除
  • リスクの低減: 段階的なデプロイやロールバック機能などにより、リリースに伴うリスクを低減

有名な CI/CD ツールには、以下のようなものがあります。なお、それぞれが提供する機能やサービスについて、厳密には一致していませんが、機能的に CI/CD に関するものということで、ざっくりとまとめて一覧としたものです。

  • Jenkins: Java で実装されたオープンソースの CI/CD ツール
  • GitHub Actions: GitHub 上で利用できる CI/CD ツール
  • GitLab CI/CD: GitLab 上で利用できる CI/CD ツール
  • CircleCI: クラウド型の CI/CD ツール
  • Gloud Build: Google Cloud Platform の CI/CD ツール
  • Azure DevOps: Microsoft Azure の CI/CD ツール

CI/CD が世の中に普及するきっかけを与えたのは Jenkins で、これは CI/CD のための自動処理を実行する環境を提供するソフトウェアです。Jenkins と、Git リポジトリ管理システムが連携して、CI/CD の機能を実現することができます。

CI/CD が普及した結果、Jenkins が提供する機能は Git リポジトリ管理システムでも標準的に提供する機能となりつつあり、GitHub Actions や GitLab CI/CD といった機能が追加されるようになっています。

なお、Forgejo は GitHub を参考にして開発されているため、CI/CD のための機能は GitHub Actions と同様に Forgejo Actions という名前で提供されています。CI/CD のための Git リモートリポジトリの設定を、この Actions で指定します。

この Actions で利用する「自動処理を実行する環境」を提供するソフトウェアがランナーと呼ばれるものになります。ランナーとしては、Forgejo 公式のものは Forgejo Runner なります。Forgejo actions runners の、他のランナーについてのドキュメント で紹介されているように、他にも Gitea 用の gitea/act_runner などを使うこともできます。

Docker Engine

Docker Engine とは、コンテナーソフトウェアで、コンテナーの実行や管理をすることができます。OSS(オープンソースソフトウェア)として開発されていて、Apache License, Version 2.0 のライセンスで利用可能です。Docker Engine の人気によりコンテナーソフトウェアが普及したので、初めてコンテナーソフトウェアを使うなら、Docker Engine が良いです。

ちなみに、Docker Engine は Docker Desktop に含まれているので、Docker Dekstop を使う場合は自動で Docker Engine も使うことになります。

なお、コンテナーソフトウェアについては、OCI(Open Container Initiative)で仕様策定がされています。また、Docker Engine 以外にも PodmanLinux Containers といったコンテナーソフトウェアもあります。Docker Engine を使ってコンテナーについての基本を理解したら、これらについても調べてみると良いでしょう。コンテナーソフトウェアについて更に理解が深まるはずです。

ここでは Docker Engine のインストールと、動作確認の方法について説明します。

Docker Engine のインストール

それでは Docker Engine をインストールしましょう。Raspberry Pi OS は Debian ベースなので、arm64 対応の Docker を https://docs.docker.com/engine/install/debian/#install-using-the-repository の説明に従ってインストールします。

次のような install_docker.sh スクリプトを用意してインストールしました。

install_docker.sh
#!/bin/sh

apt-get update
apt-get install -y ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg \
  | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update

apt-get install -y docker-ce docker-ce-cli \
  containerd.io docker-buildx-plugin docker-compose-plugin

インストールスクリプトは sudo コマンドを使って sh コマンドで実行します。

sudo sh ./install_docker.sh

これで、Docker Engine がインストールできます。

次に pi ユーザーが docker コマンドを実行できるようにするために、usermod コマンドで docker グループへ pi ユーザーを追加します。

sudo usermod -aG docker pi

この変更を反映するために、一度ログアウトします。それから、pi ユーザーで再ログインしてから動作の確認をします。

Docker Engine の動作確認

最初に root での動作確認のため、sudo コマンドを使って hello-world コンテナーを実行してみます。

sudo docker run hello-world

実行できたら、pi ユーザーで sudo をつけずに docker コマンドを使ってみます。このとき、設定がうまくできていないとエラーになります。

例えば、root による hello-world コンテナーの確認を docker ps コマンドで確認してから、それを docker rm コマンドで削除します。実際に実行すると次のようになります。

pi@pi5:~ $ docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES
2af0b6ab7f96   hello-world   "/hello"   19 minutes ago   Exited (0) 18 minutes ago             zealous_keller
pi@pi5:~ $ docker rm zealous_keller 
zealous_keller

Forgejo Runner インストールの事前準備

Forgejo Runner のインストールと設定をする前に、実際に CI/CD をするときに必要となるものを事前に準備しておきます。

  • git の設定
  • Docker イメージの用意
  • デプロイキーの用意と設定
  • Forgejo ソケットファイルの導入

git の設定

Git リポジトリを使用するので、git config コマンドを使って pi ユーザーのメールアドレスとユーザー名のデフォルト設定をしておきます。ここで指定するメールアドレスとユーザー名は Git リポジトリで使うものなので、Raspberry Pi OS のものとは別のものです。

ここでは、Raspberry Pi OS のものと同じものを指定することにして、それぞれ pi@pi5.local と pi とします。

git config --global user.email pi@pi5.local
git config --global user.name pi

Docker イメージの用意

Forgejo Runner を稼働させる前に、使用する Docker イメージはあらかじめ用意しておくと、実際に利用するときの待ち時間が少なくて済みます。ここでは node:18-bookwormubuntu:22.04 を使うことにして、docker pull コマンドでローカルマシンで使えるようにしておきます。

docker pull node:18-bookworm
docker pull ubuntu:22.04

デプロイキーの用意と設定

Forgejo Runner を使って処理を実行するにあたって、Forgejo が管理する Git リポジトリからコードを取得する必要があります。そのために CI/CD ツールが SSH クローンを使えるように設定が必要です。

SSH クローンを手動で行うときの作業を思い出すとわかるはずなのですが、デプロイ用に使うリポジトリへアクセスするための SSH のキーペアと pi5.local マシンのホスト用公開鍵の値が必要だということになります。

これらの値は、Forgejo の次の機能を使ってリポジトリ用の情報として保存し、利用することになります。

  • デプロイキー
  • Actions のシークレット
  • Actions の変数

なお、今回の説明では、これらの値を使って Forgejo Actions を使うところまではしませんが、これらを設定しておくと、次回のリポジトリーからコードを取得する Forgejo Actions がすぐに使えるようになります。

デプロイキーの用意

まず、デプロイ用のキーを ssh-keygen コマンドで作成します。pi5.local の Git リポジトリ proj001 用に作るので -C オプションでコメントに pi5 proj001 deploy を指定します。また、ファイル名に proj001-deploy を指定して、デプロイ用のキーペアだということがわかるようにします。

ssh-keygen -t ed25519 -f proj001-deploy -C "pi5 proj001 deploy"

これで、proj001-deployproj001-deploy.pub ファイルが生成されます。それぞれの値を確認して Forgejo へ登録します。

デプロイキーの設定

最初にデプロイキーを Forgejo へ登録します。デプロイキーには、デプロイ用の公開鍵を指定します。秘密鍵ではないので注意してください。ということで、proj001-deploy.pub の内容を cat コマンドで確認します。

pi@pi5:~ $ cat proj001-deploy.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGC15l4riDBENzdAMeUSg6tC5iWIcbqLk78QLmSr05BH pi5 proj001 deploy

次に https://pi5.local:3000/pi/proj001/settings/keys を開いて、「デプロイキーを追加」をクリックします。表示された画面で、デプロイキーの内容に proj001-deploy.pub の内容を追加します。また、タイトルにキーが区別できるように「pi5 proj001 deploy」と入力し、CI/CD の処理により Git リポジトリを更新できるように「書き込みアクセスも有効にする」のチェックも入れます。

/images/20240302_rpi5_runner/forgejo-runner-deploy-01.png
Forgejo デプロイキーの追加画面

それから「デプロイキーを追加」をクリックすると、Forgejo の proj001 にデプロイキーが追加されます。

/images/20240302_rpi5_runner/forgejo-runner-deploy-02.png
Forgejo 登録されたデプロイキーの一覧画面

シークレットの設定

次に、デプロイ用の秘密鍵について、 Forgejo のシークレット変数へ登録します。cat コマンドで proj001-deploy の内容を確認します。

pi@pi5:~ $ cat proj001-deploy
-----BEGIN OPENSSH PRIVATE KEY-----
(略)
-----END OPENSSH PRIVATE KEY-----

それから https://pi5.local:3000/pi/proj001/settings/actions/secrets を開いて、シークレット変数 DEPLOY_SSH_KEY を追加します。「シークレットを追加」をクリックして、シークレット変数を追加する画面を表示して、名称に「DEPLOY_SSH_KEY」、値にデプロイ用の秘密鍵を入力します。

/images/20240302_rpi5_runner/forgejo-runner-deploy-03.png
Forgejo シークレットの追加画面

「了解」をクリックすると、シークレット変数 DEPLOY_SSH_KEY が Forgejo の proj001 に追加されます。

/images/20240302_rpi5_runner/forgejo-runner-deploy-04.png
Forgejo シークレットの一覧画面

変数の設定

次に、pi5.local マシンのホスト用公開鍵について、 Forgejo の変数へ登録します。

pi5.local マシンのホスト用公開鍵は ssh-kyescan コマンドで確認できます。デプロイ用に使うキーペアを作成するときのタイプに合わせたホスト用公開鍵の値が必要なので -t オプションを使って指定します。

ssh-keyscan -t <キーのタイプ> <ホスト名>

今回はキーペアを ed25519 のタイプで作成していて、ホストは pi5.local でアクセスするので、次のようなコマンドになります。

ssh-keyscan -t ed25519 pi5.local

実際にコマンドを実行するときは、次のようにします。2>&1 でエラー出力を標準出力へリダイレクトして統合し、パイプライン(|)と grep コマンドで ssh-ed25519 を含む行だけ抽出すると必要な情報が出力できます。

pi@pi5:~/proj001 $ ssh-keyscan -t ed25519 pi5.local 2>&1 |grep ssh-ed25519
pi5.local ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP4Rm4y9/X1sZNCPG7nbrZsmeOZmhEYb9KDs1v2FCmhL

それから https://pi5.local:3000/pi/proj001/settings/actions/variables を開いてホストの公開鍵を変数 DEPLOY_KNOWN_HOST を追加します。「変数の追加」をクリックすると変数を登録する画面になります。名称へ「DEPLOY_KNOWN_HOST」、値へホスト用公開鍵の値を入力します。

/images/20240302_rpi5_runner/forgejo-runner-deploy-05.png
Forgejo 変数の追加画面

「了解」をクリックすると、Forgejo の proj001 の変数に追加されます。

/images/20240302_rpi5_runner/forgejo-runner-deploy-06.png
Forgejo 変数の一覧画面

Forgejo ソケットファイルの導入

Forgejo Runner を利用するにあたって、Forgejo の性能を高めるためにソケットファイルを導入しておきます。Forgejo では Git Hook の機能というものを使って、Git リポジトリに変更があった場合に、自分自身が提供する API を呼び出して実行するように実装がされています。

この呼び出しについて、初期設定だと HTTP/HTTPS によるネットワーク通信で実行されるのですが、ソケットファイルを導入することで内部プロセス通信による処理にすることができます。ネットワーク通信よりも、ソケットファイル経由での内部プロセス通信の方が高速で安定するはずなので、こちらが使われるように設定します(と、断定的に書きましたが、きちんとは調べていません。そのはずです)。

Forgejo ソケットファイルを導入するには /etc/systemd/system/forgejo.main.socket ファイルを用意します。forgejo サービスの一部として設定するので、このファイルを用意する前に、forgejo サービスを止めておきます。

sudo systemctl stop forgejo

それから、次の内容でファイルを作成します。

/etc/systemd/system/forgejo.main.socket
[Unit]
Description=Forgejo Web Socket
PartOf=forgejo.service

[Socket]
Service=forgejo.service
ListenStream=/run/forgejo/forgejo.sock
NoDelay=true

[Install]
WantedBy=sockets.target

次に forgejo サービスの設定 /etc/systemd/system/forgejo を変更します。設定のカスタマイズをするので、systemctl edit コマンドを使って変更の指定をします。サービス名(.service は省略可能)を指定すると、指定したサービスのカスタマイズができます。

systemctl edit <サービス名>

実際の作業では管理者権限が必要なので、sudo コマンドと組み合わせて実行します。EDITOR 環境変数を指定しない場合は次のようになります。

sudo systemctl edit forgejo

systemctl edit コマンドで forgejo サービスのカスタマイズのためのエディターを起動したら、次のように追加設定する内容を指定します。ちなみに、この場合、編集対象のファイルは /etc/systemd/system/forgejo.service.d/override.conf となります。

/etc/systemd/system/forgejo.service.d/override.conf
[Unit]
After=forgejo.main.socket
Requires=forgejo.main.socket

[Service]
RuntimeDirectory=forgejo

Forgejo ソケットファイル用の設定については、もともとの forgejo.service のコメントにあったものをそのまま使っています。つまり、そう指定すると動くということなので従っています。

一応、簡単に説明しておくと、[Unit] のセクションで指定しているのは、forgejo.main.socket で指定してあるソケット(ここでは /run/forgejo/forgejo.sock)がサービスには必要で、その設定ファイルを読み込んでから、このサービスを起動するというものです。

また、[Service] のセクションで RuntimeDirectory=forgejo を指定することで /run/forgejo ディレクトリーにソケットファイル forgejo.sock を用意して使えるようになります。使用するソケットファイルのパスは /etc/systemd/system/forgejo.main.socket ファイルで指定した ListenStream=/run/forgejo/forgejo.sock によって決まります。

ファイル編集が終わったら保存してエディターを終了します。念の為、ファイルの内容を cat コマンドで確認しておきます。

pi@pi5:~ $ cat /etc/systemd/system/forgejo.service.d/override.conf 
[Unit]
After=forgejo.main.socket
Requires=forgejo.main.socket

[Service]
RuntimeDirectory=forgejo

追加指定した設定が有効になっていることは systemctl show コマンドで確認できます。そのまま使うと設定が全部表示されるので、パイプラインと grep コマンドで設定を絞り込んで表示して確認します。ここでは After と RuntimeDirectory を grep コマンドのキーワードに指定して確認します。

pi@pi5:~ $ sudo systemctl show forgejo|grep After
RemainAfterExit=no
After=network.target systemd-journald.socket system.slice -.mount forgejo.main.socket basic.target syslog.target sysinit.target
pi@pi5:~ $ sudo systemctl show forgejo|grep RuntimeDirectory
RuntimeDirectoryPreserve=no
RuntimeDirectoryMode=0755
RuntimeDirectory=forgejo

After の設定について、forgejo.main.socket が含まれていて、RuntimeDirectory=forgejo の設定も追加されていれば大丈夫です。

準備ができたら forgejo.main.socket サービスを有効化します。

sudo systemctl enable forgejo.main.socket

これで、/etc/systemd/system/sockets.target.wants/forgejo.main.socket のシンボリックリンクが作成されます。念の為に ls -l コマンドで確認しておきます。

pi@pi5:~ $ ls -l /etc/systemd/system/sockets.target.wants/ | grep forgejo
lrwxrwxrwx 1 root root 39  2月 29 08:38 forgejo.main.socket -> /etc/systemd/system/forgejo.main.socket

systemctl status コマンドで状態も確認しておくと良いでしょう。

pi@pi5:~ $ sudo systemctl status forgejo.main.socket
● forgejo.main.socket - Forgejo Web Socket
     Loaded: loaded (/etc/systemd/system/forgejo.main.socket; enabled; preset: >
     Active: active (running) since Sat 2024-03-02 19:30:16 JST; 1min 31s ago
   Triggers: ● forgejo.service
     Listen: /run/forgejo/forgejo.sock (Stream)
     CGroup: /system.slice/forgejo.main.socket

 3月 02 19:30:16 pi5 systemd[1]: Listening on forgejo.main.socket - Forgejo Web>

ソケット導入の用意ができたので、forgejo サービスを起動します。

sudo systemctl start forgejo

それから、systemctl status で forgejo サービスの状態を確認し、Active: active (running)TriggeredBy: ● forgejo.main.socket の表示がされていれば OK です。

pi@pi5:~ $ sudo systemctl status forgejo
● forgejo.service - Forgejo (Beyond coding. We forge.)
     Loaded: loaded (/etc/systemd/system/forgejo.service; enabled; preset: enab>
    Drop-In: /etc/systemd/system/forgejo.service.d
             └─override.conf
     Active: active (running) since Sat 2024-03-02 19:30:16 JST; 5min ago
TriggeredBy: ● forgejo.main.socket
   Main PID: 3863 (forgejo)
      Tasks: 10 (limit: 9255)
        CPU: 3.661s
     CGroup: /system.slice/forgejo.service
             └─3863 /usr/local/bin/forgejo web --config /etc/forgejo/app.ini

もし、Triggers: の表示がおかしいようなら、systemctl daemon-reload コマンドで設定を反映してから、forgejo サービスについて systemctl stopsystemctl start を使って再起動して再確認をしてみてください。

sudo systemctl daemon-reload

Forgejo Runner の用意

Forgejo Runner は Forgejo インスタンスへ接続して、CI/CD のための処理を実行するデーモンプロセス用のソフトウェアです。MIT ライセンスで開発されている OSS です。

Forgejo Runner を実行するホスト OS の環境をそのまま使って CI/CD 用の処理を実行することができます。また、Forgejo Runner を実行するホスト OS で Docker コンテナーを実行することができるなら、Docker コンテナーを使って CI/CD 用の処理を実行することもできます。ただし、2024-03-02 時点では bash が動作する Docker コンテナーでないと使えないようです。

Forgejo Runner のインストール

Forgejo Runner のインストールをするには、https://code.forgejo.org/forgejo/runner/releases からバイナリをダウンロードしてホストとなる OS へインストールする方法と、https://code.forgejo.org/forgejo/-/packages/container/runner/versions で公開されている Open Container Initiative(OCI)の仕様に準拠したコンテナーイメージを使う方法があります。

ここでは arm64 版のバイナリをダウンロードしてホスト OS へインストールします。次のような install_forgejo.sh スクリプトを用意します。EB114F5E6C0DC2BCDD183550A4B61A2DC5923710 の値については、https://forgejo.org/docs/next/admin/actions/#installation-of-the-binary で提示されているスクリプトのものなので、もしそこの値が変わっているようなら、それに置き換えてください。

install_forgejo.sh
DL_URL=https://code.forgejo.org/forgejo/runner/releases/download
ARCH=arm64
#ARCH=amd64
VERSION=3.3.0
curl -o forgejo-runner ${DL_URL}/v${VERSION}/forgejo-runner-${VERSION}-linux-${ARCH}
chmod +x forgejo-runner
curl -o forgejo-runner.asc ${DL_URL}/v${VERSION}/forgejo-runner-${VERSION}-linux-${ARCH}.asc
gpg --keyserver keys.openpgp.org --recv EB114F5E6C0DC2BCDD183550A4B61A2DC5923710
gpg --verify forgejo-runner.asc forgejo-runner
sudo mv forgejo-runner /usr/local/bin/

このスクリプトを実行すると、最後に sudo コマンドを実行するために pi ユーザーのパスワード入力が要求されます。パスワードを入力して実行すると /usr/local/bin/forgejo-runner コマンドが使えるようになります。なお、途中でファイルの確認もあるので、初めてインストールするときは、1行ずつ順番に実行していくと良いでしょう。

スクリプトを実行する場合は次のようにコマンド入力します。

sh install_forgejo.sh

ちなみに、gpg コマンドでファイルをチェックしている部分のコマンド実行結果は次のようになります。

pi@pi5:~ $ gpg --keyserver keys.openpgp.org --recv EB114F5E6C0DC2BCDD183550A4B61A2DC5923710
gpg: 鍵A4B61A2DC5923710:"Forgejo <(略)>"変更なし
gpg:           処理数の合計: 1
gpg:               変更なし: 1
pi@pi5:~ $ gpg --verify forgejo-runner.asc forgejo-runner
gpg: 2023年12月05日 02時47分01秒 JSTに施された署名
gpg:                EDDSA鍵EB114F5E6C0DC2BCDD183550A4B61A2DC5923710を使用
gpg: "Forgejo <(略)>"からの正しい署名 [不明の]
gpg:                 別名"Forgejo Releases <(略)>" [不明の]
gpg: *警告*: この鍵は信用できる署名で証明されていません!
gpg:       この署名が所有者のものかどうかの検証手段がありません。
 主鍵フィンガープリント: EB11 4F5E 6C0D C2BC DD18  3550 A4B6 1A2D C592 3710

ここでは この鍵は信用できる署名で証明されていません! という警告が表示されていますが、公式の https://forgejo.org/docs/next/admin/actions/#installation-of-the-binary で指定されている値の EB114F5E6C0DC2BCDD183550A4B61A2DC5923710 から取得した GPG キーなので、これについては信頼しても大丈夫です。これを信頼する前提だと、"Forgejo <(略)>"からの正しい署名 と表示されていれば大丈夫だということになります。

Forgejo Actions の有効化

Forgejo Runner の用意ができたら、Forgejo Actions を有効化します。そのためには、pi5.local の /etc/forgejo/app.ini ファイルに [actions] セクションの追加が必要です。指定する内容は次のようになります。

/etc/forgejo/app.ini
[actions]
ENABLED = true
ZOMBIE_TASK_TIMEOUT = 10m
ENDLESS_TASK_TIMEOUT = 15m
ABANDONED_JOB_TIMEOUT = 30m
SKIP_WORKFLOW_STRINGS = [skip ci],[ci skip],[no ci],[skip actions],[actions skip]

この設定では、個人で使う前提で、確認もしやすくするために、タイムアウトの設定値を短めにしてあります。デフォルトの値は https://codeberg.org/forgejo/forgejo/src/branch/forgejo/custom/conf/app.example.ini にある例を参照してください。

この設定ファイルへの追加変更にあたっては、エディタを使っても良いですし、次のようにコマンドを実行しても良いです。

cat << EOS | sudo tee -a /etc/forgejo/app.ini
[actions]
ENABLED = true
ZOMBIE_TASK_TIMEOUT = 10m
ENDLESS_TASK_TIMEOUT = 15m
ABANDONED_JOB_TIMEOUT = 30m
SKIP_WORKFLOW_STRINGS = [skip ci],[ci skip],[no ci],[skip actions],[actions skip]
EOS

設定変更をしたら、forgejo サービスを systemctl コマンドで再起動します。

sudo systemctl restart forgejo

再起動したら systemctl status コマンドで forgejo サービスが有効になっていることを確認します。

Forgejo Runner の登録と動作確認

Forgejo で Actions の機能を有効化したら、Forgejo Runner を登録します。ここではトークン(token)を使う方法で登録します。

なお、まだ pi5.local について /etc/hosts127.0.0.1 pi5.local のエントリーをしていない場合は、次のコマンドを実行して hosts ファイルを更新してから、Forgejo Runner の登録をするようにしてください。

echo -e "127.0.0.1\tpi5.local" | sudo tee -a /etc/hosts

次の順番に説明します。

  1. Forgejo Runner の設定ファイル
  2. トークンの発行
  3. Forgejo Runner の登録
  4. Forgejo Runner の動作確認

Forgejo Runner の設定ファイル

最初に forgejo-runner コマンド用の設定ファイルとして config.yml を作成します。初期設定ファイルを生成する forgejo-runner generate-config コマンドがあるので、これを使います。生成された設定ファイルを、構築したい環境に合わせて編集します。

まず、HTTPS では自己署名のサーバー証明書を使っているため、接続時の検証が有効になっていると警告やエラーになってしまいます。そのため、接続時の検証については無効化する必要があります。そのため、runnerinsecure: true の指定します。

runner:
  #(略)
  insecure: true
  #(略)

次に、並行して実行する処理の数については、runnercapacity: 1 と指定されています。実際に使ってみたところ 1 にしておくと、次の処理が実行されるまで待つ時間が長くなるようだったので、これを 3 へ増やします。

また、タイムアウトなどの時間については、runner で、それぞれ timeout: 3hfetch_timeout: 5s/fetch_interval: 2s が指定されています。ここでは動作確認もしたいので、待ち時間は短めの 15 分にしつつ、個人で使うことを考えると CI/CD 用の処理があるかどうかを確認するフェッチのタイムアウトは 30 秒、間隔は 60 秒とすることにしました。

動作確認時にうまく動かない場合、ログを確認するときに間隔が短すぎるとフェッチのログばかりになって確認しにくくなります。

次にラベルについて決めます。Forgejo Actions では使用する Runner を自動で選ぶためにラベルというものが使われます。その値を labels: へ指定する必要があります。詳細については Forgejo Actions administrator guide labels-and-runs-on を参照してください。

ここでは、ホスト OS の環境を使って CI/CD 用の処理を実行するための self-hosted、ホスト OS で動作する Docker Engine を使って CI/CD 用の処理を実行する dockernode-18 のラベルを用意することにします。

ラベルの指定は、<ラベル名>:<実行環境> というフォーマットでします。

実行環境の部分について、host とするとホスト OS の環境をそのまま使います。正式には host://-self-hosted のようなのですが、手元では host で動いたのでそのままにします。

実行環境に Docker を使う場合は docker://<Docker イメージ> という指定をします。実行環境を省略すると node:16-bullseye のイメージが使われるようですが、Node.js 16 はすでにサポートが終了しているので、ここでは docker://ubuntu:22.04 を使うようにします。

Node.js 環境で実行したいときもあるはずなので、node-18 のラベルに対して docker://node:18-bookworm と指定して、Node.js 18 の Docker コンテナーを使えるようにしておきます。

配列で指定するときは下記のようになります。

  labels: ["self-hosted:host","docker:docker://ubuntu:22.04","node-18:docker://node:18-bookworm"]

次のように要素で指定することもできます。

  labels:
    - self-hosted:host
    - docker:docker://ubuntu:22.04
    - node-18:docker://node:18-bookworm

以上の設定を反映するためには、次のようにコマンド実行をすると良いでしょう。

/usr/local/bin/forgejo-runner generate-config > config.yml
sed -i "s/insecure: false/insecure: true/" config.yml
sed -i "s/capacity: 1/capacity: 3/" config.yml
sed -i "s/timeout: 3h/timeout: 15m/" config.yml
sed -i "s/fetch_timeout: 5s/fetch_timeout: 30s/" config.yml
sed -i "s/fetch_interval: 2s/fetch_interval: 60s/" config.yml
sed -i -e "s\
|labels: \[\]\
|labels: \
\[\
\"self-hosted:host\",\
\"docker:docker://ubuntu:22.04\",\
\"node-18:docker://node:18-bookworm\"\
\]\
|" config.yml

変更したものはいずれも runner: にあるものなので、そこだけ抜粋すると次のような内容になります。なお、コメント行は省略しています。

runner:
  file: .runner
  capacity: 3
  envs:
    A_TEST_ENV_NAME_1: a_test_env_value_1
    A_TEST_ENV_NAME_2: a_test_env_value_2
  env_file: .env
  timeout: 15m 
  insecure: true
  fetch_timeout: 30s
  fetch_interval: 60s
  labels: ["self-hosted:host","docker:docker://ubuntu:22.04","node-18:docker://node:18-bookworm"]

これで、Forgejo Runner の設定ファイルである config.yml ファイルの準備はおしまいです。

トークンの発行

次に、Forgejo Runner 登録用のトークンを発行します。Forgejo へ Web ブラウザでアクセスして画面を操作して発行することもできますが、コマンド実行の方が楽なので、そうします。

コマンドを実行する場合は、pi5.local の git ユーザーで forgejo actions generate-runner-token コマンドを実行します。ただし、今回の環境では forgejo コマンドを実行するときに使用する設定ファイルの指定なども必要なので、このままでは正しく実行できません。

forgejo actions generate-runner-token

ということで、今回は次のコマンドを git ユーザーで実行すれば良いということになります。ですが、まだ実行しないでください。

/usr/local/bin/forgejo \
  --config=/etc/forgejo/app.ini \
  actions generate-runner-token

現在の作業は pi ユーザーで行っているので、git ユーザーでコマンド実行するには sudo コマンドと組み合わせる必要があります。また、ここで発行したトークンは、この後の Forgejo Runner を登録るときにも必要なので、シェル変数へ保存しておくのが楽です。

なお、シェル変数へコマンドの出力結果を保存するには <シェル変数名>=$(<コマンド>) とします。以上のことから、シェル変数 token へトークンを保存して、echo コマンドで値を表示するようにしましょう。

そのコマンドは次のようになります。

token=$(sudo --user git sh -c "\
/usr/local/bin/forgejo \
  --config=/etc/forgejo/app.ini \
  actions generate-runner-token
")
echo ${token}

これを実行すると、次のようなトークン用の文字列が出力されます。

VhuZON1xoqfLTvJVbGDL88lSvAcz2oaLCevH5DC4

このトークンを使って、Forgejo Runner を登録します。

Forgejo Runner の登録

トークンの用意ができたら、forgejo-runner register コマンドを使って、pi5.local で実行する Forgejo Runner を https://pi5.local:3000 で稼働する Forgejo へ登録します。

ここで、forgejo-runner register コマンド実行時に指定するオプションがいくつかあります。

使用する設定ファイルは --configconfig.yml を指定します。

対話的に指定することはないので --no-interactive を指定して非対話モードとします。

登録先は --instance に URL で https://pi5.local:3000 を指定します。

トークンは --token で指定します。事前にシェル変数 token に入れてあるなら ${token} を指定します。シェル変数を使わない場合は forgejo actions generate-runner-token コマンドの実行後に出力された文字列をそのまま指定します。

最後に、登録する Forgejo Runner は区別がつくように --name で名前を指定できます。ここでは pi5-runner とします。

以上より、実行するコマンドは次のようになります。

/usr/local/bin/forgejo-runner register \
  --config config.yml \
  --no-interactive \
  --instance https://pi5.local:3000 \
  --token ${token} \
  --name pi5-runner

実際に実行したときの結果は次のようになります。Runner を pi ユーザーで実行しているため警告が出ていますが、いまのところ root 権限が必要なコマンドを実行する予定はないので無視して大丈夫です。

pi@pi5:~ $ /usr/local/bin/forgejo-runner register \
  --config config.yml \
  --no-interactive \
  --instance https://pi5.local:3000 \
  --token ${token} \
  --name pi5-runner
INFO Registering runner, arch=arm64, os=linux, version=v3.3.0. 
WARN Runner in user-mode.                         
DEBU Successfully pinged the Forgejo instance server 
INFO Runner registered successfully.              

登録が成功すると、コマンドを実行したディレクトリーに .runner ファイルが作成されます。その内容は cat コマンドで確認しておきましょう。次のようなになるはずです。

pi@pi5:~ $ cat .runner
{
  "WARNING": "This file is automatically generated by act-runner. Do not edit it manually unless you know what you are doing. Removing this file will cause act runner to re-register as a new runner.",
  "id": 1,
  "uuid": "af5313ae-583f-41a3-b56a-6a686aab6eeb",
  "name": "pi5-runner",
  "token": "3d06b21baaa3e77d70b49693b06b82cf8f257b67",
  "address": "https://pi5.local:3000",
  "labels": [
    "self-hosted:host",
    "docker:docker://ubuntu:22.04",
    "node-18:docker://node:18-bookworm"
  ]
}

また、https://pi5.local:3000/admin/actions/runners を開いて、pi5-runner が Forgejo に登録されていることを確認しましょう。このとき、id が .runner のものと一致していることも確認します。

/images/20240302_rpi5_runner/forgejo-action-system-setting-01.png
Forgejo Actions ランナーの一覧画面

Forgejo Runner の動作確認

Forgejo Runner の登録ができたら、動作確認をしてみましょう。実行するには forgejo-runner daemon コマンドを実行します。このとき、実行時のディレクトリーに .runner ファイルが必要です。また、--config オプションで使用する設定ファイルの指定も必要です。

/usr/local/bin/forgejo-runner --config config.yml daemon

これで、https://pi5.local:3000/admin/actions/runners のランナーの一覧にある pi5-runner が「アイドル」となればOKです。

Forgejo Runner の利用

Forgejo Runner を利用するには、リポジトリで Actions を有効にし、ワークフロー用のファイルを作成してリポジトリへ追加する必要があります。

Forgejo リポジトリの Actions 有効化

まず Forgejo リポジトリの Actions の設定を有効化します。ここでは proj001 リポジトリの設定をするので、https://pi5.local:3000/pi/proj001/settings を開きます。そこに、「Actions を有効にする」があるのでチェックします。

/images/20240302_rpi5_runner/forgejo-action-01.png
Forgejo proj001 リポジトリの設定で Actions を有効化

それから「設定を更新する」をクリックすると、リポジトリの画面に Actions のタブが追加されます。

/images/20240302_rpi5_runner/forgejo-action-02.png
Forgejo proj001 リポジトリの Actions のタブ

このリポジトリの Actions の画面では、この後に説明するワークフロー用のファイルを追加して Forgejo Runner が実行されると、結果が表示されます。結果については次の例でわかるように、失敗したときには赤色、成功したときには緑色で表示されて、すぐにわかるようになっています。

/images/20240302_rpi5_runner/forgejo-action-03.png
Forgejo proj001 リポジトリの Actions の画面

ワークフロー用のファイルの用意

それでは、ワークフロー用のファイルを用意して、Forgejo Actions を動かしてみましょう。なお、ここでは Actions が動作することの確認を主な目的として、ワークフロー用のファイルについての説明は簡単に済ませます。

Forgejo Runner を動作させるときの処理については、ワークフロー用のファイルをリポジトリに追加してコントロールします。ここでは、proj001 ディレクトリーに Forgejo の proj001 を SSH クローンしてあるとします。

次のように、proj001 ディレクトリの下に .forgejo/workflows ディレクトリーを用意します。

cd proj001
mkdir -p .forgejo/workflows

次に、.forgejo/workflows/demo.yaml ファイルへ、Forgejo Runner のホスト OS で echo コマンドを実行するジョブの設定をします。コマンドを実行するタイミングは、リポジトリに何らかのコミットが push されたタイミングとします。ジョブの名前は test とします。

これを指定する demo.yaml ファイルの内容は次のようになります。

on: [push]
jobs:
  test:
    runs-on: self-hosted
    steps:
      - run: echo All Good

on: でコマンドを実行するタイミング、jobs: でジョブ、runs-on: で実行環境のラベル、steps: で実行するコマンドを指定しています。エディタで作成しても良いですし、次のようにコマンドで作成しても良いです。

cat << EOS > .forgejo/workflows/demo.yaml
on: [push]
jobs:
  test:
    runs-on: self-hosted
    steps:
      - run: echo All Good
EOS

demo.yaml ファイルを作成したら、git addgit commit コマンドを使ってdemo.yaml ファイルをリポジトリへ追加して、それを git push コマンドで Forgejo の Git リポジトリへ反映します。

pi@pi5:~/proj001 $ git add .forgejo
pi@pi5:~/proj001 $ git commit -m "add demo.yaml"
[main f649e78] add demo.yaml
 1 file changed, 6 insertions(+)
 create mode 100644 .forgejo/workflows/demo.yaml

pi@pi5:~/proj001 $ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 384 bytes | 384.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
remote: . Processing 1 references
remote: Processed 1 references in total
To ssh://git@pi5.local/pi/proj001.git
   8fd20b9..f649e78  main -> main

git push コマンドを実行してからしばらくすると、forgejo-runner コマンドが実行されます。結果は Forgejo の proj001 の Actions の画面で確認することができます。各ジョブには結果の詳細を表示するためのリンクがあります。リンクをクリックすると、次のような画面が表示されて、ジョブの詳細結果を確認することが出来ます。

/images/20240302_rpi5_runner/forgejo-action-04.png
Forgejo proj001 リポジトリのジョブの詳細画面

動作確認ができたら、forgejo-runner を実行しているターミナルで、Ctrl+C を入力して停止します。

参考となる URL

最後に設定や利用方法について参考になる URL を紹介しておきます。

Discussion