Runner steuern & überwachen
Sobald du mehr als einen Runner hast (siehe Einen Runner sicher einrichten), steuerst du, welcher Runner welche Arbeit erhält. Jeder Hebel hier ist standardmäßig aus — eine Flotte ohne gesetzte Hebel verteilt „erster Online-Runner, der das Image ausführen kann“, sodass du genau die Komplexität wählst, die du brauchst.
Labels & Fähigkeiten (Routing)
Abschnitt betitelt „Labels & Fähigkeiten (Routing)“Ein Runner bewirbt Fähigkeiten bei der Registrierung (zum Ändern neu registrieren
oder rotieren). Neben images bewirb freie Labels:
{ "images": ["unified"], "labels": ["gpu", "eu-west"], "max_parallel": 4 }Eine Aufgabe, die Labels verlangt, geht nur an einen Runner, der alle bewirbt
(Teilmengen-Abgleich, wie CI runs-on). Eine Aufgabe ohne verlangte Labels
ignoriert Labels vollständig — Labels hinzuzufügen ändert also nie das Routing
bestehender Arbeit.
Drain & Cordon (sanftes Stilllegen)
Abschnitt betitelt „Drain & Cordon (sanftes Stilllegen)“Um einen Runner aus der Rotation zu nehmen, ohne seine laufenden Aufgaben zu
killen, setze seinen Drain-Zustand. Ein cordoned/draining-Runner sendet
weiter Heartbeats und beendet seine laufende Arbeit, erhält aber nichts Neues;
active stellt ihn wieder her.
curl -X POST https://supacloud.example.com/api/runners/<id>/drain \ -H "Authorization: Bearer <admin-token>" \ -H "Content-Type: application/json" \ -d '{ "drain_state": "draining" }' # active | cordoned | drainingDas ist die sanfte Alternative zum Deaktivieren eines Runners (POST /api/runners/{id}/status {"enabled": false}), das ihn abrupt parkt und seine
Heartbeats ablehnt.
Parallelitäts-Limit
Abschnitt betitelt „Parallelitäts-Limit“capabilities.max_parallel begrenzt, wie viele Aufgaben ein Runner gleichzeitig
ausführt. Der Server zählt die laufenden Zuweisungen eines Runners und verteilt
beim Limit nichts mehr an ihn — die Arbeit wartet einfach auf einen freien Platz
oder einen anderen geeigneten Runner.
Least-loaded-Sortierung
Abschnitt betitelt „Least-loaded-Sortierung“Standardmäßig behalten geeignete Runner die Registry-Reihenfolge. Schalte
gewichtetes Least-loaded ein, um jede neue Aufgabe stattdessen an den am
wenigsten ausgelasteten Runner zu senden. Es ist ein persistierter globaler
Schalter (dispatch_least_loaded, Standard aus), umgeschaltet über die
Operator-Switches:
curl -X PUT https://supacloud.example.com/api/operator/v1/switches/dispatch_least_loaded \ -H "Authorization: Bearer <operator-token>" \ -H "Content-Type: application/json" \ -d '{ "enabled": true, "reason": "Last über die Flotte ausbalancieren" }'Das capabilities.weight eines Runners (Standard 1) skaliert seinen Anteil: ein
weight: 2-Runner nimmt etwa die doppelte Last auf, bevor er deprioritisiert wird
— nützlich, wenn Maschinen unterschiedlich groß sind.
Fairness pro Workspace (Admission auf einem geteilten Pool)
Abschnitt betitelt „Fairness pro Workspace (Admission auf einem geteilten Pool)“Least-loaded balanciert über Runner; Fairness pro Workspace balanciert über
Workspaces, die um einen geteilten Pool konkurrieren. Eingeschaltet lässt der
Dispatcher Arbeit fair pro Workspace zu, sodass ein ausgelasteter Workspace nicht
die ganze Flotte vereinnahmt und die anderen aushungert — Admission-Fairness auf
einem geteilten Pool, keine harte Quote. Es ist ein persistierter globaler Schalter
(workspace_fairness_enabled, standardmäßig aus), genau wie der
Least-loaded-Schalter über die Operator-Switches umgeschaltet:
curl -X PUT https://supacloud.example.com/api/operator/v1/switches/workspace_fairness_enabled \ -H "Authorization: Bearer <operator-token>" \ -H "Content-Type: application/json" \ -d '{ "enabled": true, "reason": "verhindern, dass ein Workspace die geteilte Flotte vereinnahmt" }'Eine optionale globale Ganzzahl workspace_fair_share_cap begrenzt, wie viel des
Pools ein einzelner Workspace gleichzeitig in Bearbeitung halten darf. Solange der
Schalter aus ist, ist das Dispatching Byte-für-Byte identisch wie heute — keine
Workspace-Buchführung läuft.
Priorität & Pinning (pro Aufgabe)
Abschnitt betitelt „Priorität & Pinning (pro Aufgabe)“Zwei Steuerungen pro Aufgabe liegen in der Aufgaben-Config:
priority(Ganzzahl, Standard 0) — innerhalb der Warteschlange eines Runners wird eine höher priorisierte Aufgabe zuerst abgeholt.pinned_runner_id— zwingt die Aufgabe auf einen bestimmten Runner. Ist dieser offline oder ausgelastet, wartet die Aufgabe auf ihn (queue-pending), statt woanders zu laufen. Setze"pin_fallback": true, um stattdessen auf das normale Ranking zurückzufallen, wenn der gepinnte Runner nicht verfügbar ist.
Überwachen: Dispatch-State
Abschnitt betitelt „Überwachen: Dispatch-State“GET /api/runners/dispatch-state liefert pro Runner seine laufende
In-flight-Zahl, das beworbene Limit, den Drain-Zustand und ob sein Heartbeat
veraltet ist — das echte Signal für „kommt die Flotte hinterher“, das jedes Raten
aus Container-IDs ersetzt.
curl https://supacloud.example.com/api/runners/dispatch-state \ -H "Authorization: Bearer <admin-token>"Jede Steuerungs-Mutation (Registrieren, Aktivieren/Deaktivieren, Drain,
Token-Rotation, Hub-Modus) schreibt eine audit_events-Zeile, sodass
Flotten-Änderungen zuordenbar sind.
Autoscaler (experimentell)
Abschnitt betitelt „Autoscaler (experimentell)“Statt eine feste Flotte zu betreiben, kann der Hub sie bedarfsgerecht wachsen und
schrumpfen lassen. Der integrierte Autoscaler liest das Fleet-Pull-Queue-Signal und
startet neue lokale Docker-Runner-Container, wenn Arbeit ansteht, und zieht sie
wieder ein, wenn der Pool untätig ist. Er ist standardmäßig aus
(SUPACLOUD_RUNNER_AUTOSCALE=off) — keine Schleife wird gestartet, das Dispatching
ist unverändert.
SUPACLOUD_RUNNER_AUTOSCALE=onSUPACLOUD_RUNNER_AUTOSCALE_MIN=1SUPACLOUD_RUNNER_AUTOSCALE_MAX=8SUPACLOUD_RUNNER_AUTOSCALE_RUNNER_IMAGE=<dein-supacloud-image>SUPACLOUD_RUNNER_AUTOSCALE_COOLDOWN_SECS=120SUPACLOUD_RUNNER_AUTOSCALE_NETWORK=supacloud-agentsJeder gestartete Runner braucht ein Token, daher muss der Autoscaler mit einem
Runner-Token konfiguriert sein, das er dem gestarteten Container übergibt — siehe die
Umgebungsvariablen-Referenz.
Das Scale-in ist ARC-förmig und drain-gated: es cordont ein Opfer (sodass der
Ranker ihm keine neue Arbeit mehr sendet), wartet, bis seine in_flight-Zahl
null erreicht, und entfernt es erst dann — laufende Arbeit wird nie gewaltsam
beendet.
Troubleshooting
Abschnitt betitelt „Troubleshooting“| Symptom | Wahrscheinliche Ursache | Was prüfen |
|---|---|---|
| Aufgabe läuft lokal trotz gesundem Runner | Hub-Modus aus, oder kein Runner bewirbt das Image der Aufgabe | GET /api/runners/config; capabilities.images des Runners |
Runner ist online, bekommt aber keine Arbeit |
Cordoned/draining, am max_parallel-Limit, oder ein fehlendes verlangtes Label |
dispatch-state (drain_state, in_flight vs. Limit); verlangte Labels der Aufgabe |
Runner wird von selbst offline |
Heartbeat über das Fenster hinaus veraltet (Standard 90 s) | Uhr/Netz des Workers; SUPACLOUD_RUNNER_STALE_SECS am Hub |
| Eine gepinnte Aufgabe startet nie | Gepinnter Runner offline/ausgelastet und pin_fallback nicht gesetzt (queue-pending ist beabsichtigt) |
Zustand des Runners; setze pin_fallback, wenn sie woanders laufen soll |
| Die Aufgaben eines Workspaces hungern die anderen auf einem geteilten Pool aus | Fairness pro Workspace aus | workspace_fairness_enabled einschalten; optional workspace_fair_share_cap setzen |
| Eine microVM-pflichtige Aufgabe wartet, während Container-Runner untätig sind | Kein Runner hält einen microvm-Grant (der Filter ist fail-closed) |
Einen Runner mit isolation: microvm und microVM-Backend onboarden |
| „Bridge health check timed out“ bei einem Remote-Lauf | Agent-Container nicht im Docker-Netz des Runners | AGENT_NETWORK existiert auf dem Worker und passt |