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/terraform/hetzner/variables.tf +35

@@ -106,3 +106,38 @@ variable "cloud_init_file" {
106 106 type = string
107 107 default = ""
108 108 }
109
110 variable "runner" {
111 description = "Create a second machine that runs CI jobs. See docs/deploy/runner.md: an admin has to register its key and allow it on a repository before it receives any work."
112 type = bool
113 default = false
114 }
115
116 variable "runner_type" {
117 description = "Server type for the runner. Builds want memory, so this is worth raising before the instance's own type."
118 type = string
119 default = "cx22"
120 }
121
122 variable "runner_labels" {
123 description = "Labels this runner advertises, which a job's runs-on asks for."
124 type = list(string)
125 default = ["linux"]
126 }
127
128 variable "runner_network" {
129 description = "none gives a job no network even if it asks; bridge gives one to a job that asks. Jobs that fetch dependencies need bridge."
130 type = string
131 default = "bridge"
132
133 validation {
134 condition = contains(["none", "bridge"], var.runner_network)
135 error_message = "runner_network must be none or bridge."
136 }
137 }
138
139 variable "runner_cloud_init_file" {
140 description = "Override the runner's user data file. Empty uses deploy/cloud-init/runner.yaml from this repository."
141 type = string
142 default = ""
143 }