Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

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.

deploy/README.md +8−2

@@ -6,13 +6,19 @@ The files here put a Vole instance on a fresh machine. The guides are in
6 6 | Path | What it is |
7 7 |---|---|
8 8 | `cloud-init/vole.yaml` | The first-boot file. Installs the package, writes the configuration, creates the instance admin, starts the service. Used by every path below |
9 | `cloud-init/render.sh` | Renders that file for a machine you create by hand, with no Terraform |
10 | `terraform/hetzner`, `terraform/digitalocean`, `terraform/aws` | One complete Terraform configuration per cloud: machine, firewall, address, and optional DNS record. Each is used as a root module |
9 | `cloud-init/runner.yaml` | The CI runner's first-boot file: rootless Podman, an unprivileged account, a pinned host key, and the unit enabled |
10 | `cloud-init/render.sh` | Renders either first-boot file for a machine you create by hand, with no Terraform |
11 | `terraform/hetzner`, `terraform/digitalocean`, `terraform/aws` | One complete Terraform configuration per cloud: machine, firewall, address, optional DNS record, and `-var runner=true` for a second machine that runs CI jobs. Each is used as a root module |
11 12 | `docker/Dockerfile` | The server in one image, built from this repository |
12 13 | `docker/compose.yaml` | That image, with a volume for the instance and a health check |
13 14 | `docker/vole.toml` | The configuration the image starts with, and the file to copy for a deployment |
14 15 | `docker/entrypoint.sh` | Runs `vole admin init` once, then the command you asked for |
15 16
17 The runner's unit and its configuration example ship in the package, not here:
18 `packaging/systemd/vole-runner.service` and `packaging/runner.env`. One binary is
19 the forge, the runner, the CLI, and the library, so one package carries both
20 units.
21
16 22 Two things are deliberate:
17 23
18 24 - **The cloud-init file is the single source of truth.** The Terraform