vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
Ship the runner's unit and let a deployment create a runner machine
d0d4239f3f7236197c87a752d7965de238430f98 · Keenan Nemetz · 3d ago · parent dbae2e01
Ship the runner's unit and let a deployment create a runner machine The package installs one binary that is the forge, the runner, and the CLI, so it now carries a second unit. It is not enabled, and it refuses to start with a message until an operator fills in /etc/vole/runner.env: who runs builds on a machine is that machine owner's decision. The unit runs as a dedicated account, because rootless podman needs a home directory and a range of subordinate ids, and because a job should not find the forge's own account on the same disk. The arguments live in that one file rather than in the unit, split at spaces by systemd, so a single unit serves every machine. Each Terraform configuration takes runner=true and creates that machine beside the forge: its own firewall, no backups (its checkouts and caches are copies), the same key for a shell, and Cloud-init that installs the package, creates the account and its subuids, generates the runner's key, pins the instance's host key once, and enables the unit. The runner_setup output prints the three commands that let it take work, filled in with the addresses this apply created. The first-boot file cannot register the runner: the allowlist is per repository, and at first boot there are no repositories. That step stays with an instance admin, and the docs say so.
packaging/runner.env +25
| @@ -0,0 +1,25 @@ | |||
| 1 | # Arguments for vole-runner.service. One line, read by systemd and split at | ||
| 2 | # spaces, so it is written the way the command would be typed. | ||
| 3 | # | ||
| 4 | # The packages install this file with the arguments commented out, so enabling | ||
| 5 | # vole-runner without editing it fails with a message saying so. | ||
| 6 | # | ||
| 7 | # Start from this example and keep what applies: | ||
| 8 | # | ||
| 9 | # --remote the instance to lease jobs from. Required. | ||
| 10 | # --container-runtime docker, podman, or nerdctl. Rootless podman is | ||
| 11 | # preferred; see docs/runner.md. | ||
| 12 | # --container-network none (the default) or bridge. A machine without a | ||
| 13 | # network never receives a job that asks for one, and a | ||
| 14 | # job that fetches dependencies needs bridge. | ||
| 15 | # --label what this machine is, such as linux or arm64. A job | ||
| 16 | # with runs-on only comes to a runner carrying every | ||
| 17 | # label it asks for. | ||
| 18 | # --dir where checkouts and the cache live. | ||
| 19 | # --known-hosts the file holding the instance's SSH host key. Populate | ||
| 20 | # it once with ssh-keyscan; the runner executes | ||
| 21 | # repository code, so the instance it trusts is a | ||
| 22 | # security boundary. | ||
| 23 | # --repos narrow this machine to named repositories. | ||
| 24 | # | ||
| 25 | # VOLE_RUNNER_ARGS=--remote ssh://git@forge.example.com:2222 --container-runtime podman --container-network bridge --dir /var/lib/vole-runner --known-hosts /etc/vole/runner_known_hosts --label linux | ||