From 9da6118a3583dd2d2903b1c84b648e1799919852 Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Sun, 19 Jul 2026 13:14:17 +0200 Subject: [PATCH] [chore](trx-rs): add OpenRC service for act_runner on Alpine The runner host is Alpine (OpenRC, no systemd). Add an OpenRC init script for act_runner (supervise-daemon, depends on docker) plus a conf.d example for running one instance per project, and rewrite the runner section of the README with Alpine setup steps (apk docker, dedicated user in the docker group, register, service install). Assisted-By: Claude Code (claude-opus-4) Claude-Session: https://claude.ai/code/session_01NFpGtGTWUEYXLwZeZs2RAV Signed-off-by: Stan Grams --- container/README.md | 72 ++++++++++++++++++++++-------- container/act_runner.confd.example | 14 ++++++ container/act_runner.openrc | 44 ++++++++++++++++++ 3 files changed, 112 insertions(+), 18 deletions(-) create mode 100644 container/act_runner.confd.example create mode 100644 container/act_runner.openrc diff --git a/container/README.md b/container/README.md index 1fd15f16..8937d7a9 100644 --- a/container/README.md +++ b/container/README.md @@ -54,25 +54,61 @@ The `reuse` job stays on the upstream `fsfe/reuse-action` (a Docker action the Docker executor launches as a sibling container) — nothing REUSE-related is baked into the SDK. -## CI runner (VM) +## CI runner (Alpine / OpenRC) -The runner runs in a small VM using the **Docker executor** (not the host -executor). This gives per-job container isolation and standard `ubuntu-latest` -semantics, and caps CI resources at the VM boundary. +The runner uses the **Docker executor** (not the host executor): per-job +container isolation and standard `ubuntu-latest` semantics. `act_runner` runs +as an OpenRC service. Files provided: -1. **Size the VM to your thread budget.** 2 vCPUs = a hard 2-thread ceiling. - Pin them to specific host threads so CI never touches the rest (libvirt/KVM): +| File | Purpose | +|------|---------| +| `act_runner.openrc` | OpenRC init script (`supervise-daemon`, depends on docker). | +| `act_runner.confd.example` | Per-instance `conf.d` settings for multi-runner hosts. | - ```xml - 2 - - - - - ``` +**Cap the thread budget.** In a VM, pin its vCPUs to specific host threads +(libvirt/KVM): -2. **Inside the VM:** install Docker (moby) and `act_runner`. -3. **Register one runner per project** (separate tokens from each repo's - *Settings → Actions → Runners*; scope keeps their jobs apart). -4. **Configure** with `runner-config.example.yaml` — `capacity: 1` and - `container.options: "--cpus=2"` keep usage inside the 2-thread budget. +```xml +2 + + + + +``` + +On bare metal, the `container.options: "--cpus=2"` and `capacity: 1` in +`runner-config.example.yaml` already bound each runner. + +**Set it up:** + +```bash +# 1. Docker + a dedicated user with socket access +apk add docker docker-cli +rc-update add docker default && rc-service docker start +adduser -S -D -H -h /var/lib/act_runner act +addgroup act docker + +# 2. act_runner binary (static Go build, works on musl) +curl -fsSL -o /usr/local/bin/act_runner \ + https://gitea.com/gitea/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64 +chmod +x /usr/local/bin/act_runner + +# 3. Config + register one runner per project (scope keeps their jobs apart) +install -Dm644 container/runner-config.example.yaml /etc/act_runner/trx-rs.yaml +install -d -o act /var/lib/act_runner/trx-rs +su act -s /bin/sh -c 'cd /var/lib/act_runner/trx-rs && \ + act_runner register --no-interactive \ + --instance https://git.haxx.space --token \ + --name trx-rs-ci \ + --labels "ubuntu-latest:docker://catthehacker/ubuntu:act-latest"' + +# 4. OpenRC service (repeat the symlink+conf.d for the second project) +install -m755 container/act_runner.openrc /etc/init.d/act_runner +ln -s act_runner /etc/init.d/act_runner.trx-rs +install -m644 container/act_runner.confd.example /etc/conf.d/act_runner.trx-rs +rc-update add act_runner.trx-rs default +rc-service act_runner.trx-rs start +``` + +Check it with `rc-service act_runner.trx-rs status` and +`tail -f /var/log/act_runner.trx-rs.log`. diff --git a/container/act_runner.confd.example b/container/act_runner.confd.example new file mode 100644 index 00000000..b3ee409e --- /dev/null +++ b/container/act_runner.confd.example @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2026 Stan Grams +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Per-instance settings for an act_runner OpenRC service. +# Copy to /etc/conf.d/, e.g. /etc/conf.d/act_runner.trx-rs +# (the name must match the /etc/init.d/ symlink). + +# User that runs the daemon. Must be a member of the `docker` group. +runner_user="act" + +# Per-instance state dir (holds the .runner registration) and config file, +# so two runners on one host stay independent. +runner_dir="/var/lib/act_runner/trx-rs" +runner_config="/etc/act_runner/trx-rs.yaml" diff --git a/container/act_runner.openrc b/container/act_runner.openrc new file mode 100644 index 00000000..5c87aff3 --- /dev/null +++ b/container/act_runner.openrc @@ -0,0 +1,44 @@ +#!/sbin/openrc-run +# SPDX-FileCopyrightText: 2026 Stan Grams +# SPDX-License-Identifier: GPL-2.0-or-later +# +# OpenRC service for a Gitea act_runner (Docker executor) on Alpine. +# +# Install as /etc/init.d/act_runner (chmod +x). Single instance uses +# /etc/act_runner/config.yaml. For one runner per project, symlink this script +# and add a matching conf.d file: +# +# ln -s act_runner /etc/init.d/act_runner.trx-rs +# cp container/act_runner.confd.example /etc/conf.d/act_runner.trx-rs +# $EDITOR /etc/conf.d/act_runner.trx-rs # set runner_dir / runner_config +# rc-update add act_runner.trx-rs default +# rc-service act_runner.trx-rs start + +description="Gitea Actions runner" + +: "${runner_user:=act}" +: "${runner_dir:=/var/lib/act_runner}" +: "${runner_config:=/etc/act_runner/config.yaml}" + +command="/usr/local/bin/act_runner" +command_args="daemon --config ${runner_config}" +# No group given, so supplementary groups (incl. docker) are initialised. +command_user="${runner_user}" +directory="${runner_dir}" + +supervisor="supervise-daemon" +respawn_delay=5 +respawn_max=0 +pidfile="/run/${RC_SVCNAME}.pid" +output_log="/var/log/${RC_SVCNAME}.log" +error_log="/var/log/${RC_SVCNAME}.log" + +depend() { + need docker + use net dns +} + +start_pre() { + checkpath -d -m 0750 -o "${runner_user}" "${runner_dir}" + checkpath -f -m 0640 -o "${runner_user}" "${output_log}" +}