Zum Inhalt

Architektur

Die Architektur folgt einem Drei-Schichten-Modell: eine Verwaltungsschicht (Python-Anwendung mit Web-UI), eine Container-Orchestrierungsschicht (Docker-API, gemeinsames Bridge-Netzwerk) und eine Inference-Schicht (vLLM-Container pro Modell). Sämtliche dauerhaften Komponenten — Reverse-Proxy, API-Proxy, Datenbank, Monitoring — laufen als Docker-Container im selben Bridge-Netzwerk und werden von der Verwaltungsschicht über die Docker-API gesteuert. Die Verwaltungsschicht selbst läuft auf dem Host außerhalb des Container-Netzwerks; Anfragen zur Inference fließen ausschließlich über den Reverse-Proxy.

Auf einen Blick

  • Single-File-Verwaltungsanwendung in Python mit Gradio-UI; Bindung ausschließlich auf 127.0.0.1:7860. Die Oberfläche wird in zwei Sprachinstanzen bereitgestellt (Deutsch unter /de, Englisch unter /en; Umschalter in der Kopfzeile, Weiterleitung von / nach Browser-Sprache).
  • Docker-Bridge-Netzwerk llm-network als gemeinsame Kommunikationsebene aller Container, mit Docker-internem DNS.
  • Caddy als zentraler HTTPS-Reverse-Proxy für externe Zugriffe; alle anderen Container ohne Host-Port-Mapping.
  • LiteLLM-Proxy als OpenAI-kompatibler Vermittler für Chat, Vision und Embedding; Direktrouten an vLLM-Container für Speech-to-Text, Text-to-Speech und Bildgenerierung.
  • PostgreSQL für Virtual Keys, ohne Port-Exposition und ausschließlich im Docker-Netzwerk erreichbar.
  • Optionaler Monitoring-Stack aus Prometheus, Grafana und NVIDIA DCGM Exporter.
  • Eine zentrale JSON-Datei hält den gesamten Zustand; alle weiteren Konfigurationsdateien werden aus ihr generiert.

Architekturbeschreibung

Die Verwaltungsanwendung läuft als systemd-Dienst auf dem Host und kommuniziert über den Docker-Unix-Socket mit dem Docker-Daemon. Sie ist die einzige Komponente außerhalb des Container-Netzwerks und hält den globalen Zustand: erkannte GPUs, MIG-Konfiguration, registrierte Modelle, API-Schlüssel, Image-Versionen (global und je Modell) und HTTPS-Einstellungen. Aus diesem Zustand werden bei Änderungen die Konfigurationsdateien für LiteLLM, Caddy, Prometheus und Grafana neu erzeugt; betroffene Container werden anschließend neu gestartet oder neu geladen.

Komponenten und Datenfluss

flowchart TB
    Client[Client / Browser / API]

    subgraph Host[Host-System]
        Manager[LLM-Manager<br/>Gradio Web-UI<br/>127.0.0.1:7860]
        NVSMI[nvidia-smi]
        Config[(config.json)]
        HFCache[(Hugging Face Cache)]

        subgraph DockerNet[Docker-Netzwerk llm-network]
            Caddy[Caddy<br/>HTTPS Reverse Proxy<br/>:443]
            LiteLLM[LiteLLM Proxy<br/>:4000]
            Postgres[(PostgreSQL<br/>Virtual Keys)]

            subgraph vLLMs[vLLM-Container pro Modell]
                vLLM1[Chat / Vision / Embedding]
                vLLM2[Speech-to-Text]
                vLLM3[Text-to-Speech / Bildgenerierung]
            end

            subgraph Monitoring[Monitoring optional]
                Prom[Prometheus]
                Grafana[Grafana]
                DCGM[DCGM Exporter]
            end
        end
    end

    Client -->|HTTPS| Caddy

    Manager -->|Docker API| Caddy
    Manager -->|Docker API| LiteLLM
    Manager -->|Docker API| vLLMs
    Manager -->|nvidia-smi| NVSMI
    Manager <--> Config

    Caddy -->|"/v1/*"| LiteLLM
    Caddy -->|"/models/{name}/*"| vLLM2
    Caddy -->|"/models/{name}/*"| vLLM3
    Caddy -->|"/open/{name}/*"| LiteLLM
    Caddy -->|"/grafana/*"| Grafana

    LiteLLM --> vLLM1
    LiteLLM --> Postgres

    vLLM1 -.-> HFCache
    vLLM2 -.-> HFCache
    vLLM3 -.-> HFCache

    Prom --> vLLM1
    Prom --> vLLM2
    Prom --> vLLM3
    Prom --> LiteLLM
    Prom --> DCGM
    Grafana --> Prom

Erläuterung des Diagramms

Eingehende Anfragen treffen ausschließlich auf Caddy. Caddy unterscheidet drei Routing-Pfade: Anfragen unter /v1/* werden an LiteLLM weitergereicht; LiteLLM authentifiziert über den Master-Key oder einen Virtual Key (gegen PostgreSQL) und leitet die Anfrage an den passenden vLLM-Container weiter, bei mehreren Replicas eines Modells nach least-busy-Strategie. Anfragen unter /models/<n>/v1/* werden direkt an den genannten vLLM-Container weitergereicht; Caddy entfernt das Präfix und prüft den Authorization-Header per Expression-Matcher gegen den Master-Key und alle eingetragenen Direkt-Routen-Keys. Anfragen unter /open/<n>/v1/* (sofern aktiviert) lassen jeden nicht-leeren Bearer-Token passieren, ersetzen ihn durch den Master-Key und reichen die Anfrage an LiteLLM weiter.

Die Verwaltungsanwendung selbst ist nicht im Datenfluss der Inference-Anfragen beteiligt. Sie liest GPU-Informationen über nvidia-smi, steuert den Container-Lebenszyklus über die Docker-API, kommuniziert mit der LiteLLM-Management-API zur Schlüsselerzeugung und schreibt sämtliche Konfigurationsdateien aus dem zentralen JSON-Zustand. Der Hugging-Face-Cache ist ein gemeinsames Volume, das in alle vLLM-Container eingebunden wird, sodass Modelldateien nur einmal vorgehalten werden.

Container-Layout

Alle Container laufen im Bridge-Netzwerk llm-network und kommunizieren über Docker-internes DNS. Nur Caddy (Port 443 und 80) und das Web-UI (Port 7860, ausschließlich 127.0.0.1) sind auf dem Host erreichbar; PostgreSQL, LiteLLM, alle vLLM-Container und der Monitoring-Stack sind ohne Host-Port-Mapping konfiguriert. Container werden mit Labels versehen (managed-by, model-name, model-type), sodass sich von der Verwaltungsanwendung gepflegte Container von anderen unterscheiden lassen.

Die Image-Auswahl pro Modell folgt einer festen Priorität: ein optionaler Modell-Override schlägt zuerst zu; andernfalls bestimmt der Modell-Typ die Image-Familie — Rezept-Image (etwa für Speech-to-Text mit Whisper- oder Audio-Abhängigkeiten), vLLM-Omni-Image (Text-to-Speech, Bildgenerierung) oder Standard-vLLM-Image (Chat, Vision, Embedding) — und eine optionale Per-Modell-Version den Versionsstand; fehlt sie, greift die global konfigurierte Version. So können Modelle unterschiedlicher vLLM-Linien dauerhaft nebeneinander betrieben werden. Image-Auflösung und Startkommando entstehen in gemeinsamen, seiteneffektfreien Hilfsfunktionen, die auch die Konsistenzprüfung verwendet — Soll- und Ist-Zustand stimmen dadurch strukturell überein. Rezept-Images werden auf Wunsch direkt aus der Oberfläche heraus gebaut und je Basisversion getrennt vorgehalten; die zugehörigen Pakete sind als Rezepte hinterlegt.

Schichten der Verwaltungsanwendung

Die Python-Anwendung ist intern in mehrere Schichten gegliedert:

  • Hardware-Schicht — GPU-Discovery, NVLink- und MIG-Erkennung, MIG-Verwaltung und MIG-Persistenz.
  • Datenmodell-Schicht — Modell- und Anwendungs-Konfiguration als typisierte Datenklassen mit Migrationspfaden für ältere Konfigurationen.
  • Orchestrierungs-Schicht — Container-Lebenszyklus (Erstellen, Starten, Stoppen, Logs), Image-Auswahl, Image-Build-Logik für Rezept-Images sowie der Konsistenzabgleich zwischen Konfiguration und laufenden Containern.
  • Konfigurations-Schicht — Persistenz und Generierung der LiteLLM-, Caddy- und Prometheus-Konfigurationen aus dem zentralen JSON-Zustand.
  • Monitoring-Schicht — Energie-Sampling über nvidia-smi, Sitzungs-Tracking und CSV-Export.
  • UI-Schicht — Gradio-Oberfläche mit tabbasierter Strukturierung, Echtzeit-Updates und Event-Handlern; zweisprachig (Deutsch/Englisch) über je eine App-Instanz pro Sprache, deren Texte aus einem eingebetteten Wörterbuch stammen.

Nebenläufigkeit und Robustheit

Sicherheitsrelevante Operationen sind so ausgelegt, dass sie das Gesamtsystem nicht in einen inkonsistenten Zustand bringen können. PostgreSQL-Container werden zwar gestoppt, aber niemals entfernt, und das zugehörige Volume wird niemals gelöscht. LiteLLM-Neustarts halten eine feste Wartezeit zwischen Stop und Start ein und berühren PostgreSQL und Caddy nicht. Beim ersten Start von PostgreSQL werden Datenbank-Migrationen durch einen Health-Check mit großzügiger Anlaufzeit abgesichert. Aufrufe externer Werkzeuge (nvidia-smi, Docker-CLI) laufen mit Zeitlimits und definierter Fehlerbehandlung, sodass ein nicht reagierender GPU-Treiber die Verwaltungsanwendung nicht blockiert. Aktualisierungen von Image-Versionen wirken selektiv: Nur Container, deren Ziel-Image sich ändert, werden neu gestartet.

Die Wiederherstellung nach einem Reboot läuft als fünfstufiger Vorgang: Wiederherstellung der MIG-Partitionen, Start von PostgreSQL, Start aller Modelle mit Status „running", Start von LiteLLM und schließlich Aktualisierung der Caddy-Konfiguration. Wenn der Monitoring-Stack aktiv ist, folgt er als sechster Schritt.

Konfiguration und Deployment

Die Anwendung wird als systemd-Dienst betrieben; ihre Konfiguration liegt in einem festen Verzeichnis auf dem Host, das über eine Umgebungsvariable überschreibbar ist. Aus der zentralen config.json werden bei jeder Änderung litellm-config.yaml, Caddyfile, prometheus.yml und Grafana-Provisioning-Dateien neu erzeugt. Sensible Daten — die config.json mit Schlüsseln und Datenbank-Passwort — werden mit eingeschränkten Dateirechten abgelegt. Die DATABASE_URL wird ausschließlich als Container-Umgebungsvariable übergeben und nicht in Konfigurationsdateien geschrieben.

Technologie-Übersicht

Schicht Komponente
Web-UI Gradio
Programmiersprache Python
Container-Orchestrierung Docker, Docker SDK für Python, NVIDIA Container Toolkit
Inference-Backends vLLM, vLLM-Omni
API-Proxy LiteLLM
HTTPS-Reverse-Proxy Caddy
Datenbank PostgreSQL
Monitoring Prometheus, Grafana, NVIDIA DCGM Exporter
Modell-Bezug Hugging Face Hub (Hugging-Face-CLI)
Konfigurationsformate JSON, YAML
Datenverarbeitung pandas
Deployment systemd, Docker Bridge Network