☘️

Giteaを使ってみる

2025/03/12に公開

Giteaとは

Goで実装されたセルフホスト型のGitHubクローンで、Gitでのコードホスティング、GitHub Actionsと互換性のあるCI/CDシステムのGitea Actions、ラベルやマイルストーン等が設定可能な課題管理、ComposerやNPM等から利用可能なパッケージ機能など、GitHubでよく利用されているであろう機能は一通り実装されている。

くわしくはhttps://about.gitea.com/を参照

利用の経緯

以前からCI/CDに関して自分で設定して使ってみたいと思っていたのだが、他の技術調査優先で後回しになっていたところ、最近、CI/CDの経験やGitHub Actionsについて尋ねられることがあったり、個人的にやってる仕事等でも利用したいと思って本格的に調べ始めたらこれが見つかったというのがきっかけ。

インストール先の環境や方針について

個人で利用している国内のVPSサービス上のdebianでバージョンは12.9。
ほかのWEBベースのプロダクトがあったり、すでにSSLの設定済みということでnginxをリバースプロキシにしてアクセス。
debianのパッケージが公式で用意されていないというものあるが、一つのバイナリで実行可能で、環境変数や設定などの関連ファイルについても知りたいというのもあって公式バイナリからのインストール。
データベースに関しては個人での利用なのでひとまずsqliteで

インストール

実行ユーザーの作成

以下のコマンドで実行ユーザーを作成し、実行ユーザーへスイッチしておく。
実行ユーザーのホームディレクトリを/opt/giteaにしておいて、基本的に関連ファイルはここにおくようにする。

$ sudo adduser --system --shell /bin/bash --gecos 'Git Version Control' --group --disabled-password --home /opt/gitea gitea
$ sudo su - gitea

バイナリのダウンロード

以下のコマンドで公式バイナリをダウンロード、この記事を書いている時点ではバージョンは1.23.4、実行権限を付け、コマンド入力の際にバージョンまで入力しないで済むよう、リンクを作成。

$ curl -O https://dl.gitea.com/gitea/1.23.4/gitea-1.23.4-linux-amd64?_gl=1*x6hm9l*_gcl_au*MjczMTQ3MzY2LjE3Mzg4NDMzMTQ.
$ chmod u+x gitea-1.23.4-linux-amd64
$ ln -s gitea-1.23.4-linux-amd64 gitea

基本となる設定ファイルの作成

以下で設定ファイルを置くディレクトリを作成。giteaは環境変数で作業ディレクトリを指定することができ、そこをベースにした指定箇所にファイルを置いておけばわざわざ細かいパスを指定する必要がなくなるため、デフォルトのcustom/confとする。

$ mkdir -p custom/conf

作ったディレクトリ上にapp.iniというファイル名で以下の内容のファイルを作成

custom/conf/app.ini
[server]
PROTOCOL = http
ROOT_URL = https://gitea.example.com/
HTTP_PORT = 3001

項目はそれぞれ
PROTOCOL: giteaへのアクセスに使用するプロトコル。nginx経由のため、httpに
ROOT_URL: giteaのルートURLで外向けのURL。
HTTP_PORT: giteaの監視ポート。nginx経由のため、空いている3001に

実行してWEBから設定を行う

nginxの設定についてはこちらでは割愛

以下のコマンドでgiteaを起動、変数で作業ディレクトリを指定し、前項で作成した設定ファイルを参照させ、関連ファイル等も作業ディレクトリ下に作成させる。

$ GITEA_WORK_DIR=/opt/gitea ./gitea
  2025/03/01 00:00:00 cmd/web.go:253:runWeb() [I] Starting Gitea on PID: 1632054
  ・・・
  2025/03/01 00:00:00 ...s/graceful/server.go:50:NewServer() [I] Starting new Web server: tcp:0.0.0.0:3001 on PID: 1632054

ブラウザから前項で指定したROOT_URLにアクセス。以下のようなページが表示されるため、自分の環境に合わせて記入。ほぼ初期値で問題ないと思われる。


systemdに登録

毎度コマンドで起動するわけにもいかないため、systemdに登録し、自動で起動するようにする。
まず、以下のファイルを作成。
前項のシェル上から起動したものはctrl-cなどして終了しておき、giteaの実行ユーザーではなく、普段利用しているユーザーで操作する。

/etc/systemd/system/gitea.service
[Unit]
Description=Gitea (Git with a cup of tea)
After=network.target

[Service]
RestartSec=2s
Type=simple
User=gitea
Group=gitea
WorkingDirectory=/opt/gitea
ExecStart=/opt/gitea/gitea
Restart=always
Environment=USER=gitea HOME=/opt/gitea GITEA_WORK_DIR=/opt/gitea

[Install]
WantedBy=multi-user.target

以下のコマンドで有効化し、起動

$ sudo systemctl enable gitea --now

act_runnerのインストール

GitHub Action互換のCI/CDを有効化するため、ワークフローを処理するデーモンプログラムact_runnerをインストールする。

関連パッケージのインストール

以下のコマンドで関連パッケージをインストール。
act_runnerはホスト上、コンテナ上で実行可能なため、dockerを、ワークフローの処理でnodeを使用するためnodejsをインストールしておく

$ sudo apt update
$ sudo apt install -y docker docker.io apparmor nodejs

以下のコマンドでコンテナ上のact_runnerを使用できるようにdockerグループにact_runnerの実行に使用するgiteaユーザーを所属させ、dockerも起動しておく。

$ sudo usermod -aG docker gitea
$ sudo systemctl start docker

act_runnerのダウンロード

以下のコマンドでact_runnerをダウンロードし、実行権限付与とバージョンを省いたリンクを作成。
これはgiteaの実行ユーザーでホームディレクトリ上で行う。

$ curl -O https://dl.gitea.com/act_runner/0.2.11/act_runner-0.2.11-linux-amd64
$ chmod u+x act_runner-0.2.11-linux-amd64
$ ln -s act_runner-0.2.11-linux-amd64 act_runner

ランナーをgiteaに登録するため登録トークンをメモ

ブラウザからgiteaインスタンスへ管理アカウントでログインし、右上に表示されるアバター画像をクリック、表示されるメニューからサイト管理を選択。
表示されるページ左のメニューからActionsを選択してサブメニューを展開、サブメニューのランナーを選択。
以下のイメージのようなページが表示されるため、ページ右上の新しいランナーを作成ボタンをクリックするとRegistration Tokenと書かれている枠にトークンが表示されるため、これをメモしておく。

また、以下のコマンドを実行することでもトークンを得られる。

$ ./gitea --config /opt/gitea/custom/conf/app.ini actions generate-runner-token
  0XX0XXx0XXX0XXx000X0x0xX00xxXxXXxxXX0Xx0

ランナーをgiteaへ登録

以下のコマンドでランナーをgiteaへ登録、途中、登録先giteaインスタンスのURL、登録トークン、ランナー名、ワークフローからこのランナーを指定する際に使用するラベルの入力が求められ、設定が.runnerファイルに保存されます。

$ ./act_runner register
  INFO Registering runner, arch=amd64, os=linux, version=v0.2.11. 
  WARN Runner in user-mode.                         
  INFO Enter the Gitea instance URL (for example, https://gitea.com/): 
  http://localhost:3001/             # giteaインスタンスのURL。リバースプロキシ内でlistenしてるURLを入力
  INFO Enter the runner token:                      
  0XX0XXx0XXX0XXx000X0x0xX00xxXxXXxxXX0Xx0
                                     # 前の項で確認した登録トークンを入力
  INFO Enter the runner name (if set empty, use hostname: example.com): 
  gitea-instance-runner              # ランナー名。任意の文字列
  INFO Enter the runner labels, leave blank to use the default labels (comma-separated, for example, ubuntu-latest:docker://gitea/runner-images:ubuntu-latest): 
  gitea-instance-runner-label        # ワークフローで指定するラベル。任意の文字列
  INFO Registering runner, name=gitea-instance-runner,  instance=http://localhost:3001/, labels=[gitea-instance-runner-label]. 
  DEBU Successfully pinged the Gitea instance server 
  INFO Runner registered successfully.

systemdに登録

act_runnerもsystemdに登録しておきます。
以下の内容のファイルを作成します。

/etc/systemd/system/act_runner.service
[Unit]
Description=Gitea Actions runner
Documentation=https://gitea.com/gitea/act_runner
After=docker.service

[Service]
ExecStart=/opt/gitea/act_runner daemon
ExecReload=/bin/kill -s HUP $MAINPID
WorkingDirectory=/opt/gitea
TimeoutSec=0
RestartSec=10
Restart=always
User=gitea

[Install]
WantedBy=multi-user.target

以下のコマンドで設定を反映、有効化、実行

$ sudo systemctl daemon-reload    
$ sudo systemctl enable act_runner --now

リモートかつ、カスタムのコンテナ上で動くact_runnerも作成

安めのプランのVPSを使っているので、負荷分散したい、もうすこし自由の効くランナーも使ってみたいといったこともあると思うので、giteaインスタンスのあるサーバーとは別のサーバーで動くカスタムコンテナで動くランナーも用意してみたいと思う。
ベースとなるイメージはDebianのtrixie。
この項のコマンド操作についてはカスタムコンテナ実行可能なサーバー上のユーザーで行う。
作業ディレクトリは任意の場所で。

act_runnerの起動スクリプトを用意

コンテナで動くact_runnerは公式でも用意されていて、同じように使えるようにするため、公式のイメージと同じ起動スクリプトを用意する。
以下がそのスクリプト

run.sh
#!/usr/bin/env bash
if [[ ! -d /data ]]; then
  mkdir -p /data
fi
cd /data
RUNNER_STATE_FILE=${RUNNER_STATE_FILE:-'.runner'}
CONFIG_ARG=""
if [[ ! -z "${CONFIG_FILE}" ]]; then
  CONFIG_ARG="--config ${CONFIG_FILE}"
fi
EXTRA_ARGS=""
if [[ ! -z "${GITEA_RUNNER_LABELS}" ]]; then
  EXTRA_ARGS="${EXTRA_ARGS} --labels ${GITEA_RUNNER_LABELS}"
fi
# In case no token is set, it's possible to read the token from a file, i.e. a Docker Secret
if [[ -z "${GITEA_RUNNER_REGISTRATION_TOKEN}" ]] && [[ -f "${GITEA_RUNNER_REGISTRATION_TOKEN_FILE}" ]]; then
  GITEA_RUNNER_REGISTRATION_TOKEN=$(cat "${GITEA_RUNNER_REGISTRATION_TOKEN_FILE}")
fi
# Use the same ENV variable names as https://github.com/vegardit/docker-gitea-act-runner
test -f "$RUNNER_STATE_FILE" || echo "$RUNNER_STATE_FILE is missing or not a regular file"
if [[ ! -s "$RUNNER_STATE_FILE" ]]; then
  try=$((try + 1))
  success=0
  # The point of this loop is to make it simple, when running both act_runner and gitea in docker,
  # for the act_runner to wait a moment for gitea to become available before erroring out.  Within
  # the context of a single docker-compose, something similar could be done via healthchecks, but
  # this is more flexible.
  while [[ $success -eq 0 ]] && [[ $try -lt ${GITEA_MAX_REG_ATTEMPTS:-10} ]]; do
    act_runner register \
      --instance "${GITEA_INSTANCE_URL}" \
      --token    "${GITEA_RUNNER_REGISTRATION_TOKEN}" \
      --name     "${GITEA_RUNNER_NAME:-`hostname`}" \
      ${CONFIG_ARG} ${EXTRA_ARGS} --no-interactive 2>&1 | tee /tmp/reg.log
    cat /tmp/reg.log | grep 'Runner registered successfully' > /dev/null
    if [[ $? -eq 0 ]]; then
      echo "SUCCESS"
      success=1
    else
      echo "Waiting to retry ..."
      sleep 5
    fi
  done
fi
# Prevent reading the token from the act_runner process
unset GITEA_RUNNER_REGISTRATION_TOKEN
unset GITEA_RUNNER_REGISTRATION_TOKEN_FILE
echo ${CONFIG_ARG} > /data/args
exec act_runner daemon ${CONFIG_ARG} 2>&1 > /data/log

Dockerfileを作成してイメージをビルド

以下のDockerfileを作成、中でact_runnerをダウンロードしているが、ファイル外でダウンロードしてCOPYしても問題ない。

Dockerfile
FROM debian:trixie

RUN apt update
RUN apt install -y nodejs git curl tini
RUN curl -OL https://gitea.com/gitea/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64
RUN mv act_runner-0.2.11-linux-amd64 /usr/local/bin/act_runner
RUN chmod +x /usr/local/bin/act_runner
RUN mkdir /opt/act
COPY run.sh /opt/act/run.sh
RUN chmod +x /opt/act/run.sh
ENTRYPOINT ["/usr/bin/tini", "--", "/opt/act/run.sh"]

以下のコマンドでビルド

$ docker image build -f Dockerfile -t "act_runner:debian-trixie" ./

設定ファイルを生成し、修正

giteaインスタンスを動かしているサーバーではSSLにLet's Encryptを使っているためか、リモートからact_runnerを登録しようとすると弾かれてしまう。おそらくルート証明書の問題。イメージビルド中に内部でルート証明書の更新をすることで対応できるかもしれないが、詳しいことがわからず。
設定で証明書のチェックをスルーすることができるので今回はその方法で。
まずは以下のコマンドで基本的な設定をconfig.yamlファイルに書き出し。

$ docker run --entrypoint '' act_runner:debian-trixie /usr/local/bin/act_runner generate-config > config.yaml

設定ファイル中の
runner:insecuretrue
runner:labels内を空に、もしくはコメントアウト

config.yaml
...
runner:
...
  insecure: true
...
  labels:
    # - "ubuntu-latest:docker://gitea/runner-images:ubuntu-latest"
    # - "ubuntu-22.04:docker://gitea/runner-images:ubuntu-22.04"
    # - "ubuntu-20.04:docker://gitea/runner-images:ubuntu-20.04"

コンテナを実行

以下のコマンドでコンテナを実行、giteaインスタンスへ登録。
giteaインスタンスのURLやトークン等は環境に合わせて値を設定。

docker run \
	-v $PWD/config.yaml:/config.yaml \
	-v $PWD/data:/data \
	-v /var/run/docker.sock:/var/run/docker.sock \
	-e CONFIG_FILE=/config.yaml \
	-e GITEA_INSTANCE_URL=https://gitea.example.com \
	-e GITEA_RUNNER_REGISTRATION_TOKEN=0XX0XXx0XXX0XXx000X0x0xX00xxXxXXxxXX0Xx0 \
	-e GITEA_RUNNER_NAME=debian-trixie \
	-e GITEA_RUNNER_LABELS=debian-trixie \
	--name debian-trixie \
	-d act_runner:debian-trixie

ランナーが登録できているか確認

ブラウザからgiteaインスタンスへ管理アカウントでログインし、右上に表示されるアバター画像をクリック、表示されるメニューからサイト管理を選択。
表示されるページ左のメニューからActionsを選択してサブメニューを展開、サブメニューのランナーを選択。
以下のイメージのようなページが表示されるため、ランナーがリストされているか確認。

ワークフローを作成しテストを実行してもらう

準備が整ったので実際にワークフローを作成し、ランナーでテストを実行してもらう。
まずはgiteaでリポジトリを作成し、cloneしておく。

テストを実行する準備

簡単にテストできそうということでひとまずローカルにgoの環境を用意し、cloneしてきたプロジェクトディレクトリ上で以下のコマンドを実行

go mod init local

以下のテスト対象ファイルを作成

cmd/main.go
package main

func Message() string {
	return "Hello world."
}

func main() {
	println(Message())
}

以下のテストファイルを作成

cmd/main_test.go
package main

import (
	"testing"
)

func TestMessage(t *testing.T) {
	got := Message()
	want := "Hello world."
	if got != want {
		t.Errorf("Message() == %s, want %s", got, want)
	}
}

以下のワークフローファイルを作成。
GitHubのドキュメントにあるものに少し手を加えたもの。
runs-onの行で実行させたいランナーのラベルを指定、ここではリモートのdebianコンテナのものを指定。
debian-trixieランナーではgoを実行する環境が無いのでaptgolangパッケージもインストール。

.github/workflows/github-actions-demo.yml
name: GitHub Actions Demo
run-name: ${{ github.actor }} is testing out GitHub Actions 🚀
on: [push]
jobs:
  Explore-GitHub-Actions:
    runs-on: debian-trixie
    steps:
      - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
      - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
      - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
      - run: git config --global http.sslVerify false
      - run: apt install -y golang
      - name: Check out repository code git
        uses: actions/checkout@v4
      - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
      - run: echo "🖥️ The workflow is now ready to test your code on the runner."
      - name: List files in the repository
        run: |
          ls ${{ github.workspace }}
      - name: Run test
        run: |
          go test -v -cover ./...
      - run: echo "🍏 This job's status is ${{ job.status }}."

ワークフローの実行を確認

ワークフローの実行はリモートリポジトリにpushするだけ。
push後、giteaの対象リポジトリ内のactionタブに実行されたワークフローがリストされるので、リストタイトル(コミットメッセージの1行目)をクリックし、詳細を見る。
Run testを開くと以下のようにテスト結果が確認できる。

この記事ではひとまずここで完了
あとは実際運用しながら調整していく。

参考

91works Tech Blog

Discussion