Einen Runner sicher einrichten
Diese Anleitung fügt einer SupaCloud-Installation einen Runner hinzu — eine separate Maschine, die Agent-Aufgaben abholt und ausführt. Der Runner verbindet sich rein ausgehend über HTTPS und arbeitet daher hinter NAT ohne eingehende Ports. Für die Konzepte (Pull-Transport, laufspezifisches Secret-Modell, die zwei Bedeutungen von „Runner-Flotte”) siehe die Erklärung Die Runner-Flotte.
1. Hub-Modus aktivieren (Server)
Abschnitt betitelt „1. Hub-Modus aktivieren (Server)“-
Setze eine Umgebungsvariable auf dem Server und starte ihn neu:
SUPACLOUD_HUB_MODE=trueDer Standard ist
false. Solange aus, läuft jede Aufgabe lokal — egal wie viele Runner registriert sind. Genau das macht es sicher, den Hub-Modus im Notfall auszuschalten, ohne etwas zu deregistrieren. -
Bestätige, dass er an ist:
Terminal-Fenster curl https://supacloud.example.com/api/runners/config \-H "Authorization: Bearer <admin-session-oder-API-token>"# → { "hub_mode_enabled": true }
2. Worker-Node registrieren (Server)
Abschnitt betitelt „2. Worker-Node registrieren (Server)“-
Registriere den Runner als System-Admin und sichere das Token:
Terminal-Fenster curl -X POST https://supacloud.example.com/api/runners \-H "Authorization: Bearer <admin-session-oder-API-token>" \-H "Content-Type: application/json" \-d '{"name": "gpu-worker-01","capabilities": { "images": ["unified"], "max_parallel": 2 }}' -
Die Antwort enthält das Klartext-Bearer-Token (
scrn_…) genau einmal — der Server speichert nur dessen SHA-256-Hash. Kopiere es jetzt; im nächsten Schritt übergibst du es dem Worker. Geht es verloren, rotiere das Token, statt neu zu registrieren.
Wasm-Connector- und Skript-Ausführung bewerben
Abschnitt betitelt „Wasm-Connector- und Skript-Ausführung bewerben“Ein Runner kann sich auch dafür entscheiden, Wasm auf seinem Node auszuführen — sowohl Marketplace-Connector-Nodes als auch freie Skripte (JS / TS / Python). Beides läuft in derselben WASI-0.2-Sandbox (pro Lauf Speicher- und Wall-Clock-Grenzen, deny-all-SSRF-geprüfter Egress) hinter der eigenen OS-Grenze des Runners. Zwei Capability-Schlüssel steuern das:
connectors: true— der Runner entscheidet sich, Connector-Node-Wasm auszuführen. Der Hub schickt einem Node ohne dieses Flag nie einen Connector-Lauf.wasm.script_languages— die Skriptsprachen, deren Interpreter das Image des Runners tatsächlich bereitgestellt hat. Der Hub schickt einen Skript-Lauf nur an einen Runner, der sowohlconnectors: trueals auch die Sprache des Skripts hier bewirbt (ein Skript führt Wasm auf dem Node aus, also muss der Node sich für die Wasm-Ausführung entschieden haben und den Interpreter besitzen).
{ "name": "wasm-worker-01", "capabilities": { "images": ["unified"], "connectors": true, "wasm": { "script_languages": ["js", "ts", "py"] } }}Liste nur Sprachen auf, deren Interpreter der Runner unter
SUPACLOUD_SCRIPT_RUNTIME_DIR tatsächlich bereitgestellt hat (reproduzierbar
gebaut durch scripts/build-script-runtimes.sh). Der Matcher ist
fail-closed: ein fehlender oder fehlerhafter wasm-Schlüssel bedeutet, dass
der Runner keine Skriptsprache bewirbt und nie ein Skript erhält — eine
bestehende Flotte bleibt also völlig unberührt, und das Hinzufügen des Schlüssels
ist ein sicheres, monotones Opt-in.
Wird ein Skript an die Flotte verteilt, schickt der Hub nur Metadaten — die Sprache plus Quelltext und Eingaben als Daten — und einen SHA-256-Integritätsanker seines eigenen Interpreters. Er schickt nie den mehrere MB großen Interpreter. Der Runner löst seinen eigenen lokalen, vertrauenswürdigen Interpreter für diese Sprache auf und prüft den SHA erneut, bevor er ausführt; eine Abweichung (Versionsdrift oder Manipulation) schlägt fail-closed fehl. Eine Anfrage, die versucht, Interpreter-Bytes einzuschmuggeln, wird als Protokollverletzung abgelehnt. Der Interpreter ist stets ein lokal vertrauenswürdiges Runner-Asset — ein per Payload mitgeschickter wird nie ausgeführt.
Das wird instanzweit über SUPACLOUD_CONNECTOR_EXECUTOR_MODE gesteuert
(in_process — der Standard — / pooled / runner_fleet); setze es auf
runner_fleet, um Connector- und Skript-Läufe an die Flotte zu verteilen.
Mit dem Standardmodus in_process laufen Skripte auf dem Hub genau wie zuvor —
für bestehende Deployments ist dies ein No-op ohne Konfiguration.
Einen Drittanbieter-Runner onboarden (Enrollment)
Abschnitt betitelt „Einen Drittanbieter-Runner onboarden (Enrollment)“Abschnitt 2 erzeugt ein langlebiges scrn_…-Bearer für einen Runner, den du
betreibst. Um einen Runner auf einem Host hochzufahren, dem du weniger vertraust —
die Maschine einer Kundin, Edge-Compute, die GPU-Box einer Partnerin — nutze
stattdessen den Enrollment-Ablauf. Du übergibst dem Betreiber ein
einmaliges, kurzlebiges Enrollment-Token; sein Runner tauscht es beim Boot
gegen ein scope-begrenztes, kurzlebiges scrnj_…-JWT ein und erneuert es
automatisch. Der Betreiber hält nie ein langlebiges Hub-Credential, und der Runner
kann ausschließlich die Workspaces bedienen, auf die du ihn scopt hast. Zum
Trust-Modell dahinter siehe Runner-Flotten-Sicherheit.
-
Enrollment-Token erzeugen (Admin). Wähle Trust-Klasse, Ausführungs-Tier, Isolation und die Workspaces, die der Runner bedienen darf:
Terminal-Fenster curl -X POST https://supacloud.example.com/api/runners/enroll \-H "Authorization: Bearer <admin-session-oder-API-token>" \-H "Content-Type: application/json" \-d '{"class": "edge","tier": "docker","isolation": "container","allowed_workspace_ids": ["<workspace-uuid>"],"allowed_labels": []}'classisttrustedoderedge;tieristwasm,dockeroderboth;isolationistcontainerodermicrovm. Die Antwort enthält das Klartext-Enrollment-Token genau einmal (der Server speichert nur dessen Hash) und eine kurze Ablaufzeit. Kopiere es jetzt und übergib es dem Betreiber über einen sicheren Kanal. -
Worker mit dem Installer onboarden (Betreiber). Der Betreiber führt den gehosteten Ein-Zeilen-Installer aus. Dieser lädt das signierte Runner-Artefakt, verifiziert Prüfsumme und Signatur, installiert das Binary und bootet den Runner — rein ausgehend, keine eingehenden Ports:
Terminal-Fenster curl -fsSL https://supacloud.example.com/install-runner.sh | \SUPACLOUD_HUB_URL=https://supacloud.example.com \SUPACLOUD_RUNNER_ENROLLMENT_TOKEN=<einmal-token> \SUPACLOUD_RUNNER_NAME=customer-edge-01 \SUPACLOUD_RUNNER_LABELS=windows,unity,gpu \bashDas Runner-Binary selbst tauscht das Enrollment-Token ein: beim Boot im
--runner-Modus ruft es den gRPC-RPCRunnerService.ExchangeToken({enrollment_token, name, capabilities}→ das scope-begrenztescrnj_…-JWT, ADR 0050) und bewirbtcapabilities.labels(klein gefaltet ausSUPACLOUD_RUNNER_LABELS) plus diebackends/isolationdes konfigurierten Backends. Der Installer trägt nur das einmalige Token und die Labels; er hält nie einen Bearer. Zum Onboarding ohne Installer setzt duSUPACLOUD_RUNNER_ENROLLMENT_TOKEN(undSUPACLOUD_RUNNER_LABELS) und startest das Binary oder Image genau wie in Abschnitt 3 — oder, wenn du den Eintausch selbst fährst, setzt du stattdessenSUPACLOUD_RUNNER_TOKEN=<das scrnj_-JWT>. -
Der Runner erneuert sein JWT automatisch. Der Eintausch verbrennt das Enrollment-Token (es lässt sich nicht erneut verwenden) und liefert ein scope-begrenztes
scrnj_…-JWT, das Trust-Klasse, Tier, Isolation und die erlaubten Workspaces trägt. Das JWT lebt höchstens eine Stunde; der Runner-Daemon holt ein frisches, bevor das alte abläuft — standardmäßig bei etwa der halben Token-TTL, abgeleitet austoken_expires_atdes Grants / dem JWT-exp—, und jede Erneuerung ruft den grant-prüfenden gRPC-RPCRunnerService.RefreshTokendes Hubs auf, sodass der Entzug eines Workspaces innerhalb einer Token-Lebensdauer wirkt. Um den Takt explizit festzulegen, setzeSUPACLOUD_RUNNER_TOKEN_REFRESH_SECSauf die Anzahl Sekunden-vor-Ablauf, bei der neu eingetauscht wird (0, der Standard, bedeutet automatisch ableiten).
Neustart und Reboot: Token-Persistenz
Abschnitt betitelt „Neustart und Reboot: Token-Persistenz“Das Enrollment-Token ist einmalig: sobald der Runner es einlöst, ist es verbraucht und nicht wiederverwendbar. Ein enrolter Runner persistiert deshalb das erhaltene scope-begrenzte JWT und liest es beim nächsten Start wieder ein:
- Das JWT wird nach
SUPACLOUD_RUNNER_TOKEN_FILEgeschrieben; die Installer setzen dies aufrunner-tokenunter dem State-Verzeichnis des Runners —/var/lib/supacloud-runner, wenn der Installer als root läuft, sonst$XDG_STATE_HOME/supacloud-runner; unter Windows%LOCALAPPDATA%\supacloud\state. (Der eingebaute Fallback des Runner-Binaries ist$XDG_STATE_HOME/supacloud-runner/runner-token, unter Windows%LOCALAPPDATA%\supacloud\runner-token.) - Der Schreibvorgang ist atomar (eine Temp-Datei im selben Verzeichnis, dann ein Rename) und der Dateimodus ist 0600.
- Beim Boot liest der Runner die Datei bevor er irgendetwas eintauschen würde.
Ein noch gültiges Token wird unverändert verwendet — kein zweiter
ExchangeToken-Aufruf — ein Reboot braucht also kein frisches Enrollment-Token. Eine abgelaufene, fehlerhafte oder für Gruppe/Andere lesbare Datei wird verworfen, und der Runner enrolt stattdessen neu. - Jede erfolgreiche JWT-Erneuerung schreibt das frische Token zurück, sodass die Datei dem lebenden Credential folgt.
Die Datei ist ein Bearer-Secret at rest: halte den Runner-Host und sein
State-Verzeichnis privat, und beachte, dass --uninstall sie entfernt. Um beim
Aktualisieren des Binaries eine persistierte Runner-Identität
weiterzuverwenden, führe den Installer ohne SUPACLOUD_ENROLLMENT_TOKEN aus;
ein übergebenes Token erzwingt immer ein frisches Enrollment (der Installer
verwirft die alte Datei, damit das neue Token eingelöst wird).
3. Runner online bringen (Worker-Node)
Abschnitt betitelt „3. Runner online bringen (Worker-Node)“Der Runner ist dasselbe SupaCloud-Binary im --runner-Modus. Wähle die
Plattform, auf der du installierst. In jedem Fall ist die Konfiguration dieselbe
Menge an Umgebungsvariablen; nur der Start unterscheidet sich.
Ein-Zeilen-Installer (signiertes Binary)
Abschnitt betitelt „Ein-Zeilen-Installer (signiertes Binary)“Sobald dein Release-Kanal die signierten Binaries hostet, übernehmen die
Installer das gesamte Onboarding auf einer Worker-Node — Plattform erkennen,
das gepinnte Binary herunterladen, Prüfsumme und Signatur verifizieren,
installieren und supacloud-runner --runner über TLS ohne eingehende Ports
starten. Der Runner selbst tauscht das einmalige Enrollment-Token ein und
bewirbt seine Labels als Capabilities, sodass der Betreiber in Sekunden wieder
in der UI ist. Das einzige Secret, das du übergibst, ist das einmalige
Enrollment-Token aus dem Mint-Schritt; der Skript-Body enthält keines.
Linux / macOS (genau die Ein-Zeilen-Anweisung, die die SupaCloud-UI dir gibt):
curl -fsSL "$SUPACLOUD_URL/install-runner.sh" \ | SUPACLOUD_ENROLLMENT_TOKEN=<einmal-token> \ SUPACLOUD_RUNNER_LABELS=gpu,blender \ bashWindows (PowerShell):
$env:SUPACLOUD_URL = "https://supacloud.example.com"$env:SUPACLOUD_ENROLLMENT_TOKEN = "<einmal-token>"$env:SUPACLOUD_RUNNER_LABELS = "gpu,blender"irm "$env:SUPACLOUD_URL/install-runner.ps1" | iexDie SupaCloud-UI zeigt nach dem Minten beide Ein-Zeiler (der Runner-Host muss
nicht das OS des Browsers sein). Labels werden vor dem Senden klein gefaltet und
dedupliziert, sodass ein handgetipptes GPU und ein vorgeschlagenes gpu EIN
Label sind — die Flotte vergleicht Labels mit exakter Gleichheit, und ein nicht
gefaltetes GPU würde etwas bewerben, wonach keine Aufgabe je fragen kann.
Nützliche Overrides (Umgebungsvariablen, beide Installer): SUPACLOUD_RUNNER_NAME
(Standard: Hostname), SUPACLOUD_RUNNER_VERSION / SUPACLOUD_DOWNLOAD_BASE (ein
bestimmtes Release oder einen Artifact-Host pinnen) und
SUPACLOUD_RUNNER_DRY_RUN=1, um den aufgelösten Download-, Verify- und
Start-Plan auszugeben, ohne das Netzwerk anzufassen.
Der Hub leitet diese Pfade auf den veröffentlichten, gestempelten Installer in deinem Release-Feed um — er trägt das Skript nicht selbst, es gibt also genau eine Kopie. Konfiguriere den Feed mit zwei server-seitigen Variablen:
SUPACLOUD_RUNNER_VERSION— die Release-Version, z. B.v0.7.0.SUPACLOUD_RUNNER_DOWNLOAD_BASE— die Basis-URL des Release-Feeds, z. B.https://git.blockworx.tech/api/packages/bw-public/generic/supacloud-runner.
Das Redirect-Ziel ist <download base>/<version>/install-runner.{sh,ps1}. Bis beide
gesetzt sind, antworten die Einstiegspunkte mit 503 — onboarde bis dahin über das
Docker-Image oder ein selbstgebautes Binary (das Enrollment-Token funktioniert
identisch). Version/Download-Basis und die Signatur-Anker backt runner-release.yml
in den veröffentlichten Installer; der Hub stempelt oder schreibt ihn nie um.
Autostart-Dienst und Deinstallation
Abschnitt betitelt „Autostart-Dienst und Deinstallation“Die Ein-Zeilen-Installer registrieren einen Autostart-Dienst, damit der Runner nach einem Reboot zurückkommt und sauber außer Betrieb genommen werden kann:
- Linux: eine systemd-Unit — eine System-Unit als root, sonst eine
User-Unit (
systemctl --user, mit aktiviertem Lingering, damit sie ohne Login startet). Ist systemd nicht verfügbar, fällt der Installer auf einen dokumentiertennohup-Start zurück und druckt den Folge-Befehl; erzwinge den Fallback mitSUPACLOUD_RUNNER_NO_SERVICE=1. Logs gehen ins Journal (journalctl -u supacloud-runner -f) oder im Fallback ins State-Verzeichnis. - macOS: ein launchd
LaunchDaemon(root) oderLaunchAgent(User) mitRunAtLoad+KeepAlive; stdout/stderr gehen nachrunner.out.log/runner.err.logim State-Verzeichnis. - Windows: eine geplante Aufgabe — als
SYSTEMbeim Start, wenn der Installer erhöht läuft, sonst als aktueller Benutzer beim Logon (mit Rückfall auf den benutzereigenenRun-Schlüssel, wo der Aufgabenplaner gesperrt ist). Eine geplante Aufgabe stattsc.exe/New-Service, weil der Runner ein Konsolen-Binary ist, das das Service Control Protocol nicht implementiert und sonst nicht starten würde (Windows-Fehler 1053). Logs gehen nachlogs\runner.logunter dem Installationsverzeichnis.
Ein erneuter Installer-Lauf ist idempotent: er ersetzt das Binary und startet den
Dienst neu, und er verwendet das persistierte Token wieder, sofern du kein
frisches SUPACLOUD_ENROLLMENT_TOKEN übergibst. Um alles zu entfernen — Dienst,
Binary und persistiertes Token —:
curl -fsSL "$SUPACLOUD_URL/install-runner.sh" | bash -s -- --uninstall.\install-runner.ps1 -UninstallSUPACLOUD_RUNNER_INSTALL_DIR, SUPACLOUD_RUNNER_STATE_DIR und
SUPACLOUD_RUNNER_TOKEN_FILE platzieren Binary, State-Verzeichnis und Token-Datei
explizit.
Gemeinsame Konfiguration (alle Plattformen)
Abschnitt betitelt „Gemeinsame Konfiguration (alle Plattformen)“SUPACLOUD_HUB_URL=https://supacloud.example.comSUPACLOUD_RUNNER_TOKEN=scrn_xxxxxxxxxxxxxxxxxxxxxxxxSUPACLOUD_RUNNER_NAME=gpu-worker-01# Optionale Takt-Overrides (sinnvolle Defaults gezeigt):# SUPACLOUD_RUNNER_HEARTBEAT_SECS=30# SUPACLOUD_RUNNER_POLL_SECS=3# Docker-Netzwerk für Agent-Container (muss auf dem Worker existieren):# AGENT_NETWORK=supacloud-agentsDie Hub-URL muss https:// sein. Ein Klartext-http://-Hub wird beim Start
abgelehnt, außer du setzt explizit
SUPACLOUD_RUNNER_ALLOW_INSECURE_TRANSPORT=true — nur in einem vertrauenswürdigen
privaten Netz je akzeptabel.
Linux / macOS
Abschnitt betitelt „Linux / macOS“-
Lege die obigen Variablen in eine
.envneben das Binary (oder exportiere sie), dann:Terminal-Fenster supacloud --runner -
Oder mit dem Docker-Image (Docker-Socket einhängen, damit der Runner Agent-Container auf seinem eigenen Host starten kann):
Terminal-Fenster docker run -d --name supacloud-runner \-e SUPACLOUD_HUB_URL=https://supacloud.example.com \-e SUPACLOUD_RUNNER_TOKEN=scrn_xxxxxxxxxxxxxxxxxxxxxxxx \-e SUPACLOUD_RUNNER_NAME=gpu-worker-01 \-v /var/run/docker.sock:/var/run/docker.sock \<dein-supacloud-image> --runner
Windows
Abschnitt betitelt „Windows“-
Der Runner braucht einen Docker-Host, um Agent-Container zu starten — installiere Docker Desktop (WSL-2-Backend) auf dem Worker.
-
Setze die Variablen in PowerShell für die Sitzung und starte das Binary:
Terminal-Fenster $env:SUPACLOUD_HUB_URL = "https://supacloud.example.com"$env:SUPACLOUD_RUNNER_TOKEN = "scrn_xxxxxxxxxxxxxxxxxxxxxxxx"$env:SUPACLOUD_RUNNER_NAME = "win-worker-01".\supacloud.exe --runnerFür einen dauerhaft laufenden Worker führe denselben Befehl als Dienst aus (z. B. mit NSSM) oder nutze den Docker-Image-Befehl aus dem Linux/macOS-Tab innerhalb von WSL 2.
microVM-Ausführungs-Backend (stärkste Isolation)
Abschnitt betitelt „microVM-Ausführungs-Backend (stärkste Isolation)“Das Standard-Backend docker führt jede Aufgabe in einem Container auf dem lokalen
Docker-Host des Runners aus. Für einen nicht vertrauenswürdigen oder Edge-Runner
ist das microVM-Backend die stärkste Isolationsstufe: jede beanspruchte Aufgabe
läuft in einem eigenen kurzlebigen hardware-virtualisierten Gast (eine
Firecracker/Kata-artige microVM), sodass ein kompromittierter Agent-Prozess hinter
einer VM-Grenze eingeschlossen ist, nicht nur in einem Kernel-Namespace. Wie die
Stufen sich vergleichen, siehe Runner-Flotte Defense-in-Depth →
Isolationsstufen.
-
Baue (oder beziehe) ein Runner-Binary, das mit dem
microvm-backend-Feature kompiliert wurde. -
Stelle auf dem Worker einen microVM-Launcher bereit (z. B. einen Firecracker/Kata-Wrapper), wähle dann das Backend und richte den Runner darauf aus:
SUPACLOUD_RUNNER_EXECUTION_BACKEND=microvmSUPACLOUD_RUNNER_MICROVM_CMD=/usr/local/bin/launch-microvm -
Onboarde (oder onboarde neu) den Runner mit
isolation: microvm, damit der fail-closed Dispatch-Filter des Hubs microVM-pflichtige Aufgaben an ihn und nur an ihn routet.
Den Runner-Transport mit mTLS absichern
Abschnitt betitelt „Den Runner-Transport mit mTLS absichern“Standardmäßig vertraut der Runner dem Hub über One-Way-TLS (der Hub präsentiert ein Server-Zertifikat; der Runner verifiziert es gegen den System-Trust-Store). Um einen gegenseitigen TLS-Handshake zu verlangen — sodass der Hub auch jeden Runner per Client-Zertifikat authentifiziert, ein starker zweiter Faktor zusätzlich zum Bearer-Token — konfiguriere beide Seiten. mTLS ist optional; ist nichts davon gesetzt, ist der Transport genau wie heute.
-
Auf dem Hub (Server). TLS direkt ausliefern und Client-Zertifikate verlangen:
SUPACLOUD_TLS_CERT_PATH=/etc/supacloud/tls/hub.crtSUPACLOUD_TLS_KEY_PATH=/etc/supacloud/tls/hub.keySUPACLOUD_TLS_CLIENT_CA_PATH=/etc/supacloud/tls/runner-ca.crtSUPACLOUD_TLS_CERT_PATH+SUPACLOUD_TLS_KEY_PATHschalten TLS ein;SUPACLOUD_TLS_CLIENT_CA_PATHverlangt und verifiziert zusätzlich ein Client-Zertifikat gegen diese CA. Eine Verbindung ohne vertrauenswürdiges Client-Zertifikat wird beim Handshake abgewiesen. -
Auf jedem Runner. Eine Client-Identität präsentieren und (optional) die Hub-CA pinnen:
SUPACLOUD_RUNNER_TLS_CLIENT_CERT_PATH=/etc/supacloud/tls/runner.crtSUPACLOUD_RUNNER_TLS_CLIENT_KEY_PATH=/etc/supacloud/tls/runner.keySUPACLOUD_RUNNER_TLS_CA_PATH=/etc/supacloud/tls/hub-ca.crt # optional: Hub-CA pinnen
4. Verifizieren
Abschnitt betitelt „4. Verifizieren“-
Beim Start macht der Runner einen Heartbeat-Aufruf. Wird das Token abgelehnt, beendet er sich sofort mit klarer Fehlermeldung; ist der Hub kurz nicht erreichbar, startet er trotzdem und versucht es weiter.
-
Die Zeile des Runners wechselt beim ersten erfolgreichen Heartbeat von
pending → online. Bestätige es vom Server aus:Terminal-Fenster curl https://supacloud.example.com/api/runners \-H "Authorization: Bearer <admin-session-oder-API-token>" -
Starte eine Aufgabe, deren Image der Runner bewirbt. Bei aktivem Hub-Modus und einem passenden Online-Runner verteilt der Server sie an den Runner, und der Live-Ereignisstrom zeigt den Fortschritt genau wie bei einem lokalen Lauf.