v0.2.0 43088fd

ermite-runner.service RawHistoryFolder

1# SPDX-License-Identifier: MIT
2#
3# systemd unit of the ermite runner. Install the static binary as
4# /usr/local/bin/ermite-runner, write the settings to /etc/ermite-runner/env
5# (mode 0600) and register the runner once; the README has the commands.
6#
7# The runner runs as root: it creates TAP devices and nftables rules (vm), loop
8# mounts and containers (container), and starts the jailer. Jobs never run as
9# root on the host: they run in a micro-VM or a container as user "runner".
10#
11# The sandboxing below is what can be added without breaking those jobs.
12# What is deliberately NOT set, and why, is listed at the end of the file and
13# in the README.
14[Unit]
15Description=ermite CI runner
16Documentation=https://git.bnema.dev/bnema/ermite-runner
17Wants=network-online.target
18After=network-online.target docker.service
19
20[Service]
21Type=simple
22EnvironmentFile=/etc/ermite-runner/env
23ExecStart=/usr/local/bin/ermite-runner run
24Restart=on-failure
25RestartSec=5
26
27# SIGTERM cancels the running jobs with runner_shutdown, reports them and removes
28# their sandboxes. With the defaults that takes at most 90 s (30 s for the
29# executor to stop its steps, 30 s to destroy the sandbox, 30 s to report; the
30# jobs do this in parallel). A test checks that this value leaves 15 s of margin
31# over host.Timing.ShutdownBudget.
32KillMode=mixed
33KillSignal=SIGTERM
34TimeoutStopSec=120
35
36# The state directory holds the runner token (0600), the VM images and the
37# per-job files; RuntimeDirectory is for the lock and sockets.
38StateDirectory=ermite-runner
39StateDirectoryMode=0700
40RuntimeDirectory=ermite-runner
41
42# Jobs are many processes.
43TasksMax=infinity
44LimitNOFILE=1048576
45
46# ---- sandboxing that leaves the unit in the host's mount namespace ----------
47# Only options that do not give the unit a mount namespace of its own: in
48# container mode the runner loop-mounts the scratch disk of a job, and the Docker
49# daemon, which lives in the host's namespace, must see that mount to bind it
50# into the container. See the end of the file.
51NoNewPrivileges=yes
52# The runner does not set the clock.
53ProtectClock=yes
54# No setuid/setgid files created by the runner or its children.
55RestrictSUIDSGID=yes
56LockPersonality=yes
57# The runner does not need real-time scheduling.
58RestrictRealtime=yes
59# Syscall architectures: native only.
60SystemCallArchitectures=native
61# Address families the runner and its children use: Unix sockets (Docker, the
62# executor stream), IPv4/IPv6 (the server, the DNS forwarder), netlink (ip, nft,
63# TAP devices), packet (none needed: left out), vsock (the executor stream in a
64# micro-VM).
65RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK AF_VSOCK
66
67[Install]
68WantedBy=multi-user.target
69
70# ---- deliberately absent -----------------------------------------------------
71#
72# PrivateTmp=, ProtectHome=, ProtectSystem=, ProtectKernelModules=,
73# ProtectKernelLogs=, ProtectKernelTunables=, ProtectControlGroups=,
74# PrivateDevices=, ReadOnlyPaths=, ReadWritePaths=, InaccessiblePaths=,
75# TemporaryFileSystem=, BindPaths=
76#                     Each of these puts the unit in a mount namespace of its own
77#                     (systemd sets one up for ProtectKernelModules and
78#                     ProtectKernelLogs too: it hides /usr/lib/modules and
79#                     /proc/kmsg with mounts). In container mode the runner
80#                     loop-mounts the scratch disk of a job below the state
81#                     directory, and the Docker daemon, in the host's namespace,
82#                     cannot see a mount made inside the unit's: the bind
83#                     sources of the container would be empty directories. The
84#                     micro-VM mode would tolerate them, but one unit serves both
85#                     modes and a second unit for VM-only hardening is not worth
86#                     it. test: internal/host TestUnitHasNoMountNamespaceOptions.
87#
88# Delegate=yes        The runner does not manage cgroups of its own. The jailer
89#                     creates the cgroups of the VMs below /sys/fs/cgroup itself
90#                     (it is root and writes there directly), and Docker has its
91#                     own. Delegation would hand a subtree to this unit that
92#                     nothing uses.
93# PrivateNetwork=, RestrictNamespaces=,
94# CapabilityBoundingSet=, MemoryDenyWriteExecute=, SystemCallFilter=
95#                     The runner creates network namespaces and devices (TAP,
96#                     veth, bridges) and mounts file systems, enables
97#                     net.ipv4.ip_forward (the jailer also writes cgroups, /dev/kvm, /dev/net/tun and
98#                     /dev/loop* are needed), hands capabilities to the jailer and
99#                     to Docker, and starts Firecracker (which maps guest memory
100#                     writable and executable). Each of these would break a path
101#                     that cannot be tested without a rootful host; the
102#                     boundary of a job is the micro-VM or the container, not
103#                     this unit.
104# UMask=0077          The state directory is made 0700 by the runner itself, and the
105#                     drivers create directories that the job's user must be able
106#                     to enter (the scratch disk's work and tmp directories are
107#                     made with mode 0755): a restrictive umask would turn them
108#                     into root-only directories, which cannot be tested without
109#                     a rootful host.

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