Self-Hosted Bare Metal Runners
Ein Self-Hosted Runner ist ein Bare Metal Runner, den Sie selbst betreiben und verwalten,
anstatt einen von Bencher verwalteten On-Demand- oder Dedicated Runner zu nutzen.
Sie richten das runner-Binary auf einen Bencher API-Server aus,
und es beansprucht und führt Jobs auf Ihrer eigenen Hardware aus.
Das Self-Hosting eines Runner eignet sich gut, wenn Sie Folgendes möchten:
- Benchmarks auf spezifischer Hardware ausführen, die Bencher Cloud nicht anbietet
- Benchmark-Workloads innerhalb Ihres eigenen Netzwerks oder in einer Air-Gapped-Umgebung halten
- Bencher Self-Hosted durchgängig betreiben
Dieser Leitfaden führt durch das Registrieren eines Runner, das Beschreiben seiner Hardware mit einer Spec,
das Verknüpfen beider und das Starten des runner-Binary.
Einen konzeptionellen Überblick darüber, wie Runner, Specs, Sandboxes und Jobs zusammenpassen,
finden Sie in der Bare Metal-Übersicht.
🐰 Firecracker-Sandboxing erfordert Linux 5.14 oder neuer mit aktiviertem KVM und einer beschreibbaren cgroup-v2-Hierarchie unter
/sys/fs/cgroup, und der Runner muss alsrootlaufen. Jeder Sandbox-Job läuft in einer eigenen Cgroup unter/sys/fs/cgroup/bencher, unabhängig von der Zahl der CPU-Kerne, mit aktivierten Controllerncpuset,memoryundpids. Der Runner beendet die Prozesse eines Jobs übercgroup.killdieser Cgroup, das ältere Kernel nicht haben: Dort beendet sich ein Runner beim Start, oder er lässt, mit--danger-allow-no-sandboxgestartet, jeden Sandbox-Job fehlschlagen. Der Firecracker-Prozess hinter jedem Sandbox-Job wird in einem Chroot als unprivilegierter Benutzer eingesperrt, und der Aufbau dieser Isolierung benötigt Rechte, die das Aktivieren von KVM allein nicht gewährt. Ein Runner, der nur Specs ohne Sandbox bedient, kann auf jedem unterstützten Host laufen.
Einen Runner erstellen
Ein Runner ist die Ressource, die das runner-Binary gegenüber Ihrem Bencher API-Server authentifiziert.
Erstellen Sie einen mit der bencher CLI,
der Runners REST-API
oder der Bencher Console.
bencher runner create \ --host https://api.bencher.example.com \ --name "My Runner"Bencher gibt den neuen Runner zusammen mit seinem Schlüssel zurück:
{ "uuid": "...", "key": "bencher_runner_..."}Der Schlüssel wird nur einmal angezeigt, bewahren Sie ihn also sicher auf.
Sie übergeben ihn dem runner-Binary, wenn Sie den Runner starten.
Falls ein Schlüssel jemals verloren geht oder durchsickert, rotieren Sie ihn mit der POST /v0/runners/{runner}/key-API,
was den vorherigen Schlüssel sofort ungültig macht.
Eine Spec erstellen
Eine Spec beschreibt die Hardware, die ein Runner bereitstellt: Betriebssystem, CPU-Architektur, Sandbox-Typ, CPU-Anzahl, Arbeitsspeicher, Festplatte und Netzwerkzugriff. Ein Job deklariert die Spec, die er benötigt, und ein Runner beansprucht nur Jobs für Specs, die er unterstützt.
Erstellen Sie eine Spec mit der bencher CLI,
der Specs REST-API
oder der Bencher Console:
bencher spec create \ --host https://api.bencher.example.com \ --name "Intel v1" \ --os linux \ --architecture x86_64 \ --sandbox firecracker \ --cpu 4 \ --memory 51539607552 \ --disk 137438953472Lassen Sie --sandbox weg, um eine Spec ohne Sandbox zu definieren,
und übergeben Sie --network, wenn Jobs auf dieser Spec Netzwerkzugriff erhalten dürfen.
Arbeitsspeicher und Festplatte werden in Bytes angegeben.
Mehr zu Specs und wie ein Testbed die für jeden Report verwendete Spec aufzeichnet,
finden Sie unter Testbeds & Specs.
Eine Spec einem Runner zuweisen
Eine Runner Spec verknüpft eine Spec mit einem Runner. Ein Runner kann mehrere Specs unterstützen, und eine Spec kann von mehreren Runnern unterstützt werden. Ein Runner beansprucht nur Jobs, deren Spec ihm zugewiesen wurde.
Fügen Sie eine Spec zu einem Runner mit der bencher CLI
oder der Runner Specs REST-API hinzu:
bencher runner spec add my-runner \ --host https://api.bencher.example.com \ --spec intel-v1Entfernen Sie die Verknüpfung später mit der DELETE /v0/runners/{runner}/specs/{spec}-API.
Den Runner starten
Sobald ein Runner erstellt und mindestens eine Spec zugewiesen ist,
starten Sie das runner-Binary auf Ihrer Hardware mit runner up.
Geben Sie den API-Server-Host, die Runner-UUID oder den Slug sowie den Runner-Schlüssel an,
entweder als Flags oder als Umgebungsvariablen:
runner up \ --host https://api.bencher.example.com \ --runner my-runner \ --key bencher_runner_...export BENCHER_HOST=https://api.bencher.example.comexport BENCHER_RUNNER=my-runnerexport BENCHER_RUNNER_KEY=bencher_runner_...runner upDas runner-Binary öffnet eine einzige WebSocket-Verbindung zum API-Server,
fragt Jobs ab, die zu seinen Specs passen, führt jeden aus und meldet die Ergebnisse zurück.
Die Verbindung bleibt über Jobs hinweg offen,
und das Binary aktualisiert sich selbst zwischen Jobs, wenn eine neue Version verfügbar ist.
Standardmäßig folgt der Runner dem stable Update-Kanal
und aktualisiert nur auf versionierte Releases.
Der canary-Kanal folgt stattdessen dem rollierenden Canary-Build von Bencher Cloud.
Ein Runner, der Sandbox-Jobs ausführt, muss als root laufen,
die obigen Befehle werden also so gezeigt, wie der Benutzer root sie ausführen würde,
oder unter einem Dienstmanager, der den Runner als root startet.
Standardmäßig lehnt ein Runner jeden Job ab, dessen Spec keine Sandbox hat.
Um einem Runner zu erlauben, Jobs ohne Sandbox direkt auf dem Host auszuführen,
starten Sie ihn mit dem --danger-allow-no-sandbox-Flag.
runner uprunner upStartet den Runner und fragt Benchmark-Jobs ab und führt sie aus. Dies ist der langlaufende Befehl zum Betrieb eines Self-Hosted Runner. Der Runner öffnet eine einzige WebSocket-Verbindung zum API-Server, beansprucht Jobs, die zu seinen Specs passen, führt sie aus und meldet die Ergebnisse zurück. Der Runner schreibt sein Log als JSON nach stderr, ein Objekt pro Zeile, und protokolliert die Ausgabe eines Jobs nur als Byte-Anzahl.
runner up [OPTIONS]Optionen
--host <HOST>Der Bencher API-Server, zu dem eine Verbindung hergestellt werden soll. Standardmäßig wird
https://api.bencher.devverwendet. Kann auch mit der UmgebungsvariableBENCHER_HOSTgesetzt werden.--runner <RUNNER>Die UUID oder der Slug des Runner, als der agiert werden soll. Kann auch mit der Umgebungsvariable
BENCHER_RUNNERgesetzt werden.--key <KEY>Der Runner-Authentifizierungsschlüssel (
bencher_runner_...), der zurückgegeben wurde, als der Runner erstellt wurde. Kann auch mit der UmgebungsvariableBENCHER_RUNNER_KEYgesetzt werden.--poll-timeout <POLL_TIMEOUT>Das Long-Poll-Timeout in Sekunden beim Warten auf einen Job, zwischen
1und900. Standardmäßig wird55verwendet.--state-dir <STATE_DIR>Das persistente Zustandsverzeichnis für den Runner. Es muss ein absoluter Pfad sein. Das Jail, das die Sandbox einschließt, wird unter diesem Verzeichnis erstellt, und Jails, die durch eine unsaubere Beendigung zurückgeblieben sind, werden vor jedem Sandbox-Job daraus entfernt. Jedes Jail enthält ein vollständiges Gast-Root-Dateisystem und eine Kopie der microVM-Binärdatei, und ein Runner führt seine Jobs nacheinander aus, daher braucht dieses Verzeichnis echte Kapazität für ein Jail. Mit
--image-cache-sizeenthält es zusätzlich den Image-Cache, bis zu dieser Größe. Auf einem Host läuft immer nur ein Runner, unabhängig von seinem Zustandsverzeichnis: Ein alsrootgestarteter Runner hält die Sperre/run/bencher/runner.lock, solange er läuft, und ein zweiter, alsrootgestarteter beendet sich sofort mit einem Fehler, der diese Sperre nennt; ein Runner, der nicht alsrootläuft, kann die Sperre nicht öffnen und läuft ohne sie. Beim Start und erneut vor jedem Sandbox-Job beendet ein alsrootgestarteter Runner jeden Prozess, der noch in einer Cgroup unter/sys/fs/cgroup/bencherläuft, etwa die Sandbox eines Runners, der mitten in einem Job beendet wurde, unabhängig vom Zustandsverzeichnis dieses Runners. Ein eigenes Dateisystem oder eintmpfs-Mount wird unterstützt und empfohlen: es hält diese Schreiblast von der Systemplatte fern, und ein neu erstelltes Dateisystem wird akzeptiert, auch wenn es einlost+found-Verzeichnis mitbringt. Das Dateisystem darf nicht mitnodevodernoexeceingehängt sein, wie es/tmp,/dev/shmund/runoft sind; hängen Sie dafür also eintmpfsohne diese Optionen ein. Das Zustandsverzeichnis selbst darf ein von root angelegter symbolischer Link auf ein solches Dateisystem sein, etwa/var/lib/bencher-runnerauf eine eigene Platte. Dem Link wird nur gefolgt, wenn das Verzeichnis, das ihn enthält, nur von root beschreibbar ist, er direkt auf sein endgültiges Ziel zeigt und dieses Ziel bereits auf einem nur von root beschreibbaren Pfad existiert; ein Link, dessen Ziel noch nicht existiert, wird abgelehnt, also zuerst das Ziel anlegen. Standardmäßig wird/var/lib/bencher-runnerverwendet. Kann auch mit der UmgebungsvariableBENCHER_STATE_DIRgesetzt werden.--jail-uid <JAIL_UID>Die unprivilegierte Benutzer-ID, auf die der Sandbox-Prozess wechselt. Standardmäßig wird
61016verwendet. Sie darf nicht0sein. Ein Prozess auf dem Host, dem diese Benutzer-ID gehört, kann Signale an die Sandbox senden, setzen Sie sie also auf eine ID, die der Host nichts anderem zuweist. Kann auch mit der UmgebungsvariableBENCHER_JAIL_UIDgesetzt werden.--jail-gid <JAIL_GID>Die unprivilegierte Gruppen-ID, auf die der Sandbox-Prozess wechselt. Standardmäßig wird
61016verwendet. Sie darf nicht0sein. Kann auch mit der UmgebungsvariableBENCHER_JAIL_GIDgesetzt werden.--danger-allow-no-sandboxErlaubt das Ausführen von Jobs ohne Sandbox. Ohne dieses Flag wird ein Job, dessen Spec keine Sandbox hat, zur Laufzeit abgelehnt. Jobs ohne Sandbox laufen direkt auf dem Host, aktivieren Sie dies also nur für vertrauenswürdige Workloads. Kann auch mit der Umgebungsvariable
BENCHER_DANGER_ALLOW_NO_SANDBOXgesetzt werden.--sandbox-log-level <SANDBOX_LOG_LEVEL>Das Log-Level für den Sandbox-Prozess. Standardmäßig wird
warningverwendet.--no-raid-pauseWeiterhin Jobs annehmen, während ein md-RAID-Array auf dem Host resynchronisiert, wiederherstellt, prüft, repariert oder umformt. Standardmäßig prüft der Runner seine md-Arrays, bevor er nach jedem Job fragt, und solange eines davon einen dieser Vorgänge ausführt, pausiert er: Er nimmt keinen neuen Job an, bis die Synchronisierung abgeschlossen ist, und er stoppt nie einen Job, der bereits läuft. Ein pausierter Runner bleibt verbunden und aktualisiert sich weiterhin selbst.
--no-auto-updateDeaktiviert automatische Updates vom Server. Standardmäßig aktualisiert sich der Runner zwischen Jobs selbst, wenn der Server eine neue Version anbietet. Kann auch mit der Umgebungsvariable
BENCHER_NO_AUTO_UPDATEgesetzt werden.--update-channel <UPDATE_CHANNEL>Der Update-Kanal für automatische Updates, entweder
stableodercanary. Standardmäßig wirdstableverwendet. Derstable-Kanal aktualisiert auf versionierte Releases. Dercanary-Kanal folgt dem rollierenden Canary-Build, der neu gebaut wird, wann immer sich der Runner bei einem Bencher Cloud-Deployment ändert. Kann auch mit der UmgebungsvariableBENCHER_UPDATE_CHANNELgesetzt werden. Steht im Konflikt mit--no-auto-update.--max-download-size <MAX_DOWNLOAD_SIZE>Die maximale Download-Größe in Bytes für Self-Update-Binaries. Standardmäßig werden
500MiB verwendet. Steht im Konflikt mit--no-auto-update.--image-cache-size <IMAGE_CACHE_SIZE>Die maximale Größe in Bytes der Image-Blobs, die der Runner über Jobs hinweg behält. Der Runner behält die Config- und Layer-Blobs jedes Image, das er herunterlädt, in
blobsunter seinem--state-dir, sodass ein Job nur die Blobs herunterlädt, die der Runner noch nicht hat, das Manifest seines Image aber trotzdem jedes Mal aus der Registry abruft. Zwischen Jobs entfernt der Runner die am längsten nicht verwendeten Blobs, bis der Rest in diese Größe passt. Beim Start legt der Runner den Speicher an und macht ihn zu seinem eigenen; kann er das nicht, beendet er sich sofort mit einem Fehler, der das Verzeichnis nennt. Standardmäßig, oder mit0, behält der Runner keine Blobs über Jobs hinweg und entfernt alle, die er zuvor behalten hat. Kann auch mit der UmgebungsvariableBENCHER_IMAGE_CACHE_SIZEgesetzt werden.--max-output-size <MAX_OUTPUT_SIZE>Die maximale Größe in Bytes für erfasstes
stdoutundstderr. Standardmäßig werden25MiB verwendet.--max-file-count <MAX_FILE_COUNT>Die maximale Anzahl an Ausgabedateien, die dekodiert werden. Standardmäßig wird
255verwendet.--max-symlinks <MAX_SYMLINKS>Die maximale Anzahl an Symlinks, denen bei der Pfadauflösung gefolgt wird, entsprechend dem
MAXSYMLINKS-Limit des Linux-Kernels. Standardmäßig wird40verwendet. Wird nur im Modus ohne Sandbox verwendet.Host-Tuning
Vor jedem Benchmark wendet der
runnerHost-Tuning an, um Messrauschen zu reduzieren. Standardmäßig deaktiviert er ASLR, den NMI-Watchdog, SMT / Hyper-Threading und Turbo Boost; setzt den CPU-Scaling-Governor aufperformance, Swappiness auf10undperf_event_paranoidauf-1. Auf einem Host, auf den derrunnerseit dem letzten Neustart kein Host-Tuning angewendet hat, belassen die folgenden Flags einzelne Optimierungen stattdessen bei ihren Host-Standardwerten.Das Host-Tuning bleibt bis zum Neustart des Hosts bestehen: Jede Einstellung ist ein reiner Laufzeit-Schreibvorgang, den der
runnerbeim Beenden nicht zurücksetzt, mit Ausnahme der C-State-Sperre, die endet, wenn sich derrunnerbeendet. Nach einem Lauf mit Host-Tuning wirkt ein Flag, das eine andere Einstellung überspringt, erst ab dem nächsten Neustart: Bis dahin behält die Einstellung ihren getunten Wert, und derrunnerprotokolliert diesen Wert beim Start. Starten Sie einen gemeinsam genutzten Host neu, nachdem Sie denrunnerentfernt haben.--no-tuningDeaktiviert alle Host-Tuning-Optimierungen.
--aslrDeaktiviert ASLR nicht (Standard: für Benchmarks deaktiviert).
--nmi-watchdogDeaktiviert den NMI-Watchdog nicht (Standard: für Benchmarks deaktiviert).
--smtDeaktiviert SMT / Hyper-Threading nicht (Standard: für Benchmarks deaktiviert).
--turboDeaktiviert Turbo Boost nicht (Standard: für Benchmarks deaktiviert).
--numa-balancingDeaktiviert das automatische NUMA-Balancing nicht (Standard: für Benchmarks deaktiviert).
--timer-migrationDeaktiviert die Timer-Migration nicht (Standard: für Benchmarks deaktiviert).
--soft-watchdogDeaktiviert den Soft-Lockup-Watchdog nicht (Standard: für Benchmarks deaktiviert).
--ksmDeaktiviert KSM, das Kernel Samepage Merging, nicht (Standard: für Benchmarks deaktiviert).
--cstatesDeaktiviert tiefe C-States nicht (Standard: für Benchmarks deaktiviert).
--no-irq-steeringLenkt Geräte-IRQs und Kernel-Workqueues nicht auf Housekeeping-Kerne.
--no-cpuset-partitionLöst Benchmark-Kerne nicht über eine isolierte cpuset-Partition vom Scheduler.
--swappiness <SWAPPINESS>Setzt den Swappiness-Wert. Standardmäßig wird
10verwendet.--governor <GOVERNOR>Setzt den CPU-Scaling-Governor. Standardmäßig wird
performanceverwendet.--perf-event-paranoid <PERF_EVENT_PARANOID>Setzt den
perf_event_paranoid-Wert. Standardmäßig wird-1verwendet.--thp <THP>Setzt den Transparent-Hugepage-Modus des Hosts:
never,madvise,alwaysoderleave. Mitleavebleibt der aktuelle Modus des Hosts erhalten. Standardmäßig wirdneververwendet.--helpHilfe ausgeben.
Die runner CLI-Referenz beschreibt jede Option,
und die Runner Protocol-Referenz beschreibt die mit dem Server ausgetauschten Nachrichten.
Host-Wartung
Ein Runner und die Wartung seines Hosts, etwa Paket-Upgrades oder ein RAID-Scrub, wechseln sich ab, sodass Wartung nie während eines Jobs läuft.
Sie wechseln sich über /run/bencher ab, ein Verzeichnis, das ein als root gestarteter Runner nur für root anlegt:
- Die Job-Sperre,
/run/bencher/job.lock. Der Runner nimmt sie, bevor er nach einem Job fragt, und hält sie, bis diese Abfrage ohne Job endet oder der Job, den sie bringt, endet. Wartung wartet auf die Sperre und beginnt daher nur zwischen Jobs, und ein Runner, der die Sperre belegt vorfindet, nimmt keinen Job an, bis sie frei ist. - Wartungsmarker,
/run/bencher/maintenanceoder/run/bencher/maintenance.<name>. Wartung legt ihren eigenen Marker an, bevor sie auf die Sperre wartet, und entfernt ihn, wenn sie fertig ist. Solange ein Marker existiert, fragt der Runner nach keinem Job und lässt die Sperre frei, sodass wartende Wartung beginnt, sobald die laufende Abfrage des Runners oder der Job, den diese bringt, endet.
Während er auf Wartung wartet, ist ein Runner pausiert: Er bleibt verbunden und aktualisiert sich weiterhin selbst.
runner run wartet ebenfalls auf die Job-Sperre und warnt, läuft aber, solange ein Marker existiert oder ein md-Array synchronisiert.
Ein Runner, der nicht root ist, kann weder die Job-Sperre öffnen noch die Marker sehen und nimmt Jobs daher ohne sie an.
Mit systemd sorgt ein Drop-in dafür, dass eine Wartungs-Unit sich einreiht.
Zum Beispiel umschließt /etc/systemd/system/fstrim.service.d/zz-bencher-quiet.conf den eigenen Befehl der Unit mit flock -F.
Das leere ExecStart= löscht diesen Befehl, daher muss die nächste Zeile ihn exakt wiederholen:
[Service]ExecStartPre=+/usr/bin/install -d -m 0700 /run/bencherExecStartPre=+/usr/bin/touch /run/bencher/maintenance.%nOpenFile=/dev/nullExecStart=ExecStart=/usr/bin/flock -F /run/bencher/job.lock /sbin/fstrim --listed-in /etc/fstab:/proc/self/mountinfo --verbose --quiet-unsupportedExecStopPost=+/bin/sh -c '/usr/bin/busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager PreparingForShutdown | /usr/bin/grep -q true || /usr/bin/rm -f /run/bencher/maintenance.%n'TimeoutStartSec=infinityOpenFile=/dev/null belegt den Dateideskriptor 3, sodass die Sperre gehalten bleibt, auch wenn der Befehl den Deskriptor 3 neu öffnet, wie es apt.systemd.daily tut.
Während sich der Host auf das Herunterfahren vorbereitet, lässt ExecStopPost= den Marker stehen, sodass der Runner keinen Job annimmt, bevor der Neustart /run leert.
Einen Runner leeren
Um einen Runner zu leeren, legen Sie als root den einfachen Marker an:
touch /run/bencher/maintenanceDer Runner beendet seine laufende Abfrage, höchstens --poll-timeout Sekunden, und jeden Job, der läuft oder den diese Abfrage bringt, und nimmt danach keinen weiteren Job an, bis der Marker entfernt ist:
rm /run/bencher/maintenance/run wird beim Booten geleert, daher entfernt auch ein Neustart den Marker.
Self-Hosted Runner-Workflow
Sobald der Runner verbunden ist, reichen Sie Benchmarks auf dieselbe Weise ein wie bei jedem Bare Metal Runner:
Erstellen und pushen Sie ein Image und führen Sie dann bencher run --image mit einer passenden Spec aus.
Das folgende Diagramm zeigt den vollständigen Weg, vom Registrieren des Runner bis zum Ausführen eines Jobs.