Aller au contenu

vLLM — Inférence LLM haute performance

vLLM est un serveur d'inférence LLM haute performance conçu pour les environnements de production avec GPU. Il remplace Ollama lorsque du matériel GPU est disponible, en servant une API compatible OpenAI avec du batching continu et une utilisation optimisée de la mémoire GPU. LiteLLM route automatiquement vers vLLM lorsqu'il est activé.

Architecture

Notebooks / Cockpit / Applications
            |
      +-----v------+
      |   LiteLLM   |  API compatible OpenAI (port 4000)
      | (Passerelle) |
      +-----+------+
            |
      +-----v------+
      |    vLLM     |  Inférence GPU (port 8000)
      |  Qwen/Qwen2.5-7B-Instruct
      +------------+

En développement (sans GPU), LiteLLM route vers Ollama. En production (GPU disponible), LiteLLM route vers vLLM. Le basculement est transparent — le code applicatif ne change jamais.

Dev :  LiteLLM → Ollama (CPU, plusieurs petits modèles)
Prod : LiteLLM → vLLM   (GPU, un seul modèle haute performance)

URLs

Mode URL
Kubernetes (production) Interne uniquement — accessible via la passerelle LiteLLM

vLLM n'a pas d'ingress propre. Toutes les requêtes passent par LiteLLM (https://llm.akko.local), qui route vers vLLM en interne.


Utilisation

Depuis les notebooks (via LiteLLM)

Aucune modification de code nécessaire. La même API LiteLLM fonctionne que le backend soit Ollama ou vLLM :

from openai import OpenAI

client = OpenAI(
    base_url="http://akko-akko-litellm:4000/v1",
    api_key="akko-dev-litellm-key",
)

response = client.chat.completions.create(
    model="akko-coder",  # Routé vers vLLM en production
    messages=[{"role": "user", "content": "Écris une requête SQL pour la segmentation clients"}],
)
print(response.choices[0].message.content)

API vLLM directe (interne)

Pour les services qui doivent contourner LiteLLM :

from openai import OpenAI

client = OpenAI(
    base_url="http://akko-akko-vllm:8000/v1",
    api_key="EMPTY",  # vLLM ne requiert pas d'authentification en interne
)

response = client.chat.completions.create(
    model="Qwen/Qwen2.5-7B-Instruct",
    messages=[{"role": "user", "content": "Explique Apache Iceberg"}],
)

Configuration

Environnement de développement (values-dev.yaml)

vLLM est désactivé en dev — Ollama gère l'inférence sur CPU :

akko-vllm:
  enabled: false

akko-litellm:
  vllmBackend:
    enabled: false  # Route vers Ollama

Environnement de production (values-production.yaml)

vLLM est activé avec des ressources GPU :

akko-vllm:
  enabled: true
  replicaCount: 1
  model:
    name: "Qwen/Qwen2.5-7B-Instruct"
    maxModelLen: 4096
    gpuMemoryUtilization: 0.9

akko-litellm:
  vllmBackend:
    enabled: true
    host: "akko-akko-vllm"
    port: 8000
    model: "Qwen/Qwen2.5-7B-Instruct"

Configuration du modèle

Paramètre Défaut Description
model.name Qwen/Qwen2.5-7B-Instruct Identifiant du modèle HuggingFace
model.maxModelLen 4096 Longueur maximale de séquence
model.gpuMemoryUtilization 0.9 Fraction de mémoire GPU à utiliser (0.0-1.0)

Fonctionnalités principales

Fonctionnalité Description
Batching continu Regroupe dynamiquement les requêtes entrantes pour un débit maximal
PagedAttention Gestion efficace de la mémoire GPU, sert plus de requêtes simultanées
API compatible OpenAI Remplacement direct — même API qu'OpenAI, GPT4All, Ollama
Modèles HuggingFace Charge n'importe quel modèle depuis HuggingFace Hub par identifiant
Optimisation mémoire GPU Ratio d'utilisation configurable pour équilibrer débit et taille de modèle
Parallélisme tensoriel Mise à l'échelle sur plusieurs GPU pour les modèles plus grands

Dev vs Production

Aspect Dev (Ollama) Production (vLLM)
Matériel CPU (Apple Silicon / x86) GPU NVIDIA (CUDA)
Modèles Plusieurs petits modèles (3B-7B) Un seul modèle optimisé (7B+)
Débit Faible (1-5 tokens/s) Élevé (50-200+ tokens/s)
Batching Séquentiel Batching continu
Mémoire RAM système VRAM GPU (16 Gi+ recommandé)
Valeur Helm akko-vllm.enabled: false akko-vllm.enabled: true

Ressources requises

Ressource Minimum Recommandé
GPU 1x NVIDIA (16 Go VRAM) 1x NVIDIA A100 (40/80 Go)
RAM 8 Gi 16 Gi
Utilisation mémoire GPU 0.8 0.9

GPU requis

vLLM nécessite un GPU NVIDIA avec support CUDA. Il ne démarrera pas sur des nœuds sans GPU. Pour le développement sans GPU, utilisez Ollama à la place (akko-vllm.enabled: false).

Téléchargement du modèle

Au premier démarrage, vLLM télécharge le modèle depuis HuggingFace Hub. Pour Qwen/Qwen2.5-7B-Instruct, cela représente environ 15 Go. Assurez-vous de disposer de suffisamment d'espace disque et de bande passante réseau.


Healthcheck

vLLM expose un endpoint /health utilisé par les sondes Kubernetes :

livenessProbe:
  httpGet:
    path: /health
    port: 8000
  initialDelaySeconds: 120  # Le chargement du modèle prend du temps
  periodSeconds: 30
readinessProbe:
  httpGet:
    path: /health
    port: 8000
  initialDelaySeconds: 60
  periodSeconds: 10

Démarrage lent

vLLM met 60 à 120 secondes pour charger un modèle 7B en mémoire GPU. Le initialDelaySeconds est configuré en conséquence pour éviter les redémarrages prématurés.


Dépannage

GPU non détecté

Symptômes : Le pod vLLM ne démarre pas. Les logs affichent RuntimeError: No CUDA GPUs are available ou torch.cuda.is_available() returns False. Le pod entre en CrashLoopBackOff.

Cause : Le nœud Kubernetes n'a pas de GPU NVIDIA, le plugin de périphériques NVIDIA n'est pas installé, ou la spécification du pod ne contient pas la demande de ressource nvidia.com/gpu.

Solution :

# Vérifier si le plugin de périphériques NVIDIA tourne
kubectl get pods -n kube-system | grep nvidia

# Vérifier que les ressources GPU sont annoncées par les nœuds
kubectl describe nodes | grep -A5 "nvidia.com/gpu"

# Consulter les événements du pod vLLM pour les échecs de planification
kubectl describe pod -n akko -l app.kubernetes.io/name=akko-vllm | grep -A10 "Events"

# Vérifier que le pod demande des ressources GPU
kubectl get pod -n akko -l app.kubernetes.io/name=akko-vllm -o jsonpath='{.items[0].spec.containers[0].resources}'

# Si aucun GPU n'est disponible, désactiver vLLM et utiliser Ollama à la place
# helm upgrade akko helm/akko/ -n akko --set akko-vllm.enabled=false

Incompatibilité de version CUDA

Symptômes : Le pod vLLM démarre mais plante immédiatement. Les logs affichent CUDA driver version is insufficient for CUDA runtime version ou CUDA error: no kernel image is available for execution on the device.

Cause : La version du runtime CUDA dans l'image du conteneur vLLM ne correspond pas à la version du driver CUDA installé sur le nœud hôte. Cela arrive typiquement avec des drivers GPU anciens ou des images de conteneur plus récentes.

Solution :

# Vérifier la version du driver CUDA sur l'hôte
kubectl exec -n akko -l app.kubernetes.io/name=akko-vllm -- nvidia-smi 2>/dev/null || echo "nvidia-smi non disponible"

# Vérifier la version CUDA dans le conteneur vLLM
kubectl logs -n akko deploy/akko-akko-vllm --tail=20 | grep -i "cuda\|driver"

# Vérifier que la capacité de calcul du GPU correspond aux exigences du modèle
kubectl exec -n akko deploy/akko-akko-vllm -- python3 -c "import torch; print(torch.cuda.get_device_capability())" 2>/dev/null

# Solutions :
# 1. Mettre à jour le driver NVIDIA sur le nœud hôte
# 2. Utiliser une image vLLM compilée pour votre version CUDA
# 3. Fixer le tag de l'image vLLM à une version compatible avec votre driver

Timeout de téléchargement du modèle

Symptômes : Le pod vLLM reste en état Running mais ne devient jamais Ready. Les logs affichent Downloading model... avec une progression lente ou bloquée. La sonde de disponibilité finit par échouer et le pod redémarre.

Cause : Le téléchargement du modèle HuggingFace est lent à cause de limitations de bande passante réseau, d'un proxy bloquant les gros téléchargements, ou d'un HF_TOKEN manquant pour les modèles à accès restreint.

Solution :

# Vérifier la progression du téléchargement dans les logs
kubectl logs -n akko deploy/akko-akko-vllm --tail=30 | grep -i "download\|model\|huggingface"

# Vérifier la connectivité réseau depuis le pod
kubectl exec -n akko deploy/akko-akko-vllm -- curl -sI https://huggingface.co

# Augmenter le timeout de la sonde de disponibilité pour les téléchargements lents
# Dans values : initialDelaySeconds: 300, failureThreshold: 30

# Pour les modèles à accès restreint, s'assurer que HF_TOKEN est défini
kubectl get secret -n akko -l app.kubernetes.io/name=akko-vllm -o yaml | grep HF_TOKEN

# Envisager le pré-téléchargement du modèle sur un PVC pour éviter les téléchargements répétés

Mémoire VRAM insuffisante

Symptômes : vLLM plante avec torch.cuda.OutOfMemoryError: CUDA out of memory ou ValueError: The model's max seq len is too large. Le pod redémarre en boucle.

Cause : Le modèle nécessite plus de VRAM GPU que disponible. Le ratio gpuMemoryUtilization est trop élevé (ne laissant pas de place pour le cache KV), ou maxModelLen est trop grand pour la mémoire disponible.

Solution :

# Vérifier l'utilisation de la mémoire GPU
kubectl exec -n akko deploy/akko-akko-vllm -- nvidia-smi 2>/dev/null

# Vérifier la configuration actuelle
kubectl get cm -n akko -l app.kubernetes.io/name=akko-vllm -o yaml | grep -i "memory\|model_len\|gpu"

# Réduire l'utilisation de la mémoire GPU et la longueur maximale de séquence
# Dans votre fichier values :
# akko-vllm.model.gpuMemoryUtilization: 0.8  (au lieu de 0.9)
# akko-vllm.model.maxModelLen: 2048           (au lieu de 4096)

helm upgrade akko helm/akko/ -n akko -f helm/examples/values-dev.yaml \
  --set akko-vllm.model.gpuMemoryUtilization=0.8 \
  --set akko-vllm.model.maxModelLen=2048

# Ou passer à un modèle plus petit (ex. 3B au lieu de 7B)

Démarrage lent (chargement du modèle)

Symptômes : Le pod vLLM est Running mais pas Ready pendant plusieurs minutes. L'endpoint de santé retourne des erreurs. Les routes LiteLLM échouent car le backend vLLM n'est pas encore disponible.

Cause : Le chargement d'un modèle 7B+ en mémoire GPU prend 60 à 120+ secondes. Le initialDelaySeconds par défaut peut être insuffisant pour des modèles plus grands ou du matériel plus lent.

Solution :

# Vérifier l'âge du pod et le statut de disponibilité
kubectl get pods -n akko -l app.kubernetes.io/name=akko-vllm -o wide

# Suivre les logs de démarrage en temps réel
kubectl logs -n akko deploy/akko-akko-vllm -f --tail=20

# Vérifier si l'endpoint de santé répond
kubectl exec -n akko deploy/akko-akko-vllm -- curl -s http://localhost:8000/health || echo "Pas encore prêt"

# Si le pod redémarre à cause d'échecs de sonde, augmenter le délai
# Dans values : livenessProbe.initialDelaySeconds: 300
# Dans values : readinessProbe.initialDelaySeconds: 120, failureThreshold: 30

# Vérifier que LiteLLM gère le démarrage de vLLM correctement
kubectl logs -n akko deploy/akko-akko-litellm --tail=20 | grep -i "vllm\|backend\|error"