vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Blame · packaging/systemd/vole-runner.service
Line attribution on main · 72 line(s)
|
d0d4239f
Keenan Nemetz
3d ago
|
1 | [Unit] |
| 2 | Description=Vole CI runner | |
|
ed03b3d1
Keenan Nemetz
4h ago
|
3 | Documentation=https://rodent.software/vole |
|
d0d4239f
Keenan Nemetz
3d ago
|
4 | After=network-online.target |
| 5 | Wants=network-online.target | |
| 6 | ||
| 7 | # An instance that is down, or a name that does not resolve yet, is not a reason | |
| 8 | # to give up on the machine: the runner waits and tries again. | |
| 9 | StartLimitIntervalSec=0 | |
| 10 | ||
| 11 | [Service] | |
| 12 | Type=simple | |
| 13 | ||
| 14 | # A dedicated unprivileged account with a home directory and a subuid and subgid | |
| 15 | # range, so the container runtime is rootless. docs/deploy/runner.md has the two | |
| 16 | # commands that set it up. The instance's own account is not this one: a job that | |
| 17 | # escapes its container should not find the forge's data on the same machine. | |
| 18 | User=ci-runner | |
| 19 | Group=ci-runner | |
| 20 | Environment=HOME=/var/lib/vole-runner | |
| 21 | WorkingDirectory=/var/lib/vole-runner | |
| 22 | RuntimeDirectory=vole-runner | |
| 23 | RuntimeDirectoryMode=0700 | |
| 24 | Environment=XDG_RUNTIME_DIR=/run/vole-runner | |
| 25 | ||
| 26 | # The arguments live in a file so one unit serves every machine: --remote, | |
| 27 | # --label, --dir, --known-hosts, --container-network. See the example shipped as | |
| 28 | # /etc/vole/runner.env. | |
| 29 | EnvironmentFile=-/etc/vole/runner.env | |
| 30 | ExecStartPre=/bin/sh -c 'test -n "$VOLE_RUNNER_ARGS" || { echo "runner is not configured: set VOLE_RUNNER_ARGS in /etc/vole/runner.env" >&2; exit 1; }' | |
| 31 | ExecStart=/usr/bin/vole runner $VOLE_RUNNER_ARGS | |
| 32 | ||
| 33 | Restart=on-failure | |
| 34 | RestartSec=10s | |
| 35 | TimeoutStopSec=60s | |
| 36 | ||
| 37 | # Rootless podman creates a cgroup per container, which it can only do if this | |
| 38 | # service's own cgroup is delegated to it. | |
| 39 | Delegate=yes | |
| 40 | ||
|
4e3759da
Keenan Nemetz
2h ago
|
41 | # The backstop under the container limits. Each job gets --container-memory, and this |
| 42 | # bounds the whole runner including every job in flight, for the case where a job gets | |
| 43 | # past its own cgroup: a percentage is of the machine, so the unit does not have to | |
| 44 | # know how big it is. Size --jobs times --container-memory below it, and leave the rest | |
| 45 | # for the kernel and the runtime's own storage. TasksMax is deliberately not set: the | |
| 46 | # container's own --container-pids already applies to everything the runner starts, | |
| 47 | # and a unit-level value would have to track --jobs and --container-pids, failing | |
| 48 | # builds in a way that looks like the workflow's fault when it drifts. | |
| 49 | MemoryMax=90% | |
| 50 | ||
|
d0d4239f
Keenan Nemetz
3d ago
|
51 | # A core dump of this process is a copy of the runner's SSH key, which leases jobs |
| 52 | # and reports their results. | |
| 53 | LimitCORE=0 | |
| 54 | LimitNOFILE=65536 | |
| 55 | UMask=0027 | |
| 56 | PrivateTmp=true | |
| 57 | ||
| 58 | # Deliberately less sandboxed than vole.service: the isolation a job gets is its | |
| 59 | # container, and the runtime needs user namespaces and a writable home to build | |
| 60 | # one. Nothing here reaches the instance's data, because it is not on this | |
| 61 | # machine. | |
|
9704d735
Keenan Nemetz
3h ago
|
62 | # |
| 63 | # NoNewPrivileges is off for the same reason, and it is the one setting the unit | |
| 64 | # cannot keep. Rootless podman, Docker, and nerdctl all map the calling user into | |
| 65 | # the container through setuid newuidmap and newgidmap, and this setting stops a | |
| 66 | # setuid helper from gaining privilege, so the mapping fails before a container | |
| 67 | # exists: "newuidmap: write to uid_map failed: Operation not permitted". A job's | |
| 68 | # isolation is its container, not this sandbox, so the rest of the hardening stays. | |
| 69 | NoNewPrivileges=false | |
|
d0d4239f
Keenan Nemetz
3d ago
|
70 | |
| 71 | [Install] | |
| 72 | WantedBy=multi-user.target |