v0.5.0 22211fd

service.md RawHistoryFolder

Service

contrib/ermite-runner.service is a systemd unit. For the commands to install it, see the README.

Privileges

  • The runner runs as root on the host. It needs TAP devices, nftables, loop mounts, the jailer and Docker.
  • Jobs never run as root on the host. They run as user runner in a microVM or a container.

Registration

  • Register in the same environment as the service, so register and run agree on the URL, name, labels, isolation and state directory.
  • systemd-run with the same EnvironmentFile does this.
  • register picks the isolation mode like run will. It sends the name, labels, version, isolation and architecture.

Logs

  • The runner writes to standard error, which journald collects.
  • Set ERMITE_RUNNER_LOG_FORMAT=json under journald. Every line about a job has job_id, run_id and attempt.
  • warn marks what is retried. error marks what is refused or leaked.
  • ERMITE_RUNNER_LOG_LEVEL=debug adds detail.
  • Tokens are never logged.

Stopping

systemctl stop sends SIGTERM. The runner:

  1. Cancels running jobs with runner_shutdown.
  2. Reports them to the server.
  3. Removes their sandboxes.

Budget with the defaults:

Step Time
Executor stops its steps and runs post-steps 30 s
Destroy the sandbox 30 s
Flush the log and report 30 s
Total 90 s
  • Jobs stop in parallel. The total does not grow with ERMITE_RUNNER_CAPACITY.
  • The unit sets TimeoutStopSec=120.
  • A job whose first heartbeat is pending at SIGTERM is not started. The server gives it to another runner after 30 s.
  • A crash or power cut leaves sandboxes behind. The next start reaps them.

Unit hardening

The unit sets only options that keep it in the host's mount namespace:

  • NoNewPrivileges
  • ProtectClock
  • RestrictSUIDSGID
  • LockPersonality
  • RestrictRealtime
  • SystemCallArchitectures=native
  • RestrictAddressFamilies (UNIX, INET, INET6, NETLINK, VSOCK)

Do not add:

  • Options that give the unit its own mount namespace: PrivateTmp, ProtectHome, ProtectSystem, ProtectKernelModules, ProtectKernelLogs, ProtectKernelTunables, ProtectControlGroups, PrivateDevices, ReadOnlyPaths, ReadWritePaths, InaccessiblePaths, TemporaryFileSystem, BindPaths. In container mode the runner loop-mounts the job disk and the Docker daemon, in the host namespace, must see it. A test fails if the unit sets one of them.
  • PrivateNetwork, RestrictNamespaces, CapabilityBoundingSet, SystemCallFilter: the runner creates network devices, mounts filesystems and hands capabilities to the jailer and Docker.
  • MemoryDenyWriteExecute: Firecracker maps guest memory writable and executable.
  • Delegate and UMask: not needed.

The security boundary of a job is its microVM or container, not the unit.

source
1# Service
2
3`contrib/ermite-runner.service` is a systemd unit. For the commands to install it, see the [README](../README.md#register-and-run).
4
5## Privileges
6
7- The runner runs as root on the host. It needs TAP devices, nftables, loop mounts, the jailer and Docker.
8- Jobs never run as root on the host. They run as user `runner` in a microVM or a container.
9
10## Registration
11
12- Register in the same environment as the service, so `register` and `run` agree on the URL, name, labels, isolation and state directory.
13- `systemd-run` with the same `EnvironmentFile` does this.
14- `register` picks the isolation mode like `run` will. It sends the name, labels, version, isolation and architecture.
15
16## Logs
17
18- The runner writes to standard error, which journald collects.
19- Set `ERMITE_RUNNER_LOG_FORMAT=json` under journald. Every line about a job has `job_id`, `run_id` and `attempt`.
20- `warn` marks what is retried. `error` marks what is refused or leaked.
21- `ERMITE_RUNNER_LOG_LEVEL=debug` adds detail.
22- Tokens are never logged.
23
24## Stopping
25
26`systemctl stop` sends SIGTERM. The runner:
27
281. Cancels running jobs with `runner_shutdown`.
292. Reports them to the server.
303. Removes their sandboxes.
31
32Budget with the defaults:
33
34| Step | Time |
35| --- | --- |
36| Executor stops its steps and runs post-steps | 30 s |
37| Destroy the sandbox | 30 s |
38| Flush the log and report | 30 s |
39| **Total** | **90 s** |
40
41- Jobs stop in parallel. The total does not grow with `ERMITE_RUNNER_CAPACITY`.
42- The unit sets `TimeoutStopSec=120`.
43- A job whose first heartbeat is pending at SIGTERM is not started. The server gives it to another runner after 30 s.
44- A crash or power cut leaves sandboxes behind. The next start reaps them.
45
46## Unit hardening
47
48The unit sets only options that keep it in the host's mount namespace:
49
50- `NoNewPrivileges`
51- `ProtectClock`
52- `RestrictSUIDSGID`
53- `LockPersonality`
54- `RestrictRealtime`
55- `SystemCallArchitectures=native`
56- `RestrictAddressFamilies` (UNIX, INET, INET6, NETLINK, VSOCK)
57
58Do not add:
59
60- Options that give the unit its own mount namespace: `PrivateTmp`, `ProtectHome`, `ProtectSystem`, `ProtectKernelModules`, `ProtectKernelLogs`, `ProtectKernelTunables`, `ProtectControlGroups`, `PrivateDevices`, `ReadOnlyPaths`, `ReadWritePaths`, `InaccessiblePaths`, `TemporaryFileSystem`, `BindPaths`. In `container` mode the runner loop-mounts the job disk and the Docker daemon, in the host namespace, must see it. A test fails if the unit sets one of them.
61- `PrivateNetwork`, `RestrictNamespaces`, `CapabilityBoundingSet`, `SystemCallFilter`: the runner creates network devices, mounts filesystems and hands capabilities to the jailer and Docker.
62- `MemoryDenyWriteExecute`: Firecracker maps guest memory writable and executable.
63- `Delegate` and `UMask`: not needed.
64
65The security boundary of a job is its microVM or container, not the unit.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 4

Tags 11

↑↓ moveenter openesc close