手元メモからGit運用へ移したあなたへ
設定ファイルや小さな自動化スクリプトが増えてくると、「変更前に最低限の検査くらいは自動で走らせたい」と考える時期が来ます。家庭ラボに自前のGitサーバーを置いた人なら、Gitea Actionsで軽いCIを回したいと思うのは自然です。
ただ、CIの実用差が出るのは動いた瞬間ではありません。runnerが止まったまま誰も気づかない時、失敗ログの読み方が分からず結局手動確認に戻る時、検査ジョブが本番環境に触れていないか不安になる時——そこで初めて「常用してよい仕組みか」が決まります。
そこで今回は、便利さの紹介ではなく「壊れ方を先に観測できるか」という観点で、某所ラボの使い捨てDocker隔離VMにGiteaとact_runnerを本番非接続のまま立て、構築から撤去までを実コマンドで追いました。結論を先に言うと、構築・隔離・完全撤去は確実に行えました。一方で、肝心のジョブ結果(成功表示・失敗ログ・キュー滞留・再実行)の観測導線では今回つまずいており、その範囲も改変せず残します。
なぜ「成功」より先に壊れ方を確かめるのか
Gitea ActionsはGitea本体とrunner(act_runner)を分けて扱います。runnerの停止や登録ミスを本体と独立して観測できるため、使い捨て環境で小さく壊して見るのに向いています。家庭ラボの実運用で効いてくるのは、成功時の自動化よりも、失敗時のログ確認と「再実行してよい変更か」の判断です。だからこそ常用前に、止まった時・落ちた時の見え方を先に確認する価値があります。
検証環境
- 環境: 某所ラボの使い捨てDocker隔離VM(検証後に破棄)
- Docker Engine 29.6.0 / Docker Compose v5.2.0 / ベースはDebian bookworm
- Gitea 1.22(公式イメージ) / act_runner(latest)
- 公開ポートは 127.0.0.1:3000 のみにbindし、本番ネットワークからは非接続
- 認証情報・トークン値・内部アドレスは記載しません(すべて使い捨て)
実行コマンドとログ
1. Docker確認と使い捨てラボ定義の配置
まずホスト側のDockerとComposeを確認します。
$ docker version
$ docker compose version
Server: Docker Engine - Community
Version: 29.6.0
Docker Compose version v5.2.0
作業ディレクトリに次のCompose定義を置きます。ポイントは 127.0.0.1:3000 への限定bindで、本番から切り離した状態にしていることです。
services:
gitea:
image: gitea/gitea:1.22
environment:
- GITEA__security__INSTALL_LOCK=true
- GITEA__server__ROOT_URL=http://gitea:3000/
- GITEA__actions__ENABLED=true
ports:
- "127.0.0.1:3000:3000"
volumes:
- gitea-data:/data
runner:
image: gitea/act_runner:latest
environment:
- 設定項目=http://gitea:3000
- 設定項目=${設定項目:-}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- runner-data:/data
volumes:
gitea-data:
runner-data:
Gitea本体だけ先に起動し、待受を確認します。
$ docker compose up -d gitea
$ docker compose ps
$ ss -ltnp | grep 3000
設定項目 設定項目 設定項目 設定項目
issue-lab-gitea-1 gitea/gitea:1.22 gitea Up
設定項目 0 4096 127.0.0.1:3000 0.0.0.0:* users:(("docker-proxy",...))
待受が 127.0.0.1:3000 だけであることが確認できました。本番非接続の意図どおりです。
2. Gitea初期化・検証用リポジトリ作成・各トークン発行
起動完了を待ってから、管理ユーザーと検証用のprivateリポジトリを作ります(パスワードや発行トークンは使い捨てのため非掲載)。
$ docker compose exec -T -u git gitea gitea admin user create --username labadmin --email [email protected] --admin --password '<throwaway>'
$ docker compose exec -T -u git gitea gitea admin user generate-access-token --username labadmin --scopes 'all' --raw
$ curl -s -X 設定項目 'http://localhost:3000/api/v1/user/repos' -H "Authorization: token $API" -H 'Content-Type: application/json' -d '{"name":"cilab","auto_init":true,"private":true}' | jq '.full_name,.empty'
$ docker compose exec -T -u git gitea gitea actions generate-runner-token
New user 'labadmin' has been successfully created!
"labadmin/cilab"
false
アクセストークンとrunner登録トークンが発行され、labadmin/cilab が初期化済み(empty=false)で作成できました。
3. runner起動と正常ワークフローの投入
発行したrunner登録トークンを .env 経由で渡し、runnerを起動します。続いて成功ケースのワークフローを投入します。ワークフローの内容は次のとおりです。
name: ci
on: [push]
jobs:
echo:
runs-on: ubuntu-latest
steps:
- run: echo ok-success-case
$ docker compose --env-file .env up -d runner
$ curl -s -X 設定項目 'http://localhost:3000/api/v1/repos/labadmin/cilab/contents/.gitea/workflows/ci.yml' -H "Authorization: token $API" -H 'Content-Type: application/json' -d "{...content...}" | jq '.commit.sha'
"34de539002e7b1a784c72b3a801477c2419ddeb2"
ワークフローファイルのcommit自体は成功しました(commit shaが返っています)。ただし、この後に実行したジョブ結果取得(actions/tasks を叩いてjqで整形)は想定外の応答で失敗し、ジョブが成功状態として表示されたかどうかは今回確認できていません。詳細は後述の「失敗・制約」に正直に残します。
4. runner停止・登録ミス・再実行の試行
ここからが本題で、壊れ方を作りにいきました。
- 不正トークンでの登録ミス再現
- 失敗ジョブ(存在しないコマンド)の投入
- runner停止中のpush(キュー滞留の確認)と再起動による回復
- 失敗→revertでの復旧(再実行・ロールバック)
停止操作とpush自体はいずれも成功しました。
$ docker compose stop runner
$ docker compose ps
設定項目 設定項目 設定項目 設定項目
issue-lab-gitea-1 gitea/gitea:1.22 gitea Up 6 minutes
runnerが落ち、Gitea本体は稼働を続けていることが確認できました。runner停止中のpush(trigger while down)もcommit shaが返り、成功しています。再起動も実施しました。
$ docker compose start runner
しかし、停止中のジョブが pending として滞留したか、再起動後にそれが消化されたか、という「見え方」については、結果取得が成功しなかったため確認できていません。失敗ジョブのログ表示、再実行後の最終ステータスも同様に未確証です。登録ミス再現の手順は、Gitea/runnerの挙動に届く前の実行経路でタイムアウトし、こちらも結果を観測できませんでした。
5. 後片付けと痕跡確認
最後に、隔離環境を完全に撤去します。
$ docker compose down -v
$ docker volume ls | grep issue || echo 'no volumes'
$ rm -rf ~/issue-lab
Volume issue-lab_runner-data Removing
Volume issue-lab_gitea-data Removing
workdir removed
コンテナとボリュームが削除され、作業ディレクトリも消えました。使い捨て検証として、構築から完全撤去まで痕跡を残さず行える点は確実に確認できました。
結果:今回確証できたこと
- Docker/Composeさえあれば、Gitea 1.22+act_runnerのCI環境はCompose一式で軽く構築できる
- 127.0.0.1:3000 への限定bindで、本番ネットワークから切り離した状態を待受レベルで確認できる
- 管理ユーザー作成、privateリポジトリの初期化、アクセストークン・runner登録トークンの発行まで一連で通る
- ワークフローファイルのcommit、runnerの停止・再起動、停止中のpushはいずれも操作として成立する
docker compose down -vと作業ディレクトリ削除で、ボリューム含め完全に撤去できる
失敗・制約・再現条件:観測の壁
正直に切り分けると、今回は「建てる・隔離する・片付ける」は確証できましたが、CIの実用差が出る「ジョブ結果の観測導線」には到達できませんでした。確認できなかったのは次の点です。いずれも成功・失敗のどちらにも断定しません。
- 正常ワークフローがジョブとして成功表示されたか
- 失敗ジョブのログがどの画面・どの応答から読めるか
- runner停止中にジョブが pending として滞留する見え方、再起動後の消化
- 再実行・revert後の最終ステータス
- 不正トークンでの登録ミスがどう表示・拒否されるか
直接の症状は二つでした。一つ目は、ジョブ結果取得で、APIの応答が想定したJSONオブジェクトではなく、jqが整形時に次のエラーで停止したことです。
jq: error (at <stdin>:1): Cannot index number with string "tasks"
parse error: Invalid numeric literal at line 1, column 9
二つ目は、登録ミス再現の手順が、Gitea/runnerに届く前の実行経路でタイムアウトし、ステップ自体が完了しなかったことです。
推定原因
症状一つ目は、ジョブ結果を取りに行ったエンドポイント/フィルタの前提が、実際の応答形と食い違っていた可能性が高いです。.tasks[0] や .workflow_runs[0] を前提にしていましたが、応答が想定どおりのオブジェクト配列ではなかったため、jqが数値や非JSONを掴んで落ちました。つまり「Gitea Actionsが動かなかった」のではなく、「結果の観測導線(叩く先と整形の前提)が固まっていなかった」というのが、今回の正直な解釈です。症状二つ目は手順側(実行経路の接続段)の問題で、runnerの登録挙動とは切り離して考えるべきものです。
再現・次に固めること
- 同じ手順を、使い捨てDocker環境で再実行可能(構築・撤去部分は再現性あり)
- ジョブ結果は、整形前にまず応答の生データを保存し、構造を確認してから読む
- API経由の整形に頼る前に、GiteaのWeb UI上のActionsタブでジョブの状態・ログの見え方を一次確認する
比較:手動確認/ローカルrunner/外部CI
読者が実際に迷う三択で並べます。「今回確認」「今回未確証」を正直に付しています。
| 観点 | 手動でコマンド確認 | Gitea Actions+ローカルrunner | 外部CIに預ける |
|---|---|---|---|
| 構築の手間 | 不要 | Compose一式で軽い(今回確認) | アカウント連携が必要 |
| 本番非接続で試せる範囲 | 手元次第 | 127.0.0.1 bindで隔離できる(今回確認) | リポジトリを外部に出す前提 |
| 撤去のしやすさ | — | down -vで完全撤去(今回確認) | 外部側に履歴が残りうる |
| 失敗ログの読みやすさ | 自分の画面で完結 | 観測導線の整備が要る(今回未確証) | 提供UIに依存 |
| runner停止時の気づきやすさ | 無関係 | 監視設計が必要(今回未確証) | 提供側が管理 |
家庭ラボに置く前の判断
「家庭ラボにGitea Actionsを置く価値があるか、まずどの失敗条件を見てから常用判断するか」という問いに対して、現時点で言えることを条件として整理します。
常用に進めてよい条件
- 検査ジョブの待受を 127.0.0.1 などに限定し、本番から切り離せること(今回確認済みの方法で可能)
down -vで完全に撤去できることを、本番投入前に一度確かめてあること- そして最重要として、ジョブ結果(成功・失敗・pending)と失敗ログの観測導線を、自分の環境で先に確認できていること
まだ常用を保留すべき条件
- ジョブが落ちた時・runnerが止まった時の見え方を一度も確認していない場合。今回の検証がまさにここで止まっており、CIの価値が出る部分を未確証のまま運用に乗せるのは避けるべきです
まとめると、構築と撤去の軽さという意味でGitea Actionsを使い捨てで試す価値はあります。ただし常用判断は、本記事が到達できなかった「ジョブ結果と失敗ログの観測導線」を、Web UIを含めてご自身で先に確かめてから下すことをおすすめします。便利さよりも、止まった時に気づける導線が整っているかが、家庭ラボで放置できるCIかどうかの分かれ目です。
この検証を回している環境
この検証は、自宅の常設ラボ(使い捨てVM/LXCを回す母艦+GPU+VLAN分離ネットワーク)で動かしています。使っている機材と選定理由、全体構成は1本にまとめています。
ラボ構成のまとめを見る →