Aller au contenu
Edouard Topin's Blog
Private AI sur VCF / Série 02/04

GPU pooling sur VCF : NVIDIA vGPU + MIG en pratique

Mutualiser les GPU est la seule manière de rendre les maths du private AI tenables. On parcourt les profils vGPU, le slicing MIG et les pièges du scheduling mixte.

Edouard Topin
13 min de lecture
Illustration éditoriale abstraite de puces GPU rayonnant en cellules de ressources partagées.

Un seul H100 coûte plus cher qu’une petite flotte de serveurs CPU. Si un seul tenant peut le toucher à la fois, ton économie de private AI s’effondre dès le jour 1. Le GPU pooling, c’est ce qui rend les maths tenables — et le pari Broadcom, c’est NVIDIA vGPU plus Multi-Instance GPU (MIG), exposés via VCF et VKS.

Dans cet article on regarde concrètement ce que fait chaque mode de pooling, quand un profil vGPU bat un slicing MIG, et les modes de défaillance qui apparaissent quand training, inference et notebooks partagent la même carte physique.

TL;DR

  • vGPU et MIG, ce n’est pas la même chose — vGPU découpe en temps, MIG partitionne le silicium en dur.
  • VCF expose le pool GPU via des pools d’hôtes vSphere et le consomme depuis les nodes VKS.
  • Le scheduling mixte (training + inference + notebooks) explose en tail latency sans politique explicite.

Profils vGPU vs slices MIG : qu’est-ce qui est réellement partagé

Les deux permettent à plusieurs tenants d’utiliser une même carte. Ils cassent différemment, et la différence n’apparaît que sous charge.

vGPU découpe la carte entière en tranches de temps. Le driver hôte installé sur ESXi présente des GPU virtuels aux machines virtuelles. La mémoire framebuffer est partitionnée statiquement par profil : choisis un profil de 20 Go sur une carte de 80 Go et tu obtiens quatre VM, chacune avec un plafond dur que personne d’autre ne franchit. Le compute, lui, n’est pas partitionné. Chaque vGPU prend son tour sur l’intégralité du tableau de SM, et la politique de scheduling vGPU décide comment ces tours sont distribués. Le mode best-effort laisse une VM active consommer toute la carte pendant que ses voisines dorment. L’equal share répartit entre les vGPU actifs du moment. Le fixed share attribue à chaque vGPU une part constante, que les autres travaillent ou non.

Tout l’arbitrage tient dans ce réglage. Best-effort maximise l’utilisation et détruit la prédictibilité. Fixed share achète de la prédictibilité et brûle de la capacité sur des tenants inactifs.

MIG partitionne le silicium. Sur les GPU data-center compatibles MIG, la carte est découpée en GPU instances qui possèdent leurs propres tranches de SM, leur portion de cache L2 et leurs propres chemins mémoire. Les profils se nomment par compute et mémoire — des motifs du type 1g.10gb, 2g.20gb, 3g.40gb jusqu’à l’instance pleine carte — et le catalogue exact dépend de la génération et de la taille mémoire, donc lis la liste des profils sur le matériel que tu as réellement acheté plutôt que sur un article de blog. Jusqu’à sept instances par GPU. Vu de CUDA, une instance ressemble à un petit GPU indépendant.

Voilà la conséquence qui compte en exploitation : sous MIG, un voisin qui sature la bande passante mémoire ne te vole pas la tienne. Sous vGPU time-sliced, si. Même en fixed share, les vGPU d’une même carte se disputent le cache L2, la bande passante mémoire et les copy engines — le scheduler découpe le temps, pas le sous-système mémoire. « On a mis du fixed share, donc les tenants sont isolés » fait partie des idées reçues les plus coûteuses qu’on puisse emporter dans une plateforme de private AI.

Le prix de MIG, c’est la rigidité. La géométrie se définit carte par carte, et la changer exige que le GPU soit vide de tout travail en cours : une re-partition est donc une opération de drain-et-reconfigure, pas un bouton qu’on tourne à chaud. Les instances ne se parlent pas via NVLink et un job ne peut pas s’étendre sur deux d’entre elles, ce qui rend MIG structurellement inadapté au training multi-GPU. Et une petite instance est vraiment petite : si le modèle plus son KV cache n’entre pas dans la mémoire de l’instance, aucune astuce de partitionnement ne te sauvera.

vGPU time-sliced MIG
Mémoire découpe dure par profil découpe dure par instance
Compute partagé dans le temps, tableau complet par tour SM physiquement partitionnés
Cache L2 et bande passante partagés sur la carte partitionnés par instance
Voisin bruyant réel, atterrit dans ton p99 largement contenu
Burst au-delà de sa part possible en best-effort jamais
Reconfiguration changement de profil au power-on de la VM drain du GPU, re-partition
Jobs multi-GPU supportés non supportés

Comment VCF expose les GPU mutualisés à VKS

Entre une carte vissée dans un hôte ESXi et un pod qui demande nvidia.com/gpu: 1, il y a une chaîne de garde. Quatre maillons, et chacun casse indépendamment.

Sur l’hôte. Le driver hôte NVIDIA vGPU s’installe en VIB sur chaque hôte ESXi porteur de cartes. Tous les hôtes GPU du cluster doivent tourner sur la même version de driver — un écart ne se plaint pas bruyamment à l’installation, il se manifeste plus tard, quand une VM refuse de démarrer là où DRS voulait la poser.

Dans vSphere. Le GPU devient un device que tu attaches à une VM Class. Cette classe est ta vraie unité d’allocation : vCPU, mémoire et un profil vGPU nommé, empaquetés ensemble. Les VM classes sont ensuite rattachées à un vSphere Namespace avec une storage policy et des quotas, et le namespace constitue ta frontière de tenancy. Si une équipe voit une VM class GPU dans son namespace, elle peut consommer ce matériel.

Dans VKS. Un node pool référence la VM class. Tout le reste est du Cluster API standard — le caractère « GPU » du pool tient entièrement dans le nom de la classe.

workers:
  machineDeployments:
    - class: node-pool
      name: gpu-inference
      replicas: 3
      variables:
        overrides:
          - name: vmClass
            value: gpu-mig-1x-20gb      # VM class portant le profil vGPU
          - name: nodePoolLabels
            value:
              - key: accelerator.local/profile
                value: mig-20gb
          - name: nodePoolTaints
            value:
              - key: accelerator.local/gpu
                value: "true"
                effect: NoSchedule

Dans le guest. Le NVIDIA GPU Operator installe le driver invité, le container toolkit, le device plugin et l’exporter DCGM. C’est le device plugin qui annonce la capacité au scheduler Kubernetes. Sous MIG, son réglage mig.strategy décide si le node annonce un compteur générique nvidia.com/gpu (stratégie single) ou des ressources par profil comme nvidia.com/mig-1g.10gb (stratégie mixed). Le mode mixed est ce qui permet au scheduler de distinguer une petite instance d’une grande. Choisis délibérément : basculer plus tard réécrit tous les manifests qui demandent un GPU.

Deux dépendances méritent plus de respect qu’elles n’en reçoivent d’habitude. D’abord le licensing : vGPU exige une entitlement servie par le NVIDIA License System, soit le service cloud, soit une appliance déléguée locale. Un node GPU qui ne l’atteint pas ne tombe pas proprement — il se dégrade. Traite cette appliance comme une dépendance de production au même niveau d’exigence que le DNS, parce qu’un node pool qui se recycle à 2 h du matin la trouvera avant toi. Ensuite la mobilité : les VM adossées à vGPU peuvent migrer, mais le framebuffer doit se déplacer avec elles, donc le temps de stun grandit avec la taille du profil. Ne laisse pas DRS brasser tes nodes GPU à sa guise ; fixe explicitement le niveau d’automatisation et considère le déplacement d’un node GPU comme un changement, pas comme un événement de fond. Si les node pools et les VM classes sont un terrain neuf pour toi, le premier cluster VKS détaille la plomberie en dessous.

Scheduler training, inference et notebooks ensemble

Pars de la contrainte qui surprend la plupart des gens venus de Kubernetes : les demandes de GPU sont entières. Un pod demande une unité de nvidia.com/gpu, ou deux. Pas de fraction, pas de bin-packing au dixième. Tout le fractionnement a eu lieu plus bas, au moment où quelqu’un a choisi un profil vGPU ou une géométrie MIG pour ce node pool. La politique de partage se décide donc à la construction du node pool, pas au scheduling — et c’est exactement pour ça qu’une plateforme d’accélérateurs demande du design, pas seulement un device plugin.

Trois formes de charge veulent des choses incompatibles :

Training — throughput, long, checkpointableInference — SLO de latence, régulier, allergique au jitterNotebooks — interactif, inactif la plupart du temps

Mets-les sur un même pool time-sliced et ton dashboard d’utilisation sera magnifique pendant que le p99 de ton inference triple discrètement. Le mécanisme est simple : un kernel de training qui tourne pendant des dizaines de millisecondes occupe la carte pour tout son tour, si bien que la granularité du time-slice vGPU devient le plancher de jitter de toutes les requêtes qui attendent derrière. La latence moyenne bouge à peine, raison pour laquelle personne ne l’attrape dans un test de charge qui ne rapporte que des moyennes. C’est la queue de distribution que les utilisateurs ressentent.

La panoplie de politiques qui fonctionne vraiment :

  • Un node pool séparé par forme de charge. C’est le premier geste et il n’est pas négociable. Inference sur instances MIG ou cartes dédiées ; training sur profils pleine carte avec NVLink intact ; notebooks sur de la capacité time-sliced en best-effort.
  • Taints et labels. Taint chaque node GPU pour que les charges CPU ne dérivent pas sur du matériel hors de prix, et label les nodes avec leur profil pour que les manifests visent une forme plutôt qu’un hostname.
  • Priorité et préemption. Une PriorityClass haute et non préemptible pour l’inference, une classe préemptible pour le training batch, la plus basse pour les notebooks. La préemption ne marche que si le job préempté sait reprendre : c’est un contrat avec l’équipe data science, pas un réglage de scheduler.
  • Quotas. Un ResourceQuota par namespace sur le compte de GPU est la seule chose qui sépare une équipe enthousiaste du pool entier.
  • Idle culling sur les notebooks. La politique au meilleur rendement de toute la plateforme. Un notebook qui tient encore une carte trois semaines après la démo est la façon la plus courante de voir disparaître la capacité private AI.
  • Gang scheduling pour les jobs multi-GPU. Kueue ou Volcano. Sans ça, deux jobs à huit GPU en attrapent cinq chacun et aucun ne démarre jamais.

Enfin, instrumente honnêtement. Le compteur « GPU utilization » affiché partout tient davantage du drapeau « occupé » que d’une mesure d’occupation : un kernel qui n’utilise qu’une fraction des SM rapporte quand même la carte comme active. Préfère les compteurs de profiling DCGM sur l’activité SM et la bande passante mémoire, et pose-les à côté de tes SLO de latence plutôt que sur un dashboard séparé — la stack Prometheus et Grafana pour VKS est le bon endroit pour les atterrir.

Charge Placement Mode de partage Contrôle clé
Inference de production pool dédié instance MIG ou carte entière priorité non préemptible, quota par tenant
Training batch pool dédié carte entière, NVLink intact classe préemptible, gang scheduling, checkpoints
Notebooks et dev pool partagé vGPU time-sliced, best-effort idle culling, priorité la plus basse, quota dur

Dimensionnement et règle du GPU de spare

Tout ce que tu sais du sizing des clusters CPU sous-estime le coût de la perte d’un node GPU.

Le domaine de panne est bien plus large. Un hôte GPU peut porter quatre ou huit cartes. Perdre un hôte ne retire pas deux pour cent du pool comme le ferait un node CPU — ça retire d’un coup une fraction visible de tout ton parc d’accélérateurs.

Il n’y a pas de soupape de débordement. La capacité CPU déborde sur d’autres clusters, ou sur des instances cloud bon marché, sans grande cérémonie. La capacité GPU non : burster signifie payer des tarifs d’accélérateurs en cloud public et, pire, déplacer les données que tu as justement construit une plateforme private AI pour garder dans ton DC.

Le remplacement est lent. Presque personne ne garde un châssis GPU de rechange sur le plancher technique, et les délais d’approvisionnement sur le matériel accélérateur sont longs et volatils depuis des années. Raisonne comme si un hôte mort restait mort pendant des semaines.

Ready ne veut pas dire en service. Quand un node de remplacement rejoint le cluster, le driver invité doit charger, le runtime s’initialiser, et des poids de modèle qui se comptent en dizaines de gigaoctets doivent être tirés puis poussés en VRAM. Le time-to-first-token après remplacement d’un node est un chiffre à mesurer sur ta propre stack, parce qu’il se compte en minutes et non en secondes, et qu’il tombe entièrement à l’intérieur de ta fenêtre d’incident.

Les drivers sont couplés en version. Un hôte reconstruit doit revenir avec la version de driver hôte que les guests attendent. Rebâtir un hôte GPU depuis une vieille image est une manière discrète de fabriquer des nodes qui paraissent sains et ne démarrent pas un seul pod accéléré.

Deux autres habitudes valent la peine d’être prises tôt. Ne planifie pas le pool porteur de SLO sur une utilisation élevée en régime permanent — une file d’accélérateurs se comporte comme n’importe quel système de files d’attente, et le temps d’attente grimpe brutalement à l’approche de la saturation. Où se situe le coude dépend entièrement de la distribution de tailles de tes jobs, donc dérive-le de tes propres métriques de queue au lieu d’adopter la cible de quelqu’un d’autre. Et rends la capacité réservée productive plutôt qu’inactive : dirige du batch préemptible dessus, vérifie que ces jobs savent réellement checkpointer et reprendre en les tuant volontairement pendant un game day, et tu obtiens une assurance qui se paye toute seule entre deux incidents.

Pour la refacturation, compte en GPU-heures par profil plutôt que par carte. Un tenant sur une petite instance MIG et un tenant qui tient une carte entière ne consomment pas la même chose, et un modèle plat à la carte subventionne silencieusement les plus gaspilleurs.

Conclusion

Le GPU pooling sur VCF tient moins au choix de l’option maligne qu’à l’alignement entre mécanisme de partage et forme de charge, puis à la défense de cet alignement par la politique de scheduling et une marge de capacité honnête.

L’isolation est matérielle ou n’est pas

Le vGPU time-sliced découpe mémoire et temps mais partage cache et bande passante. MIG partitionne le silicium. Choisis par tier, pas par plateforme.

La politique bat l’utilisation

Node pools séparés, priority classes, quotas et culling des notebooks. Un dashboard bien rempli avec un p99 cassé n’est pas un pool bien tenu.

Garde un hôte en réserve

Les hôtes GPU tombent en bloc, se remplacent lentement et démarrent lentement. Réserve au niveau châssis et laisse le batch préemptible occuper la réserve.

Suite de la série. Une fois le compute mutualisé et ordonnancé, le goulot se déplace vers la donnée. L’article suivant traite des bases vectorielles sur VCF : où vivent les embeddings, comment la latence de retrieval interagit avec le tier d’inference que tu viens de dimensionner, et ce que coûte le maintien d’un index à jour.

Reçois le prochain par email

Les nouveaux articles et séries, envoyés à leur publication. Aucun autre courrier.

Désabonnement en un clic, à tout moment.

Retour au blog
Partager

Articles similaires

  1. 14 min de lecture

    vDefend Distributed Firewall : le zero trust au niveau du workload

    Une politique de moindre privilège par vNIC, bâtie sur des groupes dynamiques et des tags plutôt que sur des IP — et la frontière honnête où l'identité fédérée s'arrête et où le pare-feu commence.

  2. 17 min de lecture

    VCF Identity Broker : où s'arrête vraiment le SSO de VCF 9.1

    VCF Identity Broker fédère la connexion aux consoles VCF, mais le périmètre documenté est plus étroit que la promesse. On cartographie ce qu'il couvre, ce qui reste local, et l'accès de secours.

  3. 16 min de lecture

    Fédérer l'identité VCF : Okta, Entra ID, et le chemin générique

    Quatre fournisseurs d'identité sont documentés nommément, chacun avec son chemin protocolaire. Le reste passe par le SAML 2.0 générique — un chemin qui fonctionne sans valoir déclaration de support.

Suivre le blog

Nouveaux articles, réflexions et mises à jour.