Kubernetes GPU : comment gérer vos workloads IA efficacement

Rédigé par Matthieu ROBIN | May 27, 2026 12:00:00 PM

Device plugins, GPU Operator, MIG et time-slicing : le guide complet

Temps de lecture : 6 minutes

La gestion des GPU dans Kubernetes constitue un défi technique majeur pour les organisations déployant des workloads d'IA à l'échelle. Selon Collabnix, 48% des organisations exécutent désormais leurs workloads AI/ML sur Kubernetes, avec une croissance de 300% des recherches "Kubernetes AI" en 2025. Cette adoption massive génère une pression sur les équipes infrastructure : comment orchestrer efficacement des ressources GPU coûtant 2 à 10 CHF par heure tout en maximisant l'utilisation et en garantissant l'isolation entre tenants ?

Kubernetes ne gère pas nativement les GPU comme des ressources de première classe. Le scheduler standard traite les GPU comme des compteurs binaires (0 ou 1), ignorant leurs caractéristiques spécifiques : modèle, mémoire VRAM, topologie réseau. Cette approche simpliste génère du gaspillage : pods consommant 10% d'un GPU tout en bloquant l'accès aux 90% restants, clusters hétérogènes où des H100 servent des workloads qui ne nécessitent qu'un T4. Cet article détaille les trois composants critiques de la gestion GPU dans Kubernetes — Device Plugin, GPU Operator, et schedulers spécialisés —, expose les stratégies de partage GPU (MIG, time-slicing), et propose un framework de déploiement progressif testé en production.

 

Les 3 composants clés de Kubernetes GPU

L'orchestration GPU dans Kubernetes repose sur trois couches logicielles complémentaires qui transforment des accélérateurs matériels en ressources schedulables.

Device Plugin : exposer les GPU au scheduler

Le Device Plugin framework constitue le mécanisme par lequel Kubernetes découvre et alloue des ressources matérielles spécialisées. Chaque device plugin s'exécute comme un DaemonSet sur les nœuds GPU, communique avec le kubelet via gRPC, et expose des ressources étendues (extended resources) visibles du scheduler. Pour NVIDIA, le k8s-device-plugin officiel expose la ressource nvidia.com/gpu.

L'architecture est simple : le device plugin interroge périodiquement le pilote NVIDIA pour lister les GPU disponibles sur le nœud, puis notifie le kubelet de ces ressources via l'API ListAndWatch. Lorsqu'un pod demande nvidia.com/gpu: 1, le kubelet réserve un GPU et configure le runtime de conteneur (containerd ou CRI-O) pour exposer le device GPU au conteneur via NVIDIA Container Toolkit.

Architecture Device Plugin :

Node avec 4× A100 80GB

Device Plugin (DaemonSet)
↓ gRPC ListAndWatch
Kubelet
↓ expose ressources
Scheduler Kubernetes
↓ placement decision
Pod avec nvidia.com/gpu: 2
↓ runtime configuration
Container avec accès 2× GPU

Le device plugin standard présente deux limitations majeures. Premièrement, il traite tous les GPU comme homogènes : impossible de demander spécifiquement un H100 versus un A100, le scheduler place le pod sur le premier nœud ayant des GPU disponibles sans considération du modèle. Deuxièmement, l'allocation est tout-ou-rien : un pod demandant un GPU obtient l'accès exclusif complet, même s'il n'utilise que 15% de sa capacité.

GPU Operator : automatisation du cycle de vie

NVIDIA GPU Operator résout le problème de gestion du stack logiciel GPU sur chaque nœud. Avant GPU Operator, les administrateurs devaient installer manuellement sur chaque nœud : pilotes NVIDIA, NVIDIA Container Toolkit, device plugin, DCGM pour monitoring, GPU Feature Discovery pour labeling. Cette approche manuelle générait des incohérences de versions, des erreurs de configuration, et des temps de déploiement comptés en jours.

GPU Operator implémente le pattern Operator de Kubernetes : une Custom Resource Definition (ClusterPolicy) décrit l'état désiré du cluster GPU, et l'opérateur converge automatiquement l'état réel vers cet état désiré. Lors du déploiement, GPU Operator installe via DaemonSets sur les nœuds GPU : pilotes NVIDIA (ou détecte les pilotes pré-installés), NVIDIA Container Toolkit, k8s-device-plugin, DCGM Exporter, GPU Feature Discovery, Node Status Exporter.

Installation GPU Operator (Helm) :

# Ajouter le repo Helm NVIDIA
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update

# Installer GPU Operator
helm install gpu-operator nvidia/gpu-operator \
  --namespace gpu-operator \
  --create-namespace \
  --version v24.9.0 \
  --set driver.enabled=true

# Vérifier déploiement
kubectl get pods -n gpu-operator
kubectl get nodes -o json | jq '.items[].status.allocatable'

GPU Feature Discovery (GFD), composant de GPU Operator, applique automatiquement des labels aux nœuds décrivant leurs GPU : nvidia.com/gpu.product (nom commercial comme A100-SXM4-80GB), nvidia.com/gpu.memory (VRAM en bytes), nvidia.com/gpu.count (nombre de GPU), nvidia.com/cuda.driver.major et minor (version driver), nvidia.com/gpu.family (architecture : ampere, hopper). Ces labels permettent des nodeSelector et affinités précis dans les pod specs.

Schedulers spécialisés : au-delà du scheduler par défaut

Le scheduler Kubernetes standard utilise des prédicats (filters) et des priorités (scores) pour placer les pods. Pour les GPU, ses limitations deviennent critiques : absence de gang scheduling (tous les pods d'un job multi-GPU ou aucun), pas de quotas par tenant ou par queue, pas de préemption intelligente basée sur priorités métier, topologie réseau (NVLink, InfiniBand) ignorée lors du placement.

Les schedulers spécialisés comblent ces lacunes. NVIDIA KAI Scheduler, open-sourcé en janvier 2025, introduit : fractional GPU requests (nvidia.com/gpu: 0.5), gang scheduling natif via PodGroups, queues hiérarchiques avec quotas, topology-aware scheduling pour workloads distribués, préemption configurable par priorité et fairness.

Kueue, développé par Kubernetes SIG, fonctionne comme couche d'admission control avant scheduling : les workloads (Jobs, PyTorchJobs, RayJobs) sont enqueueés dans des LocalQueues liées à des ClusterQueues avec quotas configurés. Kueue simule le scheduling sur le cluster et admet (ou retient) le workload atomiquement. Les cohorts permettent à plusieurs queues de partager des quotas idle avec weighted fairness.

Volcano, projet CNCF, implémente gang scheduling strict et bin-packing optimisé : tous les pods d'un PodGroup sont schedulés simultanément ou aucun, évitant les deadlocks. Volcano supporte plusieurs algorithmes de scheduling : proportion (fair-share), gang (atomicité), DRF (dominant resource fairness), binpack (minimiser fragmentation).

Scheduler Force principale Use case optimal Complexité
Kubernetes standard Simplicité, par défaut Workloads single-GPU, faible concurrence Faible
KAI Scheduler Fractional GPU, topologie Multi-tenant, GPU sharing, disaggregated serving Moyenne
Kueue Quotas, cohorts, fairness Multi-équipes, budgets GPU, priorités métier Moyenne
Volcano Gang scheduling, bin-packing Training distribué, workloads multi-GPU/multi-node Élevée

 

Stratégies de partage GPU : MIG vs time-slicing

Partager un GPU entre plusieurs pods améliore l'utilisation et réduit les coûts. Deux approches dominent : Multi-Instance GPU (MIG) avec isolation matérielle, et time-slicing logiciel.

MIG : isolation matérielle par partition

Multi-Instance GPU (MIG), introduit avec l'architecture Ampere (A100, A30), partitionne physiquement un GPU en jusqu'à 7 instances indépendantes. Chaque instance MIG dispose de ressources dédiées : Streaming Multiprocessors (SM), mémoire VRAM, contrôleurs mémoire, cache L2. L'isolation est garantie matériellement : un crash dans une instance MIG n'affecte pas les autres, la bande passante mémoire est garantie par le QoS hardware.

Un A100 80GB supporte plusieurs profils MIG : 1g.10gb (1/7 du GPU, 10 GB VRAM), 2g.20gb (2/7, 20 GB), 3g.40gb (3/7, 40 GB), 7g.80gb (GPU complet). Un H100 80GB propose : 1g.10gb, 2g.20gb, 3g.40gb, 4g.40gb, 7g.80gb. Les profils définissent les combinaisons possibles : un A100 peut héberger simultanément 7× 1g.10gb, ou 2× 3g.40gb + 1× 1g.10gb, selon les besoins.

Configuration MIG dans Kubernetes :

# Activer MIG sur le GPU (requiert reboot)
nvidia-smi -i 0 -mig 1

# Créer instances MIG (exemple : 2× 3g.40gb + 1× 1g.10gb)
nvidia-smi mig -cgi 3g.40gb -C
nvidia-smi mig -cgi 3g.40gb -C
nvidia-smi mig -cgi 1g.10gb -C

# ConfigMap GPU Operator pour MIG
apiVersion: v1
kind: ConfigMap
metadata:
  name: gpu-operator-config
data:
  migStrategy: mixed  # single, mixed, ou none

Le mode mixed expose à la fois des GPU complets (nvidia.com/gpu) et des instances MIG (nvidia.com/mig-3g.40gb). Les pods peuvent demander soit un GPU complet, soit une instance MIG spécifique. Le mode single expose uniquement les instances MIG, forçant tous les workloads à utiliser MIG.

Les limitations MIG incluent : configurations statiques nécessitant GPU reset pour modification, maximum 7 instances par GPU limitant la granularité, overhead de gestion pour petits clusters (moins de 10 GPU), support limité aux GPU Ampere et Hopper (A100, A30, H100, H200).

Time-slicing : partage logiciel par multiplexage

Le time-slicing permet à plusieurs conteneurs de partager un GPU via CUDA time-slicing : le driver GPU commute rapidement le contexte entre processus, donnant à chacun une tranche de temps d'exécution. Contrairement à MIG, il n'y a aucune isolation mémoire ni garantie de bande passante. Un pod "noisy neighbor" peut épuiser la VRAM et provoquer des erreurs CUDA OOM dans les autres pods partageant le même GPU.

Le time-slicing s'avère idéal pour : environnements de développement et notebooks interactifs, inférence légère (chatbots, APIs) avec latence tolérante, GPU anciens ne supportant pas MIG (T4, V100, P100), partage très granulaire (16+ workloads par GPU). À l'inverse, time-slicing ne convient pas aux workloads exigeant : performances prévisibles et garanties, isolation mémoire stricte, latence ultra-faible (<50ms), training intensif nécessitant GPU exclusif.

Configuration time-slicing (ConfigMap) :

apiVersion: v1
kind: ConfigMap
metadata:
  name: device-plugin-config
  namespace: gpu-operator
data:
  A100-SXM4-80GB: |-
    version: v1
    sharing:
      timeSlicing:
        resources:
        - name: nvidia.com/gpu
          replicas: 4  # 1 GPU physique → 4 GPU logiques
  Tesla-T4: |-
    version: v1
    sharing:
      timeSlicing:
        resources:
        - name: nvidia.com/gpu
          replicas: 8  # 1 T4 → 8 replicas

Après application de cette configuration, un nœud avec 1× A100 80GB annoncera nvidia.com/gpu: 4 au lieu de nvidia.com/gpu: 1. Quatre pods pourront chacun demander nvidia.com/gpu: 1 et s'exécuter concurremment sur le même GPU physique. GPU Feature Discovery ajoute le label nvidia.com/gpu.product: A100-SXM4-80GB-SHARED pour distinguer les GPU time-sliced.

Critère MIG Time-slicing
Isolation Matérielle (VRAM, SM, cache) Aucune (logiciel)
Performances Garanties, prévisibles Variables, contention possible
Granularité Max 7 instances par GPU Illimitée (pratique : 8-16)
GPU supportés Ampere et Hopper uniquement Tous GPU NVIDIA
Configuration Statique, requiert reset GPU Dynamique, ConfigMap
Use case optimal Production multi-tenant, SLA stricts Dev/test, inférence légère

 

Configuration pas-à-pas : cluster Kubernetes GPU

Le déploiement d'un cluster Kubernetes GPU pour workloads IA suit une progression méthodique en 5 étapes, chacune validée avant passage à la suivante.

Étape 1 : Préparation infrastructure (1-2 jours)

Les nœuds GPU nécessitent des prérequis système spécifiques. Kernel Linux récent (5.15+) avec modules NVIDIA activés, secure boot désactivé (incompatible pilotes propriétaires), packages de base installés : build-essential, gcc, make, linux-headers-$(uname -r). Pour les déploiements cloud (AWS, Azure, GCP), utiliser des instance types dédiées GPU : AWS p4d.24xlarge (8× A100), Azure NC A100 v4, GCP a2-highgpu-8g.

Sur site (on-premise), vérifier BIOS settings : IOMMU activé pour passthrough GPU, PCIe ASPM désactivé (peut causer instabilité), Above 4G Decoding activé pour GPU 80GB+. Confirmer visibilité GPU via lspci | grep -i nvidia. Installer runtime conteneur compatible : containerd 1.7+ ou CRI-O 1.28+ avec support CDI (Container Device Interface).

Étape 2 : Déploiement GPU Operator (3-4 heures)

GPU Operator s'installe via Helm chart officiel. La configuration ClusterPolicy détermine les composants à déployer. Pour production, activer : pilotes NVIDIA (sauf si pré-installés sur les nœuds), device plugin, DCGM Exporter pour monitoring, GPU Feature Discovery, toolkit et validation.

Installation complète GPU Operator :

# Créer namespace
kubectl create namespace gpu-operator

# Installer via Helm avec paramètres production
helm install gpu-operator nvidia/gpu-operator \
  -n gpu-operator \
  --set driver.enabled=true \
  --set driver.version="550.90.07" \
  --set toolkit.version="1.16.2" \
  --set devicePlugin.version="v0.16.2" \
  --set dcgmExporter.enabled=true \
  --set gfd.enabled=true \
  --set operator.defaultRuntime=containerd

# Validation
kubectl wait --for=condition=ready pod -l app=gpu-operator -n gpu-operator --timeout=600s
kubectl get nodes -o json | jq '.items[].status.allocatable | select(.["nvidia.com/gpu"] != null)'

La validation confirme que les nœuds exposent la ressource nvidia.com/gpu et que les labels GFD sont appliqués. Tester avec un pod CUDA simple vérifie le fonctionnement end-to-end.

Étape 3 : Configuration partage GPU (4-6 heures)

Décider de la stratégie de partage selon use cases : MIG pour production multi-tenant avec SLA, time-slicing pour dev/test et inférence légère, GPU exclusifs pour training intensif. Il est possible de mixer les stratégies sur différents node pools : node pool "production" avec MIG, node pool "dev" avec time-slicing, node pool "training" GPU exclusifs.

Pour MIG, configurer les profils sur chaque GPU puis modifier la ClusterPolicy pour stratégie MIG. Pour time-slicing, créer ConfigMap avec configurations par modèle GPU, puis patcher la ClusterPolicy pour référencer ce ConfigMap. Appliquer labels aux nœuds pour sélection précise : kubectl label nodes gpu-node-1 gpu-sharing=mig, kubectl label nodes gpu-node-2 gpu-sharing=time-sliced.

Étape 4 : Monitoring et observabilité (2-3 heures)

DCGM Exporter, déployé par GPU Operator, expose métriques GPU au format Prometheus. Métriques critiques : DCGM_FI_DEV_GPU_UTIL (utilization %), DCGM_FI_DEV_FB_USED et DCGM_FI_DEV_FB_FREE (VRAM), DCGM_FI_DEV_POWER_USAGE (consommation W), DCGM_FI_DEV_GPU_TEMP (température), DCGM_FI_DEV_SM_CLOCK (fréquence GPU).

Configurer Prometheus pour scraper DCGM Exporter sur port 9400. Importer dashboard Grafana préconfiguré (ID 12239) visualisant : utilization GPU par nœud, usage VRAM avec seuils, température et throttling, consommation électrique totale cluster. Définir alertes : GPU utilization <30% pendant 1h (sous-utilisation), VRAM >90% (risque OOM), température >85°C (throttling imminent).

Étape 5 : Quotas et politiques (1-2 jours)

ResourceQuotas Kubernetes limitent la consommation GPU par namespace. Un quota typique : requests.nvidia.com/gpu: "8" limite un namespace à 8 GPU simultanés. LimitRanges définissent min/max par pod : empêcher pods demandant 0 GPU ou >4 GPU.

Pour contrôle avancé, déployer Kueue ou Volcano. Kueue implémente queues avec quotas : équipe A quota 16 GPU, équipe B quota 8 GPU, avec cohort permettant emprunt de quota idle. Volcano implémente priorités et préemption : pods haute priorité peuvent préempter pods basse priorité pour libérer GPU.

 

Les 5 erreurs qui dégradent l'efficacité GPU

1. Ne pas utiliser node labels et affinity

Symptôme : Déployer des pods sans nodeSelector ni affinity, laissant le scheduler placer les workloads sur n'importe quel nœud GPU disponible sans considération du modèle.

Impact : Workloads d'inférence légère schedulés sur H100 coûteux (7 CHF/h) alors qu'un T4 (1,2 CHF/h) suffirait. Modèles 70B+ schedulés sur nœuds A100 40GB provoquant OOM immédiat au lieu de cibler A100 80GB. Fragmentation GPU : cluster avec 50% H100 idle pendant que des jobs attendent des A100 tous occupés. Gaspillage estimé : 30 à 50% du budget GPU pour clusters hétérogènes.

Solution : Labelliser les nœuds par modèle GPU et capabilities. Utiliser nodeSelector pour workloads simples : nodeSelector: nvidia.com/gpu.product: Tesla-T4. Utiliser node affinity pour logique complexe : préférer H100 mais accepter A100 si indisponible. Créer node pools dédiés : pool "inference" avec T4/L40S, pool "training" avec A100/H100. Automatiser via admission controllers validant que chaque pod GPU spécifie un nodeSelector approprié.

2. Ignorer les resource limits

Symptôme : Définir uniquement requests.nvidia.com/gpu sans limits, ou inversement.

Impact : Pour les GPU, requests et limits doivent être identiques car GPU ne se partage pas par throttling comme CPU. Un pod avec requests: 1, limits: 2 obtient 1 GPU mais réservera 2 slots, causant gaspillage. Un pod sans limits n'est pas OOM-killable côté GPU (kubelet ne peut pas forcer libération GPU). Quotas namespace contournables si seuls requests sont quotés. Résultat : fragmentation ressources, quotas inefficaces, billing imprécis.

Solution : Toujours définir requests et limits identiques pour GPU : resources: limits: nvidia.com/gpu: "2" requests: nvidia.com/gpu: "2". Utiliser LimitRange pour forcer cette égalité au niveau namespace. Monitorer pods avec requests != limits via policy engine (OPA, Kyverno) et rejeter automatiquement. Pour fractional GPU (KAI Scheduler), respecter même principe avec valeurs fractionnaires : nvidia.com/gpu: "0.5" en requests et limits.

3. Sous-estimer la configuration réseau multi-GPU

Symptôme : Déployer training distribué multi-GPU/multi-node sans configurer RDMA, GPUDirect, ou topologie NVLink.

Impact : Un training PyTorch DistributedDataParallel sur 32 GPU (4 nœuds × 8 GPU) communique via réseau Ethernet standard (25 Gbps) au lieu de RDMA InfiniBand (200 Gbps). Temps de synchronisation gradients passe de 150ms (InfiniBand) à 1200ms (Ethernet), multipliant le temps d'itération par 5. Sur un training 1000 epochs, l'overhead réseau ajoute plusieurs jours. Coût GPU gaspillé : 60-70% du temps passé en attente réseau. Sur 4 nœuds H100 à 56 CHF/h cumulé, c'est 35 CHF/h brûlés en idle réseau.

Solution : Configurer RDMA sur nœuds GPU : installer drivers InfiniBand ou ROCEv2, activer GPUDirect RDMA dans GPU Operator (--set rdma.enabled=true). Pour on-premise, déployer réseau InfiniBand HDR 200 Gbps minimum. Pour cloud, utiliser instance types avec réseau optimisé : AWS p4d (400 Gbps EFA), Azure ND A100 v4 (200 Gbps InfiniBand). Utiliser topology-aware scheduling (KAI Scheduler, Volcano) pour placer pods d'un même job sur nœuds proches topologiquement. Valider bande passante réseau GPU-GPU avec benchmarks NCCL avant production.

4. Mélanger MIG et time-slicing sans stratégie claire

Symptôme : Activer MIG sur certains GPU et time-slicing sur d'autres dans le même node pool, sans documentation ni labels clairs.

Impact : Confusion utilisateurs : certains pods demandent nvidia.com/gpu: 1 et obtiennent GPU complet, d'autres obtiennent instance MIG, d'autres encore obtiennent time-slice, selon quel nœud le scheduler a choisi. Performances imprévisibles : même pod redéployé performe différemment selon placement. Debugging complexe : identifier quel type de GPU a reçu un pod nécessite inspection labels nœud, ConfigMap device plugin, et MIG configuration. Temps DevOps gaspillé : 2-3 heures par incident diagnostic.

Solution : Définir stratégie claire par node pool : pool A full GPU exclusifs, pool B MIG uniquement, pool C time-slicing uniquement. Labelliser explicitement : gpu-mode: exclusive, gpu-mode: mig, gpu-mode: time-sliced. Forcer les utilisateurs à spécifier nodeSelector pour GPU mode souhaité via admission policy. Documenter dans wiki interne quel pool pour quel use case. Pour experts, mode mixte possible mais nécessite rigueur : exposer MIG et time-slice comme ressources différentes (nvidia.com/mig-3g.40gb vs nvidia.com/gpu.shared), jamais nvidia.com/gpu ambigu.

5. Absence de gang scheduling pour training distribué

Symptôme : Lancer jobs training distribué (PyTorchJob, MPIJob) sur cluster Kubernetes standard sans gang scheduling, en espérant que tous les pods seront schedulés.

Impact : Un PyTorchJob requiert 16 pods (16 GPU). Le scheduler place 12 pods immédiatement, mais 4 restent Pending car pas assez de GPU disponibles dans le cluster. Les 12 pods lancés attendent indéfiniment les 4 manquants (DistributedDataParallel bloque au rendezvous). GPU des 12 pods idle 100% jusqu'à timeout (souvent 30-60 min). À 3,2 CHF/h par A100, c'est 38 CHF gaspillés par job échoué. En production, 20-40% des jobs training échouent ainsi sans gang scheduling selon benchmarks Uber KubeCon 2024.

Solution : Déployer scheduler avec gang scheduling : Volcano (maturité élevée, CNCF), Kueue (intégration native Kubernetes), ou KAI Scheduler (features NVIDIA avancées). Pour Volcano, wrapper le Job dans PodGroup spécifiant minMember = nombre total pods : tous schedulés simultanément ou aucun. Configurer timeout raisonnable : 10-15 minutes pour jobs 8-16 GPU, 30 minutes pour jobs 32+ GPU. Monitorer métriques gang scheduling : taux de jobs admis du premier coup, temps moyen d'attente en queue, taux de deadlocks évités. ROI immédiat : économie 20-30% du budget training via élimination des échecs partiels.

 

Cas pratique : cluster multi-tenant pour équipes ML

Cas concret : startup suisse IA avec 3 équipes (Research, Production, Data Science), budget GPU 25'000 CHF/mois, besoins hétérogènes. Infrastructure : cluster Kubernetes on-premise avec 3 node pools : 4× nœuds H100 80GB (training intensif), 8× nœuds A100 80GB (production inférence + fine-tuning), 6× nœuds L40S 48GB (dev/test + inférence légère).

Configuration déployée :

  • Pool Training (H100) : GPU exclusifs, Volcano gang scheduling, quotas par équipe : Research 50% (2 nœuds), Production 30%, Data Science 20%
  • Pool Production (A100) : MIG 2× 3g.40gb + 1× 1g.10gb par GPU, Kueue avec quotas stricts, SLA latence <200ms
  • Pool Dev (L40S) : Time-slicing 8 replicas par GPU, pas de gang scheduling, best-effort QoS

Quotas Kueue implémentés :

ClusterQueue "production" :
  - Flavors : A100-MIG-3g40gb, A100-MIG-1g10gb
  - Quota nominal : 12× 3g.40gb, 4× 1g.10gb
  - Max par workload : 4× 3g.40gb

ClusterQueue "research" :
  - Flavors : H100-full
  - Quota nominal : 16 H100 full
  - Max par workload : 8 H100 (gang scheduling)
  - Borrowing : peut emprunter de "production" si idle

ClusterQueue "dev" :
  - Flavors : L40S-shared
  - Quota nominal : 48 replicas (6 GPU × 8 replicas)
  - Max par workload : 2 replicas
  - Préemption : peut être préempté par queues prioritaires

Résultats mesurés après 3 mois :

  • Utilisation GPU globale : 35% (baseline) → 72% (+106%)
  • Taux de jobs training réussis du premier coup : 62% → 94% (gang scheduling)
  • Coût par inférence : 0,12 CHF → 0,05 CHF (-58% via MIG et batching)
  • Time-to-first-GPU pour dev : 15 min → 30 sec (time-slicing élimine attente)
  • Économie mensuelle : 9'200 CHF (37% du budget initial)

Les learnings clés : gang scheduling élimine 90% des échecs training distribué, MIG sur production réduit coûts inférence de moitié versus GPU exclusifs, time-slicing transforme expérience dev (attente éliminée), quotas Kueue évitent conflits inter-équipes et permettent borrowing intelligent.

 

En résumé : 3 points clés

L'orchestration GPU nécessite composants spécialisés au-delà de Kubernetes standard

Kubernetes ne gère pas nativement les GPU comme ressources de première classe. L'architecture complète combine trois couches essentielles : Device Plugin (expose GPU au scheduler), GPU Operator (automatise cycle de vie logiciel NVIDIA), et schedulers spécialisés (KAI, Kueue, Volcano pour gang scheduling, quotas, topologie). Le scheduler standard ignore modèle GPU, VRAM, topologie réseau, générant placement sous-optimal et gaspillage. GPU Operator réduit le temps de setup de plusieurs jours (installation manuelle sur chaque nœud) à quelques heures (déploiement Helm automatisé). Les schedulers avancés apportent capacités critiques absentes du scheduler par défaut : gang scheduling élimine 90% des échecs training distribué, quotas hiérarchiques avec borrowing permettent multi-tenancy efficace, topology-aware placement réduit latence réseau de 70-80% pour workloads multi-node.

MIG et time-slicing répondent à des besoins distincts, pas interchangeables

MIG fournit isolation matérielle (VRAM, SM, cache dédiés) garantissant performances prévisibles et QoS, idéal pour production multi-tenant avec SLA stricts. Time-slicing multiplex logiciellement sans isolation mémoire, acceptant contention et variabilité performance en échange de granularité supérieure (16+ replicas vs max 7 instances MIG) et compatibilité universelle (tous GPU NVIDIA vs Ampere/Hopper uniquement). Les cas pratiques montrent séparation claire : production inférence sous SLA utilise MIG (coût réduit 50-60% vs GPU exclusif), dev/test utilise time-slicing (attente GPU éliminée, expérience dev améliorée 10×), training intensif reste GPU exclusif (performances maximales). Mixer les deux sur même node pool sans stratégie documentée génère confusion et overhead opérationnel. La décision correcte : définir node pools dédiés avec stratégie claire, forcer utilisateurs à sélectionner explicitement via nodeSelector.

Gang scheduling et quotas intelligents transforment l'efficacité cluster

Gang scheduling garantit atomicité : tous les pods d'un job distribué schedulés simultanément ou aucun, éliminant deadlocks où pods partiels consomment GPU en attendant indéfiniment les manquants. Sans gang scheduling, 20-40% des jobs training échouent en gaspillant GPU (benchmarks Uber). Kueue et Volcano implémentent gang via PodGroups avec quotas configurables par équipe et borrowing entre queues : quota nominal garanti, possibilité d'emprunter quota idle d'autres équipes selon policies configurées. Le cas pratique startup suisse démontre impact mesurable : utilization GPU +106% (35% à 72%), taux réussite jobs +52% (62% à 94%), coût inférence -58%, ROI 3 mois. L'investissement initial (1-2 semaines engineering pour déployer Kueue/Volcano, configurer quotas, documenter) se récupère en <2 mois via économies GPU et réduction friction équipes.