Zum Inhalt springen
Farbschema wählenSprache wählen

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.

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.

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.

Terminal window
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 | draining

Das ist die sanfte Alternative zum Deaktivieren eines Runners (POST /api/runners/{id}/status {"enabled": false}), das ihn abrupt parkt und seine Heartbeats ablehnt.

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.

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:

Terminal window
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:

Terminal window
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.

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.

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.

Terminal window
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.

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=on
SUPACLOUD_RUNNER_AUTOSCALE_MIN=1
SUPACLOUD_RUNNER_AUTOSCALE_MAX=8
SUPACLOUD_RUNNER_AUTOSCALE_RUNNER_IMAGE=<dein-supacloud-image>
SUPACLOUD_RUNNER_AUTOSCALE_COOLDOWN_SECS=120
SUPACLOUD_RUNNER_AUTOSCALE_NETWORK=supacloud-agents

Jeder 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.

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