vLLM nicht selbst betreiben, sondern betreiben lassen?
Auf dem Managed GPU Server laufen Modell, vLLM und Open WebUI auf einer dedizierten GPU in Deutschland, mit Monitoring und Updates, ab 699 € netto im Monat zzgl. einmaliger Einrichtung. Die laufende Prüfung der Anwendung darüber (Traces, Evaluationen, Kosten) übernimmt Managed LLMOps.
Ein vllm serve läuft in Minuten, ein produktiver Betrieb braucht mehr: Speicherrechnung, begrenzte Parameter, Absicherung, Metriken, ein Update-Verfahren und einen Lasttest. Dieser Leitfaden ist eine Betriebsanleitung für vLLM mit Docker, geprüft gegen die vLLM-Dokumentation und den Quellcode. Stand 28. Oktober 2026, aktuelle Version vLLM 0.32.0. Was vLLM ist, erklärt Was ist vLLM?, den Vergleich mit Ollama zeigt vLLM vs. Ollama.
Inhaltsverzeichnis
- Speicher planen: Gewichte und KV-Cache
- vLLM mit Docker Compose starten
- Die Serverparameter, die zählen
- Kubernetes: Hinweise
- Healthchecks und Readiness
- Metriken, LiteLLM und Langfuse
- Absicherung
- Updates und Versions-Pinning
- Typische Fehler
- Lasttest ohne erfundene Zahlen
- Woran sich eine vLLM-Beratung messen lässt
- Stand und Methodik
- Unser Vorgehen bei WZ-IT
- Weiterführende Guides
Speicher planen: Gewichte und KV-Cache
Produktiv heißt zuerst: Kontext und Parallelität passen zum Speicher der GPU. Der GPU-Speicher teilt sich in Gewichte, KV-Cache und Reserve:
- Gewichte = Dateigröße des Checkpoints (Parameter × Byte je Parameter).
- KV-Cache je Token = 2 × Layer × KV-Heads × Head-Dimension × Byte (klassische Attention, Werte aus der
config.json). Bei Multi-Head Latent Attention speichert vLLM je Layer nurkv_lora_rank + qk_rope_head_dimWerte (Quellcode). - Verfügbar für den Cache = GPUs × GPU-Speicher ×
--gpu-memory-utilization(Default 0,92, CLI-Referenz) - Gewichte - Reserve. Die Summe über alle GPUs gilt, solange die Tensor-Parallelität die KV-Heads nicht übersteigt. Bei MLA-Modellen mit einem latenten KV-Head liegt der Cache je Token auf jeder GPU der Tensor-Parallelität, dort gilt das Budget je GPU (Abhilfe:--decode-context-parallel-size, vLLM-Doku). - Sitzungen = Verfügbar ÷ (KV-Cache je Token × Kontextlänge).
Beispiel Ministral 3 14B in FP8 (Model Card): 15,73 GB Gewichte (15.726.706.472 Byte), 40 Layer, 8 KV-Heads, Head-Dimension 128, also 160 KiB je Token in BF16.
| GPU | Verfügbar für Cache | Token im Cache | Sitzungen mit 32.768 Token |
|---|---|---|---|
| 96 GB | 96 × 0,92 - 15,73 - 4 = 68,59 GB | rund 418.700 | 12,8 |
| 24 GB | 24 × 0,92 - 15,73 - 4 = 2,35 GB | rund 14.400 | 0,4 |
Annahmen: 4 GB Reserve je GPU für Aktivierungen und CUDA-Graphen (Planungswert, kein Messwert), KV-Cache in BF16, 1 GB = 10^9 Byte. Die Tabelle rechnet mit dem Default 0,92, die Compose-Datei unten setzt 0,90 und verkleinert das Budget um 1,9 GB (96 GB) beziehungsweise 0,5 GB (24 GB). Auf der 24-GB-Karte reicht der Cache rechnerisch nicht für einen einzelnen Kontext von 32.768 Token, dort braucht es einen kleineren --max-model-len (oder auto, das den größten passenden Wert wählt). Beim Start meldet vLLM die tatsächlichen Werte im Log (Available KV cache memory, GPU KV cache size: … tokens, Maximum concurrency for … tokens per request). Die Herleitung steht in GPU und VRAM für LLMs richtig dimensionieren, Quantisierung behandelt LLM-Quantisierung.
vLLM mit Docker Compose starten
Das Modell wird einmalig vorab geladen (HF_HOME=/srv/models/huggingface hf download mistralai/Ministral-3-14B-Instruct-2512), die vLLM-Fehlerbehebung empfiehlt das. Danach genügt diese compose.yaml (ausgelegt auf die 96-GB-Zeile der Tabelle, auf 24 GB muss --max-model-len kleiner sein):
services:
vllm:
image: vllm/vllm-openai:v0.32.0
restart: unless-stopped
shm_size: "16gb"
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
environment:
VLLM_API_KEY: ${VLLM_API_KEY}
VLLM_NO_USAGE_STATS: "1"
HF_HUB_DISABLE_TELEMETRY: "1"
HF_HUB_OFFLINE: "1"
volumes:
- /srv/models/huggingface:/root/.cache/huggingface
- vllm-cache:/root/.cache/vllm
ports:
- "127.0.0.1:8000:8000"
command:
- --model=mistralai/Ministral-3-14B-Instruct-2512
- --served-model-name=assistent
- --tokenizer-mode=mistral
- --config-format=mistral
- --load-format=mistral
- --max-model-len=32768
- --gpu-memory-utilization=0.90
- --max-num-seqs=16
- --enable-auto-tool-choice
- --tool-call-parser=mistral
volumes:
vllm-cache:
Was vom Tutorial-Standard abweicht:
- Feste Image-Version statt
latest. Das Image startet mitvllm serve, Parameter folgen nach dem Image-Namen. vLLM braucht--ipc=hostoder--shm-size(Docker-Doku). - Compile-Cache auf einem Volume (
/root/.cache/vllm). Sonst kompiliert jeder neue Container die Modell-Artefakte erneut. - GPU-Reservierung nach der Compose-Dokumentation, mit installiertem NVIDIA Container Toolkit.
- Port nur an Loopback. Veröffentlichte Docker-Ports sind sonst auch von außen erreichbar (Docker-Doku).
- Schlüssel in
.env(Dateirechte 600), nicht in der Compose-Datei. - Tokenizer-Modus und Tool-Calling-Flags stammen aus der Model Card. Andere Modelle brauchen andere Parser.
- Optional läuft der Container ohne Root:
--user 2000:0mit Mounts unter/home/vllm(Docker-Doku).
Die Serverparameter, die zählen
Quellen: CLI-Referenz, Optimierungsanleitung und Parallelität.
| Parameter | Wirkung | Regel für den Betrieb |
|---|---|---|
--max-model-len |
Kontext aus Prompt und Antwort. Ohne Angabe gilt der Wert der Modellkonfiguration, bei aktuellen Mistral-Modellen 256k. | Auf den realen Bedarf setzen, der Startlog rechnet die Parallelität mit diesem Wert. |
--gpu-memory-utilization |
Anteil des GPU-Speichers je Instanz, Default 0,92. | Das Compose-Beispiel setzt 0,90 als vorsichtigen Startwert (Einschätzung, kein Wert der Doku). Zwei Instanzen auf einer GPU: Summe höchstens 1. |
--tensor-parallel-size |
GPUs je Modell. | So klein wie möglich. Die Zahl der Attention-Heads muss durch den Wert teilbar sein (Quellcode), der Wert muss außerdem die Zahl der KV-Heads teilen oder ein Vielfaches davon sein (Quellcode). Eine Zweierpotenz ist nicht verlangt. Ohne NVLink empfiehlt die Doku Pipeline-Parallelität, siehe Multi-GPU-Inferenz. |
--max-num-seqs |
Höchstzahl gleichzeitiger Sequenzen. | An den Cache anpassen, bei häufigen Preemptions senken. |
--max-num-batched-tokens |
Token-Budget je Schritt. | 2048 verbessert die Zeit zwischen Tokens, über 8192 den Durchsatz. Per Lasttest wählen. |
--enable-prefix-caching |
Wiederverwendung bei gleichem Prompt-Anfang. Standardmäßig aktiv, sofern das Modell es unterstützt, abschaltbar mit --disable-prefix-caching. |
Hilft bei langem System-Prompt oder wiederholten Dokumenten, nicht bei langen Antworten (Doku). Treffer über Metriken prüfen. |
--kv-cache-dtype fp8 |
Halbiert den Cache je Token. | Qualität mit eigenen Fragen prüfen (Doku). |
--enable-auto-tool-choice mit --tool-call-parser |
Tool Calling für Agenten. | Parser passend zum Modell (Doku). |
--served-model-name |
API-Name, auch Label model_name der Metriken. |
Stabilen Namen vergeben, damit ein Modellwechsel Clients nicht bricht. |
--generation-config |
Quelle der Sampling-Defaults, Standard auto liest die generation_config.json des Modells. |
Bei Qualitätsfragen mit vllm gegenprüfen. |
--api-key |
Bearer-Schlüssel für die API. | Nur ein Baustein, siehe Absicherung. |
Parameter lassen sich auch in einer YAML-Datei führen (vllm serve --config), Werte auf der Kommandozeile haben Vorrang (Doku).
Kubernetes: Hinweise
Kubernetes lohnt bei mehreren GPU-Knoten, Replikas oder einem bestehenden Cluster mit Betriebsprozess, für wenige GPUs ist Compose die kleinere Betriebsfläche. Die vLLM-Anleitung für Kubernetes und die Kubernetes-Dokumentation zu GPUs nennen die Eckpunkte:
- GPU unter
limits:nvidia.com/gpugehört inlimits. Requests dürfen entfallen (Kubernetes übernimmt dann das Limit) oder müssen gleich groß sein, Requests ohne Limits sind nicht zulässig. - Gemeinsamer Speicher: ein
emptyDirmitmedium: Memoryunter/dev/shm. - Modell-Cache auf einem PersistentVolumeClaim, ein Hugging-Face-Token als Secret nur für geschützte Modelle.
- Startup-Probe mit ausreichendem
failureThreshold. Ist er zu niedrig, beendet Kubernetes den Container während des Ladens (Log:KeyboardInterrupt: terminated). Den Wert liefert eine Messung der Startzeit ohne Probe. - Feste Image-Version. Die Beispiele der Doku nutzen
latest.
Mehrere Replikas mit Routing und Autoscaling deckt der vom vLLM-Projekt gepflegte production-stack mit Helm-Chart ab. Allgemeine Cluster-Anforderungen behandelt die Kubernetes-Produktionscheckliste.
Healthchecks und Readiness
/health meldet den Zustand der Engine, ohne API-Key. Die Doku nutzt den Endpunkt für Liveness und Readiness. Drei Ergänzungen gehören in den Betrieb:
- Startup-Probe für die Ladezeit großer Modelle (Kubernetes-Probes).
- Synthetische Anfrage: Das Monitoring schickt regelmäßig eine kurze Chat-Anfrage mit
max_tokens: 1und API-Key an/v1/chat/completionsund misst die Zeit bis zum Antwortbeginn./healthzeigt, dass der Prozess lebt, nicht dass das Modell antwortet. - Probes am Proxy vorbei:
/healthpassiert den Reverse Proxy nicht, Probes gehen direkt an Container oder Pod.
Metriken, LiteLLM und Langfuse
vLLM liefert Prometheus-Metriken unter /metrics (Metriken-Doku), auch bei gesetztem --api-key ohne Authentifizierung (Sicherheitsdoku). Zähler tragen in Prometheus das Suffix _total, etwa vllm:prompt_tokens_total im Grafana-Beispiel der Doku. Namen vor Alarmregeln mit curl http://localhost:8000/metrics prüfen, die Tabelle nennt die Zähler mit diesem Suffix.
| Frage | Metrik |
|---|---|
| Ist der Cache voll? | vllm:kv_cache_usage_perc (1 = 100 Prozent) |
| Staut sich die Warteschlange? | vllm:num_requests_waiting gegen vllm:num_requests_running |
| Wie schnell beginnen Antworten? | histogram_quantile(0.95, sum by (le) (rate(vllm:time_to_first_token_seconds_bucket[5m]))) |
| Wie flüssig läuft die Ausgabe? | vllm:inter_token_latency_seconds |
| Fehlt Cache-Speicher? | vllm:num_preemptions_total, steigt bei Verdrängung von Anfragen |
| Wirkt Prefix Caching? | vllm:prefix_cache_hits_total geteilt durch vllm:prefix_cache_queries_total |
| Wie enden Anfragen? | vllm:request_success_total |
Alarmschwellen bestimmt das Servicelevel der Anwendung, nicht eine Tabelle. Dauerhaft hohe Cache-Auslastung bei steigenden Preemptions heißt: weniger Kontext, weniger Parallelität oder mehr GPU-Speicher. Veraltete Metriken sind eine Minor-Version später ausgeblendet und eine weitere später entfernt (Metriken-Doku), Dashboards gehören deshalb zum Update-Test.
Ein Gateway ergänzt die Engine-Metriken. LiteLLM spricht vLLM über hosted_vllm/<modell> mit api_base an (Doku) und schreibt mit success_callback: ["langfuse"] Traces nach Langfuse (Doku). So stehen Latenz und Kosten je Anwendung neben den Engine-Werten. Das Gateway ist selbst ein Angriffsziel, siehe LiteLLM-Sicherheitslücke und Gateway-Härtung.
Absicherung
Die Sicherheitsdokumentation von vLLM warnt ausdrücklich davor, sich allein auf --api-key zu verlassen.
--api-keyschützt nur/v1,/v2,/inferenceund/cohere. Ohne Schlüssel erreichbar bleiben unter anderem/invocations(dieselbe Inferenz wie/v1),/pooling,/classify,/score,/rerank,/metrics,/health,/tokenize,/loadsowie Steuerpfade wie/pause,/abort_requestsund/update_weights.- Reverse Proxy mit Allowlist. Nur die benötigten Pfade passieren, alles andere endet mit 403. Rate-Limit und Logging liegen am Proxy. Beispiel für nginx (vor dem Einsatz testen; ohne Pufferung geht die Antwort synchron an den Client, nginx-Doku):
location ~ ^/v1/(chat/completions|completions|models)$ {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_buffering off; # Streaming ohne Zwischenpuffer
proxy_read_timeout 600s; # Default 60s, lange Antworten brauchen mehr
}
location / { return 403; }
- Netz abgrenzen. Bei mehreren Knoten sind PyTorch-Distributed-Verkehr und KV-Transfer unverschlüsselt und gehören in ein isoliertes Netz,
VLLM_HOST_IPbekommt eine feste Adresse. Von außerhalb dieses Netzes darf nur der API-Port erreichbar sein. - Gefährliche Schalter aus:
VLLM_SERVER_DEV_MODE=1(öffnet unter anderem/collective_rpc) nie in Produktion,--enable-tokenizer-info-endpointnur bei Bedarf. - Multimodale Eingaben:
--allowed-media-domainsbegrenzt Abrufe gegen SSRF. Öffentlich erreichbare Dienste setzenVLLM_MAX_N_SEQUENCESniedrig (die Doku nennt 64 oder 128 als Beispiel). - Ein Schlüssel ist kein Rechtekonzept. Schlüssel je Team, Limits und Zuordnung gehören in ein Gateway.
- Datenwege schließen. vLLM sammelt standardmäßig anonyme Nutzungsdaten, abschaltbar mit
VLLM_NO_USAGE_STATS=1oderDO_NOT_TRACK=1(Doku). Hugging-Face-Telemetrie endet mitHF_HUB_DISABLE_TELEMETRY=1, Abrufe beim Hub mitHF_HUB_OFFLINE=1(Doku).--enable-log-requestsschreibt Parameter, auf DEBUG-Stufe auch Prompts ins Log. Bei Personenbezug bleibt es aus.
Anwendungsrisiken wie Prompt Injection behandelt Schutz vor Prompt Injection, den Zugriff von außen Lokale KI sicher von außen bereitstellen.
Updates und Versions-Pinning
Laut PyPI erschienen 0.28.0 (26.08.2026), 0.29.0, 0.30.0, 0.31.0 und 0.32.0 (18.10.2026) in knapp acht Wochen. Die Docker-Tags tragen die Version (v0.32.0), daneben gibt es latest und nightly.
- Image pinnen auf Versionsnummer oder Digest, nie auf
latest. - Zuerst testen: Update auf einer Umgebung mit gleicher GPU und gleichem Modell, danach Startlog (Cache-Größe, Parallelität), Lasttest und Dashboards vergleichen.
- Rückfall behalten: vorherige Compose-Datei und vorheriges Image bleiben verfügbar.
- Modellanforderungen prüfen: Neue Modelle verlangen oft neue vLLM-Versionen, die Model Card von Mistral Medium 3.5 nennt zum Beispiel ein Nightly-Build.
- Caches einplanen: Änderungen an Modell, Konfiguration, torch oder GPU invalidieren den Compile-Cache (Doku), der erste Start nach einem Update dauert länger.
- Sicherheitsmeldungen verfolgen: Das Projekt koordiniert Schwachstellen in einem eigenen Prozess (Vulnerability Management) und veröffentlicht Security Advisories.
Typische Fehler
| Symptom | Ursache | Maßnahme |
|---|---|---|
| Start bricht mit Out-of-Memory ab | Gewichte, Reserve und Cache übersteigen den GPU-Speicher | Kleineres oder quantisiertes Modell, mehr GPUs, --max-model-len und --max-num-seqs senken (Doku) |
Antworten stocken unter Last, num_preemptions_total steigt |
KV-Cache zu klein für Parallelität und Kontextlänge | --max-num-seqs oder --max-num-batched-tokens senken, --gpu-memory-utilization erhöhen oder GPUs ergänzen (Doku) |
| Chat-Anfragen scheitern | Modell ohne Chat-Template im Tokenizer | --chat-template mit Template-Datei angeben (Doku) |
| Tool Calls erscheinen als Text | Auto-Tool-Choice oder passender Parser fehlt | --enable-auto-tool-choice mit modellpassendem --tool-call-parser |
| Antwortstil weicht von Tests ab | Sampling-Defaults kommen aus der generation_config.json des Modells |
Mit --generation-config vllm gegenprüfen (Doku) |
| Start hängt beim Laden | Gewichte kommen vom Netzlaufwerk oder werden heruntergeladen | Modell vorab lokal ablegen |
| Jeder Neustart dauert sehr lange | Compile-Cache nicht persistent | Volume auf /root/.cache/vllm |
Lasttest ohne erfundene Zahlen
Durchsatzzahlen anderer Setups sagen nichts über Ihre Prompts, Ihr Modell und Ihre GPU. Die vLLM-Doku sieht vllm bench serve für Feature- und Regressionstests vor und empfiehlt für Produktionsserver GuideLLM (Benchmarking). Ablauf:
- Eigene Prompts als
.jsonlmit dem Feldprompt, in realer Längenverteilung der Eingaben (kurzer Chat gegen RAG mit langem Kontext). Die Antwortlänge legt--custom-output-lenfest (Default 256), mit--custom-output-len -1gilt je Zeile das Feldoutput_tokens. Keine Echtdaten mit Personenbezug in Testwerkzeuge kopieren. - Stufen: Parallelität schrittweise erhöhen (
--max-concurrency, optional--request-rate). - Messen: Zeit bis zum ersten Token, Zeit zwischen Tokens und Gesamtlatenz als Perzentile, Fehlerquote, daneben
kv_cache_usage_perc,num_requests_waitingundnum_preemptions_totalaus den Metriken. - Prefix-Cache beachten: Wiederholte Läufe mit denselben Prompts blähen den Durchsatz auf. Seed variieren oder den Server neu starten (Doku).
- Abnahme vorab festlegen, mit
--goodputals Ziel je Anfrage. Die Zielwerte setzt der Fachbereich. - Wiederholen nach jedem Update und Modellwechsel.
vllm bench serve --backend openai-chat --endpoint /v1/chat/completions \
--model mistralai/Ministral-3-14B-Instruct-2512 --served-model-name assistent \
--host 127.0.0.1 --port 8000 \
--header "Authorization=Bearer ${VLLM_API_KEY}" \
--dataset-name custom --dataset-path prompts.jsonl --num-prompts 200 \
--skip-chat-template --max-concurrency 8 \
--percentile-metrics ttft,itl,e2el --metric-percentiles 50,95,99
Die Optionen stammen aus der Doku zu vllm bench serve. Der Aufruf läuft je Stufe mit anderem --max-concurrency. --skip-chat-template verhindert, dass der Client das Chat-Template zusätzlich zum Server anwendet (der Endpunkt /v1/chat/completions wendet es selbst an). Der Client lädt den Tokenizer des Modells, ohne Hub-Zugang zeigt --tokenizer auf eine lokale Kopie. Gelesen werden Perzentile, nicht Mittelwerte.
Woran sich eine vLLM-Beratung messen lässt
Ob intern oder extern: Diese Fragen müssen sich mit Dateien und Messwerten beantworten lassen.
- Welche Image-Version läuft, wie ist sie gepinnt, wie sieht der Rückfall aus?
- Liegt die Speicherrechnung mit Annahmen vor (Gewichte, KV-Cache, Reserve)?
- Welche Endpunkte sind von außen erreichbar, und wo steht die Allowlist?
- Welche Metriken und Alarme gibt es, wer empfängt sie?
- Gibt es einen Lasttest mit eigenen Prompts und schriftlichen Abnahmewerten?
- Wie läuft ein Update, und welche Tests gehören dazu?
- Wem gehören Konfiguration, Schlüssel und Zugänge, wie läuft die Rückübergabe?
- Welche Datenwege verlassen die Umgebung (Telemetrie, Logs, Modell-Downloads)?
Stand und Methodik
- Stand: 28.10.2026. Grundlage sind die vLLM-Dokumentation (Version latest) und der Quellcode im Hauptzweig, abgerufen am 28.10.2026.
- Rechnung: Gewichte aus den Dateigrößen der Hugging-Face-Repositories, Cache-Werte aus der
config.json. Die Reserve von 4 GB je GPU ist eine Annahme. - Nicht gemessen: Der Leitfaden enthält keine Benchmarks und keine Durchsatzwerte. Sie entstehen im eigenen Lasttest.
- Beispielmodell: Ministral 3 14B (Apache 2.0), Flags anderer Modelle stehen in deren Model Cards.
Unser Vorgehen bei WZ-IT
Wir betreiben vLLM auf dem Managed GPU Server: dedizierte NVIDIA-GPU in einem deutschen Rechenzentrum mit abgestimmtem Modell, vLLM und Open WebUI. Vor der Bereitstellung prüfen wir Modell, Quantisierung, Kontext und Parallelität rechnerisch gegen 24 oder 96 GB GPU-Speicher. Zum Betrieb gehören Monitoring von Host, GPU und vLLM, Pflege von Betriebssystem, Treiber und vLLM mit CVE-Einordnung und Störungsbearbeitung. Monitoring erfolgt 24/7, die Reaktion auf P1-Incidents erfolgt entsprechend Service Level. Externe APIs, Telemetrie und Backupziele stimmen wir als eigene Datenwege ab. Wer die Anwendung über der Inferenz laufend prüfen will (Traces, Evaluationen, Kosten, Latenz), nutzt Managed LLMOps mit Langfuse. Auf eigener Hardware im eigenen Netz laufen vLLM und Open WebUI vorinstalliert auf dem AI Cube. Das Fachgebiet beschreibt die Seite vLLM-Expertise, die Betriebswege vergleicht LLM-Hosting.
Weiterführende Guides
- Was ist vLLM? - Engine, PagedAttention und Continuous Batching
- vLLM vs. Ollama - wann welche Engine passt
- GPU und VRAM für LLMs richtig dimensionieren - Herleitung der Speicherrechnung
- Multi-GPU-Inferenz ohne NVLink - Tensor- und Pipeline-Parallelität
- LLM-Quantisierung - FP8, NVFP4 und AWQ im Vergleich
- Was ist LiteLLM? - Gateway vor vLLM
- Was ist Langfuse? - Traces und Evaluationen
- vLLM, Ollama oder llama.cpp - Inferenz-Server im Vergleich
- vLLM mit Qwen3.5-122B auf zwei RTX PRO 6000 - Praxisbeispiel mit Compose und Hybrid-Modell
vLLM in Betrieb nehmen? WZ-IT betreibt vLLM auf dediziertem GPU-Server in Deutschland oder prüft Ihre Anwendung laufend. Managed GPU Server · Managed LLMOps · LLM-Hosting











