Communitygithub.com

bilgihankose/k8s-debug-bridge

Debugge einen laufenden Kubernetes-Dienst live auf deinem Laptop. Fünf Bash-Skripte + ein Agent-Skill – kein Agent, kein Operator, keine Installation.

Was ist k8s-debug-bridge?

Der **K8s Debug Bridge** Skill ermöglicht es, Live-Traffic von einem Kubernetes/OpenShift-Dienst auf einen lokalen Rechner umzuleiten, ohne zusätzliche CLI-Tools oder Agenten zu installieren. Er nutzt ausschließlich `kubectl`/`oc exec`, Bashs eingebautes `/dev/tcp` und `nc` im Bridge-Pod. Der Mechanismus erstellt einen temporären Bridge-Pod, ändert vorübergehend den `spec.selector` des Zieldienstes auf das Label dieses Pods und baut einen Reverse-Tunnel zwischen Pod und lokalem Port auf. Der Skill ist sprach- und frameworkunabhängig und unterstützt alle Kubernetes-Distributionen (vanilla K8s, OpenShift, EKS/GKE/AKS). Er arbeitet mit `oc` falls verfügbar, sonst mit `kubectl`. Der Skill erfordert ausdrückliche Benutzerbestätigungen vor jedem kritischen Schritt (Pod-Erstellung, Service-Umleitung) und speichert den ursprünglichen Selektor sowohl lokal als auch als Annotation im Service, um eine vollständige Rückabwicklung zu gewährleisten. Besondere Vorsicht gilt der Sicherheit: Der Skill warnt vor dem Risiko, den Service-Selektor nicht zurückzusetzen (dauerhafter Ausfall) und dem Missbrauch von `exec`-Berechtigungen über RBAC. Der Bridge-Pod wird nach Beendigung automatisch bereinigt, entweder durch `trap` (Ctrl+C oder `kill -TERM`) oder manuell über das Skript `cleanup.sh`.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add bilgihankose/k8s-debug-bridge

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

K8s Debug Bridge

Leitet Live-Traffic von einem Kubernetes/OpenShift-Dienst zu einem lokalen Rechner zum Debuggen um – unter Verwendung von ausschließlich standardmäßigem kubectl/oc exec, Bashs eingebautem /dev/tcp und dem nc im Bridge-Pod – ohne zusätzliche CLI oder Agenteninstallation. Mechanismus: Ein temporärer „Bridge-Pod“ wird gestartet, der spec.selector des Zieldienstes wird vorübergehend auf das Label dieses Pods umgestellt, und ein Reverse-Tunnel verbindet den Pod und den lokalen Port. Funktioniert auf jeder Kubernetes-Distribution (vanilla K8s, OpenShift, EKS/GKE/AKS) – verwendet oc falls verfügbar, sonst kubectl (siehe scripts/lib-kube-cli.sh). Die README.md erläutert die Beweggründe und die Abwägungen gegenüber Tools wie Telepresence und mirrord.

Dieser Skill ist nicht an eine einzelne Sprache/ein einzelnes Framework gebunden: Die Bridge transportiert nur Traffic. VS Code + Air + Delve (Go) ist nur ein Beispiel für eine Integration – wenn du in einer anderen Sprache arbeitest, schließe deinen eigenen Watcher/Debugger an (Node: nodemon+inspector, Python: watchdog+debugpy usw.) über denselben Tunnel an. Wenn die lokale Seite des Benutzers noch nicht eingerichtet ist – kein Reloader, kein Debugger verbunden, oder sie möchten sie an ihr eigenes Projekt anpassen – lese zu diesem Zeitpunkt docs/local-debug-setup.md und folge ihr. Gib deren Inhalt nicht aus dem Gedächtnis wieder und lese sie nicht, wenn die lokale App bereits läuft und zuhört.

Dieser Skill erstellt eine echte Ressource in deinem Cluster und ändert eine echte Ressource: Er erstellt einen Pod und ändert vorübergehend den spec.selector eines Dienstes. Dies sind keine Simulationen – dies ist echter Cluster-Zustand. Es muss bei jedem Schritt einen Rollback-Plan geben – ändere niemals den Selektor und vergiss ihn.

Voraussetzungen – vor dem Fragen des Benutzers prüfen

Frage den Benutzer nicht nach dem Namespace/Dienstnamen und übergib ihn blind an bridge-up.sh – ein falsch geschriebener Name führt mitten im Skript zu einem Fehler. Führe zuerst scripts/check-env.sh [namespace] aus (schreibgeschützt, ändert nichts):

  • Ohne Argumente: Zeigt den Login-Status und zugängliche Namespaces an. Wenn nicht eingeloggt, stoppe hier und sage dem Benutzer, er solle oc login/kubectl config use-context ausführen.
  • Mit einem Namespace: Überprüft, ob der Namespace existiert, und listet die darin enthaltenen Dienste auf (Name + Port + targetPort, einschließlich bereits gebrückter).

Zeige diese Ausgabe dem Benutzer und lass ihn den Zieldienst aus der Liste auswählen – lass ihn nicht raten. Dann:

  • Das Bridge-Pod-Image – immer fragen, niemals annehmen. Wähle keinen Standardwert und führe ihn aus: Frage den Benutzer direkt „Welches Image soll der Bridge-Pod verwenden?“ und warte auf eine Antwort. Das Image muss von diesem spezifischen Cluster genehmigt und erreichbar sein, und nur der Benutzer weiß, welches das ist – viele Cluster ziehen nur aus einer genehmigten internen Registry, sodass ein geratenes Image beim Pull fehlschlagen kann, während der Dienst bereits umgeleitet wurde. nicolaka/netshoot ist ein Beispiel, das angeboten werden kann, aber kein Fallback, der stillschweigend verwendet wird. Was auch immer sie wählen, es muss nc ausliefern: Die Pod-Seite verwendet nc anstelle von socat, weil gehärtete Images oft socat entfernen, während Nmaps nc erhalten bleibt. tunnel.sh prüft auf nc, bevor der Tunnel geöffnet wird, und stoppt mit einer klaren Fehlermeldung, wenn das Image es nicht enthält.
  • Pod-Manifest: Der Bridge-Pod wird aus assets/bridge-pod.yaml gerendert. Wenn der Cluster imagePullSecrets, einen securityContext, nodeSelector/tolerations oder andere Ressourcenlimits erfordert, bearbeite diese Datei – arbeite nicht in den Skripten darum herum. Behalte das debug: "__BRIDGE_NAME__"-Label und den Containernamen debug-bridge bei; die anderen Skripte adressieren den Pod darüber.
  • Der Port: Verwende den numerischen targetPort des Dienstes aus der Ausgabe von check-env.sh, NICHT einen beliebigen freien Port. Wenn der Dienst einen benannten targetPort verwendet (z. B. http), löse ihn in seinen numerischen Container-Port auf. kube-proxy leitet Traffic nach der Umleitung des Selektors an den targetPort des Pods weiter – wenn du eine andere Nummer wählst, erreicht der Traffic den Bridge-Pod nie.
  • Ausgehende Abhängigkeiten: Diese Bridge behandelt nur eingehenden Traffic (Cluster → Lokal). Wenn lokaler Code andere Cluster-Dienste aufrufen muss (.svc.cluster.local), verwende externe Routes/Ingress oder lokale Port-Forwards.
  • Geheimnisse und Umgebung: Führe niemals oc exec ... env, printenv, set oder einen ähnlichen Befehl gegen einen Anwendungs-Pod aus. Werte können mehrzeilige Anmeldeinformationen sein und in die Terminal-/Tool-Ausgabe gelangen, selbst wenn ein Befehl nur Namen auszuwählen scheint. Kopiere niemals Pod-Umgebungsvariablen in einen lokalen Befehl, die Shell-Historie oder eine .env. Erfordere einen vorhandenen lokalen Secret-Management-Workflow oder lass den Benutzer die benötigte lokale Umgebungsdatei außerhalb der Reihe bereitstellen. Überprüfe nur, ob die lokale Anwendung startet; gib ihre Umgebung nicht aus.

Die lokale Anwendung muss bereits laufen, bevor du den Dienst berührst. Dies ist eine Vorbedingung, kein späterer Schritt: Der Tunnel liefert Traffic an 127.0.0.1:<port>. Wenn dort nichts lauscht, wenn der Selektor umschaltet, schlägt jede abgefangene Anfrage mit connection-refused/502 fehl, während die echten Pods bereits außer Betrieb sind. Lass den Benutzer seine App starten (mit einer sicher bereitgestellten lokalen Umgebungsdatei – niemals einer, die aus einem Cluster-Pod ausgelesen wurde) und bestätige den Listener unmittelbar vor Schritt 2:

lsof -nP -iTCP:<port> -sTCP:LISTEN

Ablauf

  1. Bridge einrichten: Sage dem Benutzer klar, bevor du etwas ausführst: „Ich werde einen echten Pod namens <bridge-pod> im Namespace <namespace> erstellen (Image: <image>) – er verbraucht Cluster-Ressourcen und wird gelöscht, wenn du fertig bist.“ Nach Zustimmung führe scripts/bridge-up.sh <namespace> <service> <bridge-pod> <image> [port] aus – dies erstellt den Bridge-Pod und speichert den ursprünglichen Selektor sowohl im lokalen Zustand als auch als k8s-debug-bridge/owner-Annotation am Dienst (kein python3/jq erforderlich, reines Bash). Überspringe diesen Schritt nicht – leite niemals um, ohne den ursprünglichen Selektor gespeichert zu haben, sonst gibt es keinen Weg zurück. Wenn der Dienst bereits von jemand anderem gebrückt wird, schlägt dieses Skript fehl und stoppt (Annotation-Check) – zeige dem Benutzer in diesem Fall den Besitzer aus der Fehlermeldung, versuche es nicht selbst erneut.

  2. Dienst umleiten: Bevor der Selektor des Zieldienstes auf das Label des Bridge-Pods umgestellt wird, sage dem Benutzer klar und hole eine explizite Zustimmung ein: „Ab diesem Moment geht der GESAMTE Traffic zu <service> zu deinem Bridge-Pod – die echten Pods erhalten keinen Traffic mehr.“ Nach Zustimmung führe scripts/redirect-service.sh <namespace> <service> --yes aus – --yes überspringt die eigene interaktive read-Eingabeaufforderung des Skripts (da du bereits im Chat zugestimmt hast); ohne --yes wartet das Skript auf stdin und kann hängen bleiben. Das Skript ersetzt die vollständige Selektor-Map nur durch debug=<bridge-pod>; es darf dieses Label nicht mit dem ursprünglichen Selektor zusammenführen, da der Bridge-Pod die ursprünglichen Labels der Anwendung nicht trägt.

  3. Tunnel starten: scripts/tunnel.sh <namespace> <service> <bridge-pod> <port> – dieses Skript blockiert, gehört daher in ein eigenes Terminal oder einen Hintergrundprozess. Es reinigt sich selbst: trap fängt EXIT/INT/TERM ab, sodass Strg+C oder jede andere Beendigung automatisch cleanup.sh aufruft. Wenn du es selbst im Hintergrund gestartet hast, gibt es kein Strg+C zum Drücken – stoppe es mit kill -TERM <pid>, was der trap ebenfalls behandelt; notiere die PID beim Start und teile sie dem Benutzer mit. Die manuelle Ausführung von cleanup.sh ist nur erforderlich, wenn der Prozess unfangbar getötet wird (kill -9). Es überträgt jeweils eine Verbindung und erstellt automatisch einen neuen Pod-seitigen Listener, nachdem jede Verbindung geschlossen wurde. Lasse daher denselben Tunnel zwischen aufeinanderfolgenden Debug-Anfragen laufen. Wenn der Tunnel wiederholt WARNING: could not carry a connection protokolliert, lauscht nichts auf 127.0.0.1:<port> – die lokale App ist ausgefallen, wird noch gebaut, oder ein Hot Reload hat den Port freigegeben. Behebe das, anstatt den Tunnel neu zu starten.

  4. Lokales Debuggen: Der Port, den du brückst, ist der Port, auf dem die Anwendung bedient (der targetPort des Dienstes), niemals der Port, auf dem ihr Debugger lauscht. Wenn der Benutzer sagt „Mein Debugger ist auf 2345, brücke das“, verwechselt er die beiden: Korrigiere ihn, frage, auf welchem Port die Anwendung selbst bedient, und brücke diesen. Traffic, der an einen Debugger-Port gesendet wird, kommt als 502 zurück, die wie ein defekter Tunnel aussehen. Die lokale App läuft bereits und ist verifiziert (siehe Vorbedingung oben); sie erhält den getunnelten Traffic. Der Debugger ihrer Sprache (z. B. Delve, ein Node-Inspector) hängt sich separat an diese laufende Anwendung an, normalerweise auf einem anderen Port – z. B. in Go: Air + Delve auf Port 2345, während die App selbst auf dem getunnelten <port> lauscht. Ein Hot Reload kann den Listener kurzzeitig entfernen; während er fehlt, gibt die Bridge Verbindungsfehler/502 zurück. Wenn sich die lokale App nicht rechtzeitig erholt, stoppe den Tunnel und bereinige den Dienst, anstatt den gesamten Traffic auf eine fehlerhafte Bridge zu lenken. Die Bridge transportiert den HTTP-Pfad unverändert: Konfiguriere das Basispräfix der lokalen App so, dass es dem an den Dienst gelieferten Pfad entspricht; sie reproduziert keine Ingress-Umschreibung. Traffic kann von jedem In-Cluster-Aufrufer des Dienstes kommen (z. B. einem Dashboard-Nginx-Proxy); eine öffentliche Route/Ingress ist nicht erforderlich. Wenn die Ausführung über das Timeout des Aufrufers hinaus pausiert wurde, setze sie fort und löse eine neue Anfrage aus. Nach einem Hot Reload, der Delve neu startet, muss sich die IDE möglicherweise erneut verbinden. Wenn Delve mit --accept-multiclient gestartet wurde, kann der Agent zusätzlich zu VS Code einen terminalbasierten Delve-Client an Port 2345 anhängen, um die aktuelle Quellzeile, den Stack und Variablen zu inspizieren. Melde Beobachtungen dem Benutzer; hole explizite Zustimmung ein, bevor du die Ausführung fortsetzt oder den Debugger-Zustand anderweitig änderst.

  5. Wenn fertig: Strg+C im Tunnel-Terminal oder kill -TERM <pid>, wenn du es im Hintergrund gestartet hast – der Dienst-Selektor und der Bridge-Pod werden automatisch zurückgesetzt, einschließlich der Wiederherstellung der vollständigen ursprünglichen Selektor-Map. Wenn der trap nicht ausgelöst wurde (z. B. kill -9), muss scripts/cleanup.sh <namespace> <service> manuell ausgeführt werden; erinnere den Benutzer daran, bevor er die Sitzung verlässt.

Sicherheitshinweis

Diese Methode installiert keine dauerhafte Komponente im Cluster (kein Mutating Webhook, Sidecar-Injector oder clusterweites RBAC) – nur einen temporären Pod, der klar durch seinen Namen/Label gekennzeichnet ist (debug=<bridge-pod-name>), und Standard-exec-Berechtigungen. Dennoch gibt es zwei reale Risiken, warne den Benutzer davor:

  1. Den Dienst-Selektor zurückzusetzen vergessen – ein dauerhafter Ausfall in Produktion/Staging.
  2. exec-Berechtigungen, die über RBAC missbraucht werden können – dieser Skill sollte nur in deinem eigenen Namespace, auf deinem eigenen Bridge-Pod und niemals mit Cluster-Admin ausgeführt werden.

Ausführliche Schritte und Fehlerbehebung findest du in der README.md.

Überprüfe vor Beendigung der Sitzung, ob noch eine ungereinigte Bridge vorhanden ist. Der Zustand befindet sich neben dem scripts/-Verzeichnis, im eigenen Ordner dieses Skills – nicht im Projektverzeichnis des Benutzers. Löse ihn relativ zu den Skripten auf, die du ausführst, z. B.:

find "$(dirname <path-to>/scripts)/.state" -name '*.env'

Ein nacktes find .state aus dem Projektverzeichnis des Benutzers findet stillschweigend nichts und meldet einen sauberen Zustand, selbst wenn noch eine Bridge aktiv ist. Wenn dort eine .env-Datei existiert, teile dem Benutzer mit, welchen Namespace/Dienst sie benennt, und schlage scripts/cleanup.sh <namespace> <service> vor. Dies ist eine Erinnerung, kein deterministisches Gate – achte darauf, sie nicht zu vergessen.

Verwandte Skills