Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.
Calcul et mise à l'échelle automatique
Optimisation des ressources GPU et gestion des coûts
Planifiez les charges de travail en fonction des exigences en matière de GPU à l'aide d'étiquettes connues
Pour les AI/ML charges de travail sensibles aux différentes caractéristiques du GPU (par exemple, GPU, mémoire GPU), nous recommandons de spécifier les exigences du GPU à l'aide d'étiquettes de planification connues
Exemple
Par exemple, en utilisant le sélecteur de nœud de nom du GPU lors de l'utilisation de Karpenter :
apiVersion: v1 kind: Pod metadata: name: gpu-pod-example spec: containers: - name: ml-workload image: <image> resources: limits: nvidia.com/gpu: 1 # Request one NVIDIA GPU nodeSelector: karpenter.k8s.aws/instance-gpu-name: "l40s" # Run on nodes with NVIDIA L40S GPUs
Utilisez le plugin Kubernetes Device pour exposer GPUs
Pour effectuer une exposition GPUs sur des nœuds, le pilote GPU NVIDIA doit être installé sur le système d'exploitation du nœud et le runtime du conteneur doit être configuré pour permettre au planificateur Kubernetes d'attribuer des pods aux nœuds disponibles. GPUs Le processus de configuration du plug-in d'appareil NVIDIA Kubernetes dépend de l'AMI accélérée EKS que vous utilisez :
-
AMI accélérée Bottlerocket : cette AMI inclut le pilote GPU NVIDIA et le plug-in pour appareil NVIDIA Kubernetes
est préinstallé et prêt à l'emploi, permettant ainsi un support GPU prêt à l'emploi. Aucune configuration supplémentaire n'est requise pour accéder GPUs au planificateur Kubernetes. -
AL2AMI accélérée 023 : cette AMI
inclut le pilote GPU NVIDIA, mais le plug-in de périphérique NVIDIA Kubernetes n'est pas préinstallé. Vous devez installer et configurer le plug-in de l'appareil séparément, généralement via un DaemonSet. Notez que si vous utilisez eksctl pour créer votre cluster et que vous spécifiez un type d'instance GPU (par exemple, g5.xlarge
) dans votre cluster ClusterConfig, l'AMIeksctl
accélérée sera automatiquement sélectionnée et le plug-in d'appareil NVIDIA Kubernetes sera installé sur chaque instance du groupe de nœuds. Pour en savoir plus, consultez le support du GPUdans la documentation eksctl.
Pour vérifier que le plug-in de périphérique NVIDIA est actif et GPUs correctement exposé, exécutez :
kubectl describe node | grep nvidia.com/gpu
Cette commande vérifie si la nvidia.com/gpu
ressource est dans la capacité du nœud et si les ressources sont allouables. Par exemple, un nœud doté d'un processeur graphique devrait s'affichernvidia.com/gpu: 1
. Consultez le guide de planification du GPU Kubernetes
Utilisez les blocs de capacité ML pour garantir la capacité des instances P et Trainium
Les blocs de capacité pour le ML vous permettent de réserver des instances GPU très recherchées, en particulier des instances P (par exemple, p6-b200, p5, p5e, p5en, p4d, p4de) et des instances Trainium (par exemple, trn1, trn2), pour démarrer presque immédiatement ou à une date future afin de prendre en charge vos charges de travail d'apprentissage automatique (ML) de courte durée. Ces réservations sont idéales pour garantir la capacité nécessaire aux tâches de calcul intensives, telles que la formation et le réglage des modèles. EC2 La tarification de Capacity Blocks comprend des frais de réservation et des frais de système d'exploitation. Pour en savoir plus sur la tarification, consultez la section EC2 Capacity Blocks for ML pricing
Pour réserver GPUs pour les AI/ML charges de travail sur Amazon EKS afin de garantir une capacité prévisible, nous vous recommandons d'utiliser les blocs de capacité ML pour les réservations de capacité à court terme ou à la demande (ODCRs) pour une assurance de capacité à usage général.
-
ODCRs vous permettent de réserver de la capacité d' EC2 instance (par exemple, des instances GPU telles que g5 ou p5) dans une zone de disponibilité spécifique pendant une certaine durée, afin de garantir la disponibilité, même en cas de forte demande. ODCRs vous n'avez aucun engagement à long terme, mais vous payez le tarif à la demande pour la capacité réservée, qu'elle soit utilisée ou inutilisée. Dans EKS, ODCRs sont pris en charge par des types de nœuds tels que Karpenter
et des groupes de nœuds gérés. Pour établir des priorités ODCRs dans Karpenter, configurez le NodeClass pour utiliser le capacityReservationSelectorTerms
champ. Consultez la NodePools documentation de Karpenter. -
Les blocs de capacité sont un mécanisme de réservation spécialisé pour les instances GPU (par exemple, p5, p4d) ou Trainium (trn1, trn2), conçu pour les charges de travail ML à court terme telles que la formation de modèles, le réglage fin ou l'expérimentation. Vous réservez des capacités pour une période définie (généralement de 24 heures à 182 jours) à compter d'une date future, en ne payant que pour le temps réservé. Ils sont prépayés, nécessitent une planification préalable en fonction des besoins en capacité et ne prennent pas en charge la mise à l'échelle automatique, mais ils sont regroupés pour un réseau à faible latence. EC2 UltraClusters Ils facturent uniquement pour la période réservée. Pour en savoir plus, reportez-vous à la section Rechercher et acheter des blocs de capacité, ou commencez par configurer des groupes de nœuds gérés avec des blocs de capacité en suivant les instructions de la section Créer un groupe de nœuds gérés avec des blocs de capacité pour le ML.
Réservez de la capacité via l'AWS Management Console et configurez vos nœuds pour utiliser des blocs de capacité ML. Planifiez les réservations en fonction des plannings de charge de travail et testez-les dans un cluster intermédiaire. Reportez-vous à la documentation sur les blocs de capacité pour plus d'informations.
Envisagez des réservations de capacité à la demande, Amazon EC2 Spot ou à la demande (ODCRs) pour les EC2 instances G Amazon
Pour les EC2 instances Amazon G, considérez les différentes options d'achat proposées par On-Demand, Amazon EC2 Spot Instances et On-Demand Capacity Reservations. ODCRsvous permettent de réserver de la capacité d' EC2 instance dans une zone de disponibilité spécifique pendant une certaine durée, garantissant ainsi la disponibilité même en cas de forte demande. Contrairement aux blocs de capacité ML, qui ne sont disponibles que pour les instances P et Trainium, ils ODCRs peuvent être utilisés pour un plus large éventail de types d'instances, y compris les instances G, ce qui les rend adaptés aux charges de travail nécessitant des capacités GPU différentes, telles que l'inférence ou les graphiques. Lorsque vous utilisez des instances Amazon EC2 Spot, il est essentiel de pouvoir varier les types d'instances, les tailles et les zones de disponibilité pour pouvoir rester sur Spot plus longtemps.
ODCRs vous n'avez aucun engagement à long terme, mais vous payez le tarif à la demande pour la capacité réservée, qu'elle soit utilisée ou inutilisée. ODCRs peuvent être créés pour une utilisation immédiate ou planifiés pour une date future, offrant ainsi une flexibilité dans la planification des capacités. Dans Amazon EKS, ODCRs sont pris en charge par des types de nœuds tels que KarpentercapacityReservationSelectorTerms
champ. Consultez la NodePools documentation de Karpenter
Envisagez d'autres types et tailles d'instances accélérés
La sélection de l'instance accélérée et de la taille appropriées est essentielle pour optimiser à la fois les performances et les coûts de vos charges de travail ML sur Amazon EKS. Par exemple, les différentes familles d'instances de GPU ont des performances et des capacités différentes, telles que la mémoire GPU. Pour vous aider à choisir l'option la plus rentable, consultez les instances de GPU disponibles sur la EC2 page Types
Si vous utilisez une instance de GPU dans un nœud EKS, le nvidia-device-plugin-daemonset
pod figurera par défaut dans l'kube-system
espace de noms. Pour savoir rapidement si vous utilisez pleinement le ou les GPU de votre instance, vous pouvez utiliser nvidia-smi
kubectl exec nvidia-device-plugin-daemonset-xxxxx \ -n kube-system -- nvidia-smi \ --query-gpu=index,power.draw,power.limit,temperature.gpu,utilization.gpu,utilization.memory,memory.free,memory.used \ --format=csv -l 5
-
Si
utilization.memory
cette valeur est proche de 100 %, vos codes sont probablement liés à la mémoire. Cela signifie que le GPU (mémoire) est pleinement utilisé, mais cela pourrait suggérer qu'une optimisation plus poussée des performances devrait être étudiée. -
Si la
utilization.gpu
valeur est proche de 100 %, cela ne signifie pas nécessairement que le GPU est pleinement utilisé. Une meilleure métrique à examiner est le ratio depower.draw
àpower.limit
. Si ce ratio est supérieur ou égal à 100 %, vos codes utilisent pleinement la capacité de calcul du GPU. -
Le
-l 5
drapeau indique de sortir les métriques toutes les 5 secondes. Dans le cas d'un seul type d'instance de GPU, l'indicateur de requête d'index n'est pas nécessaire.
Pour en savoir plus, consultez les instances GPU dans la documentation AWS.
Optimisez l'allocation des ressources GPU grâce au découpage temporel, au MIG et à l'allocation fractionnée du GPU
Les limites de ressources statiques dans Kubernetes (par exemple, le nombre de processeurs, de mémoire, de GPU) peuvent entraîner un provisionnement excessif ou une sous-utilisation, en particulier pour les charges de travail dynamiques telles que l'inférence. AI/ML Il est important de sélectionner le bon processeur graphique. Pour les charges de travail à faible volume ou trop élevées, le découpage en tranches de temps permet à plusieurs charges de travail de partager un seul GPU en partageant ses ressources de calcul, ce qui peut améliorer l'efficacité et réduire le gaspillage. Le partage du GPU peut être réalisé grâce à différentes options :
-
Tirez parti des sélecteurs de nœuds et de l'affinité des nœuds pour influencer la planification : assurez-vous que les nœuds provisionnés et les pods sont planifiés en fonction de la GPUs charge de travail (par exemple,)
karpenter.k8s.aws/instance-gpu-name: "a100"
-
Tranchage dans le temps : planifie les charges de travail pour partager les ressources de calcul d'un GPU au fil du temps, permettant ainsi une exécution simultanée sans partitionnement physique. C'est idéal pour les charges de travail soumises à des exigences de calcul variables, mais qui peuvent ne pas isoler la mémoire.
-
GPU multi-instance (MIG) : MIG permet de partitionner un seul GPU NVIDIA en plusieurs instances isolées et est compatible avec NVIDIA Ampere (par exemple, GPU A100), NVIDIA Hopper (par exemple, GPU H100) et NVIDIA Blackwell (par exemple, Blackwell). GPUs GPUs Chaque instance MIG reçoit des ressources de calcul et de mémoire dédiées, ce qui permet le partage des ressources dans des environnements mutualisés ou des charges de travail nécessitant des garanties de ressources, ce qui vous permet d'optimiser l'utilisation des ressources du GPU, y compris des scénarios tels que le service de plusieurs modèles avec des tailles de lots différentes par le biais d'un découpage temporel.
-
Allocation fractionnée du GPU : utilise une planification logicielle pour allouer des parties du calcul ou de la mémoire d'un GPU aux charges de travail, offrant ainsi une flexibilité pour les charges de travail dynamiques. Le planificateur NVIDIA KAI
, qui fait partie de la plateforme Run:AI, permet cela en permettant aux pods de demander des ressources GPU fractionnées.
Pour activer ces fonctionnalités dans EKS, vous pouvez déployer le plugin NVIDIA Device, qui expose les ressources GPUs sous forme de ressources planifiables et prend en charge le time-slicing et le MIG. Pour en savoir plus, consultez les sections Time-Slicing GPUs dans Kubernetes
Exemple
Par exemple, pour activer le time-slicing avec le plugin NVIDIA Device :
apiVersion: v1 kind: ConfigMap metadata: name: nvidia-device-plugin-config namespace: kube-system data: config.yaml: | version: v1 sharing: timeSlicing: resources: - name: nvidia.com/gpu replicas: 4 # Allow 4 pods to share each GPU
Exemple
Par exemple, pour utiliser KAI Scheduler pour l'allocation fractionnée du GPU, déployez-le aux côtés de l'opérateur GPU NVIDIA et spécifiez les ressources GPU fractionnées dans la spécification du pod :
apiVersion: v1 kind: Pod metadata: name: fractional-gpu-pod-example annotations: gpu-fraction: "0.5" # Annotation for 50% GPU labels: runai/queue: "default" # Required queue assignment spec: containers: - name: ml-workload image: nvcr.io/nvidia/pytorch:25.04-py3 resources: limits: nvidia.com/gpu: 1 nodeSelector: nvidia.com/gpu: "true" schedulerName: kai-scheduler
Résilience des nœuds et gestion des tâches de formation
Mettre en œuvre des contrôles de santé des nœuds avec restauration automatique
Pour les tâches de formation distribuées sur Amazon EKS qui nécessitent des communications fréquentes entre nœuds, telles que la formation de modèles multi-GPU sur plusieurs nœuds, les problèmes matériels tels que les pannes du GPU ou de l'EFA peuvent perturber les tâches de formation. Ces interruptions peuvent entraîner une perte de progression en matière de formation et une augmentation des coûts, en particulier pour les AI/ML charges de travail de longue durée qui reposent sur un matériel stable.
Pour renforcer la résilience face aux défaillances matérielles, telles que les pannes de GPU dans les clusters EKS exécutant des charges de travail GPU, nous vous recommandons de tirer parti de l'agent de surveillance des nœuds EKS avec Auto Repair ou d'Amazon SageMaker HyperPod. Alors que l'agent de surveillance des nœuds EKS avec réparation automatique fournit des fonctionnalités telles que la surveillance de l'état des nœuds et la réparation automatique à l'aide des mécanismes Kubernetes standard, il SageMaker HyperPod offre une résilience ciblée et des fonctionnalités supplémentaires spécialement conçues pour la formation ML à grande échelle, telles que des bilans de santé approfondis et la reprise automatique des tâches.
-
L'agent de surveillance des nœuds EKS avec Node Auto Repair surveille en permanence l'état des nœuds en lisant les journaux et en appliquant NodeConditions des conditions standard telles que
Ready
les conditions spécifiques au matériel accéléré afin d'identifier les problèmes tels que les pannes de GPU ou de réseau. Lorsqu'un nœud est jugé insalubre, Node Auto Repair le cordon et le remplace par un nouveau nœud. La replanification des pods et le redémarrage des tâches s'appuient sur les mécanismes standard de Kubernetes et sur la politique de redémarrage des tâches. -
Les contrôles de santé SageMaker HyperPod
approfondis et l'agent de surveillance de l'état de santé surveillent en permanence l'état de santé des instances basées sur le GPU et Trainium. Il est adapté aux AI/ML charges de travail et utilise des étiquettes (par exemple node-health-status) pour gérer l'état des nœuds. Lorsqu'un nœud est jugé défectueux, HyperPod déclenche le remplacement automatique du matériel défectueux, par exemple GPUs. Il détecte les défaillances liées au réseau pour EFA par le biais de ses contrôles de santé de base par défaut et prend en charge la reprise automatique des tâches de formation interrompues, permettant ainsi aux tâches de poursuivre les tâches depuis le dernier point de contrôle, minimisant ainsi les interruptions pour les tâches de machine learning à grande échelle.
Pour l'agent de surveillance des nœuds EKS avec réparation automatique et les SageMaker HyperPod clusters utilisant EFA, afin de surveiller les métriques spécifiques à EFA, telles que les erreurs RDMA (Remote Direct Memory Access) et les pertes de paquets, assurez-vous que le pilote AWS EFA est installé. En outre, nous vous recommandons de déployer le module complémentaire CloudWatch Observability ou d'utiliser des outils tels que DCGM Exporter avec Prometheus et Grafana pour surveiller l'EFA, le GPU et, pour SageMaker HyperPod les indicateurs spécifiques liés à ses fonctionnalités.
Désactiver Karpenter Consolidation pour les charges de travail sensibles aux interruptions
Pour les charges de travail sensibles aux interruptions, telles que le traitement, les tâches de AI/ML prédiction à grande échelle ou la formation, nous recommandons d'ajuster les politiques de consolidation de Karpenter
La politique de WhenEmptyOrUnderutilized
consolidation peut mettre fin aux nœuds prématurément, ce qui entraîne des délais d'exécution plus longs. Par exemple, les interruptions peuvent retarder la reprise des tâches en raison de la replanification des modules ou du rechargement des données, ce qui peut s'avérer coûteux pour les tâches d'inférence par lots de longue durée. Pour atténuer ce problème, vous pouvez définir la valeur WhenEmpty
et consolidationPolicy
configurer une consolidateAfter
durée, telle qu'une heure, pour conserver les nœuds pendant les pics de charge de travail. Par exemple :
disruption: consolidationPolicy: WhenEmpty consolidateAfter: 60m
Cette approche améliore la latence au démarrage des modules pour les charges de travail d'inférence par lots complexes et autres tâches sensibles aux interruptions, telles que le traitement des données d'inférence en ligne en temps réel ou la formation de modèles, où le coût de l'interruption l'emporte sur les économies de coûts de calcul. Karpenter NodePool Disruption Budgets
Utiliser ttlSecondsAfter Finished pour nettoyer automatiquement les tâches Kubernetes
Nous vous recommandons de configurer ttlSecondsAfterFinished
les tâches Kubernetes dans Amazon EKS pour qu'elles suppriment automatiquement les objets de tâche terminés. Les objets de travail persistants consomment les ressources du cluster, telles que la mémoire du serveur d'API, et compliquent la surveillance en encombrant les tableaux de bord (par exemple, Grafana, Amazon). CloudWatch Par exemple, la définition d'un TTL d'une heure garantit que les tâches sont supprimées peu de temps après leur fin, ce qui permet de garder votre cluster bien rangé. Pour plus de détails, reportez-vous à la section Nettoyage automatique des tâches terminées
Configurer la préemption des tâches de faible priorité pour les tâches et les charges de travail de priorité plus élevée
Pour les charges de AI/ML travail à priorité mixte sur Amazon EKS, vous pouvez configurer la préemption des tâches à faible priorité afin de garantir que les tâches les plus prioritaires (par exemple, l'inférence en temps réel) reçoivent des ressources rapidement. Sans préemption, les charges de travail peu prioritaires telles que les processus par lots (par exemple, inférence par lots, traitement des données), les services non batch (par exemple, tâches en arrière-plan, tâches cron) ou les tâches gourmandes en CPU et en mémoire (par exemple, les services Web) peuvent retarder les pods critiques en occupant des nœuds. La préemption permet à Kubernetes d'expulser les pods de faible priorité lorsque les pods de priorité élevée ont besoin de ressources, garantissant ainsi une allocation efficace des ressources sur les nœuds dotés de ou de mémoire. GPUs CPUs Nous vous recommandons d'utiliser Kubernetes PriorityClass
pour attribuer des priorités et contrôler le comportement PodDisruptionBudget
d'expulsion.
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: low-priority value: 100 --- spec: priorityClassName: low-priority
Consultez la documentation relative à la priorité et à la préemption de Kubernetes
Mise à l'échelle et performances des applications
Adaptez la capacité de calcul aux charges de travail ML avec Karpenter ou Static Nodes
Pour garantir une capacité de calcul rentable et réactive pour les flux de travail d'apprentissage automatique (ML) sur Amazon EKS, nous vous recommandons d'adapter votre stratégie de provisionnement des nœuds aux caractéristiques de votre charge de travail et à vos engagements en matière de coûts. Vous trouverez ci-dessous deux approches à envisager : le just-in-time dimensionnement avec Karpenter
-
Just-in-time scalers de plans de données tels que Karpenter : pour les flux de travail ML dynamiques soumis à des exigences de calcul variables (par exemple, inférence basée sur le GPU suivie d'un tracé basé sur le processeur), nous recommandons d'utiliser des scalers de plans de données tels que Karpenter. just-in-time
-
Utilisez des groupes de nœuds statiques pour des charges de travail prévisibles : pour des charges de travail ML prévisibles et stables ou lors de l'utilisation d'instances réservées, les groupes de nœuds gérés par EKS peuvent contribuer à garantir que la capacité réservée est entièrement provisionnée et utilisée, maximisant ainsi les économies. Cette approche est idéale pour des types d'instances spécifiques commis via RIs ou ODCRs.
Exemple
Voici un exemple de Karpenter diversifié NodePoolg
Amazon lorsque la génération d'instances est supérieure à trois.
apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: gpu-inference spec: template: spec: nodeClassRef: group: karpenter.k8s.aws kind: EC2NodeClass name: default requirements: - key: karpenter.sh/capacity-type operator: In values: ["on-demand"] - key: karpenter.k8s.aws/instance-category operator: In values: ["g"] - key: karpenter.k8s.aws/instance-generation operator: Gt values: ["3"] - key: kubernetes.io/arch operator: In values: ["amd64"] taints: - key: nvidia.com/gpu effect: NoSchedule limits: cpu: "1000" memory: "4000Gi" nvidia.com/gpu: "10" *# Limit the total number of GPUs to 10 for the NodePool* disruption: consolidationPolicy: WhenEmpty consolidateAfter: 60m expireAfter: 720h
Exemple
Exemple d'utilisation de groupes de nœuds statiques pour une charge de travail d'entraînement :
apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: ml-cluster region: us-west-2 managedNodeGroups: - name: gpu-node-group instanceType: p4d.24xlarge minSize: 2 maxSize: 2 desiredCapacity: 2 taints: - key: nvidia.com/gpu effect: NoSchedule
Utilisez des contraintes et des tolérances pour empêcher que des charges de travail non accélérées ne soient planifiées sur des instances accélérées
La planification de charges de travail non accélérées sur les ressources GPU n'est pas efficace en termes de calcul. Nous vous recommandons d'utiliser des restrictions et des tolérances pour garantir que les pods de charges de travail non accélérées ne sont pas planifiés sur des nœuds inappropriés. Consultez la documentation de Kubernetes
Échelle basée sur les performances du modèle
Pour les charges de travail d'inférence, nous recommandons d'utiliser Kubernetes Event-Driven Autoscaling (KEDA) pour effectuer une mise à l'échelle en fonction des indicateurs de performance du modèle, tels que les demandes d'inférence ou le débit de jetons, avec des périodes de recharge appropriées. Les politiques de dimensionnement statique peuvent surprovisionner ou sous-allouer les ressources, ce qui a un impact sur les coûts et la latence. Pour en savoir plus, consultez la documentation KEDA
Allocation dynamique des ressources pour une gestion avancée du GPU
L'allocation dynamique des ressources (DRA)
-
Allocation précise du GPU
-
Mécanismes de partage avancés, tels que le service multi-processus (MPS) et le GPU multi-instance (MIG)
-
Support pour les architectures matérielles de nouvelle génération, notamment NVIDIA 00 GB2 UltraClusters
L'allocation GPU traditionnelle traite les ressources GPUs comme des entiers opaques, ce qui entraîne une sous-utilisation significative (souvent 30 à 40 % dans les clusters de production). Cela se produit parce que les charges de travail bénéficient d'un accès exclusif à l'intégralité, GPUs même lorsqu'elles ne nécessitent que des ressources fractionnaires. DRA transforme ce modèle en introduisant une allocation déclarative structurée qui fournit au planificateur Kubernetes une visibilité complète sur les caractéristiques matérielles et les exigences en matière de charge de travail. Cela permet de prendre des décisions de placement intelligentes et de partager efficacement les ressources.
Avantages de l'utilisation de DRA au lieu du plug-in d'appareil NVIDIA
Le plug-in pour appareil NVIDIA (à partir de la version0.12.0
) prend en charge les mécanismes de partage du GPU, notamment le time-slicing, le MPS et le MIG. Cependant, il existe des limites architecturales que le DRA corrige.
Limitations des plug-ins pour appareils NVIDIA
-
Configuration statique : les configurations de partage du GPU (répliques temporelles et paramètres MPS) nécessitent une préconfiguration à l'échelle du cluster.
ConfigMaps
Il est donc difficile de proposer différentes stratégies de partage pour différentes charges de travail. -
Sélection granulaire limitée : alors que le plug-in de l'appareil expose les caractéristiques du GPU par le biais d'étiquettes de nœuds, les charges de travail ne peuvent pas demander de manière dynamique des configurations GPU spécifiques (taille de mémoire et capacités de calcul) dans le cadre de la décision de planification.
-
Aucune coordination des ressources entre nœuds : impossible de gérer les ressources GPU distribuées sur plusieurs nœuds ou d'exprimer des exigences topologiques complexes, telles que les NVLink domaines pour des systèmes tels que NVIDIA GB2 00.
-
Contraintes du planificateur : le planificateur Kubernetes traite les ressources du GPU comme des entiers opaques, ce qui limite sa capacité à prendre des décisions tenant compte de la topologie ou à gérer des dépendances de ressources complexes.
-
Complexité de la configuration : la mise en place de différentes stratégies de partage nécessite un étiquetage multiple
ConfigMaps
et minutieux des nœuds, ce qui crée une complexité opérationnelle.
Solutions avec DRA
-
Sélection dynamique des ressources : le DRA permet aux charges de travail de spécifier des exigences détaillées (mémoire GPU, versions des pilotes et attributs spécifiques) au
resourceclaims
moment de la demande. Cela permet une mise en correspondance des ressources plus flexible. -
Connaissance de la topologie : grâce à des paramètres structurés et à des sélecteurs de périphériques, le DRA répond à des exigences complexes telles que la communication GPU entre nœuds et les interconnexions cohérentes en mémoire.
-
Gestion des ressources entre nœuds :
computeDomains
permet de coordonner les ressources GPU distribuées sur plusieurs nœuds, ce qui est essentiel pour les systèmes tels que GB2 00 dotés de canaux IMEX. -
Configuration spécifique à la charge de travail : chacune
ResourceClaim
définit des stratégies et des configurations de partage différentes, ce qui permet un contrôle précis par charge de travail plutôt que des paramètres à l'échelle du cluster. -
Intégration améliorée du planificateur : DRA fournit au planificateur des informations détaillées sur les appareils et permet de prendre des décisions de placement plus intelligentes en fonction de la topologie matérielle et des caractéristiques des ressources.
Important : DRA ne remplace pas entièrement le plug-in de l'appareil NVIDIA. Le pilote NVIDIA DRA fonctionne conjointement avec le plug-in de l'appareil pour fournir des fonctionnalités améliorées. Le plug-in de l'appareil continue de gérer la découverte et la gestion de base du GPU, tandis que le DRA ajoute des fonctionnalités avancées d'allocation et de planification.
Instances prises en charge par DRA et leurs fonctionnalités
La prise en charge du DRA varie en fonction de la famille d' EC2 instances Amazon et de l'architecture GPU, comme indiqué dans le tableau suivant.
Famille d’instances | Type de GPU | Trancher le temps | Support MIG | Support MPS | Support IMEX | Cas d’utilisation |
---|---|---|---|---|---|---|
G5 |
NVIDIA A10 G |
Oui |
Non |
Oui |
Non |
Charges de travail graphiques et d'inférence |
G6 |
NVIDIA L4 |
Oui |
Non |
Oui |
Non |
Inférence basée sur l'IA et traitement vidéo |
G6e |
NVIDIA L40 |
Oui |
Non |
Oui |
Non |
Entraînement, inférence et graphisme |
P4D/P4de |
NVIDIA A100 |
Oui |
Oui |
Oui |
Non |
Formation à grande échelle et HPC |
P5 |
NVIDIA H100 |
Oui |
Oui |
Oui |
Non |
Formation sur les modèles de base |
P6 |
NVIDIA B200 |
Oui |
Oui |
Oui |
Non |
Modèles comportant des milliards ou des billions de paramètres, formation distribuée et inférence |
P6e |
NVIDIA GB2 00 |
Oui |
Oui |
Oui |
Oui |
Modèles comportant des milliards ou des billions de paramètres, formation distribuée et inférence |
Les descriptions de chaque fonctionnalité du tableau sont les suivantes :
-
Tranchage dans le temps : permet à plusieurs charges de travail de partager les ressources de calcul du GPU au fil du temps.
-
GPU multi-instance (MIG) : partitionnement au niveau du matériel qui crée des instances de GPU isolées.
-
Service multiprocessus (MPS) : permet l'exécution simultanée de plusieurs processus CUDA sur un seul GPU.
-
Internode Memory Exchange (IMEX) : communication cohérente en mémoire entre les nœuds pour 00. GB2 UltraClusters
Ressources supplémentaires
Pour plus d'informations sur les pilotes Kubernetes DRA et NVIDIA DRA, consultez les ressources suivantes sur : GitHub
Configurez l'allocation dynamique des ressources pour une gestion avancée du GPU
La rubrique suivante explique comment configurer l'allocation dynamique des ressources (DRA) pour une gestion avancée du GPU.
Prérequis
Avant d'implémenter le DRA sur Amazon EKS, assurez-vous que votre environnement répond aux exigences suivantes.
Configuration de cluster
-
Cluster Amazon EKS en cours d'exécution
1.33
ou version ultérieure -
Nœuds de travail compatibles avec le GPU NVIDIA dotés des types d'instances appropriés
Composants requis
-
Version du plugin pour appareil NVIDIA
0.17.1
ou version ultérieure -
Version du pilote NVIDIA DRA
25.3.0
ou ultérieure
Étape 1 : créer un cluster avec un groupe de nœuds compatible DRA à l'aide d'eksctl
-
Créez un fichier de configuration de cluster nommé
dra-eks-cluster.yaml
:--- apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: dra-eks-cluster region: us-west-2 version: '1.33' managedNodeGroups: - name: gpu-dra-nodes amiFamily: AmazonLinux2023 instanceType: g6.12xlarge desiredCapacity: 2 minSize: 1 maxSize: 3 labels: node-type: "gpu-dra" nvidia.com/gpu.present: "true" taints: - key: nvidia.com/gpu value: "true" effect: NoSchedule
-
Créez le cluster :
eksctl create cluster -f dra-eks-cluster.yaml
Étape 2 : Déployer le plug-in pour appareil NVIDIA
Déployez le plug-in pour appareil NVIDIA pour activer la découverte de base du GPU :
-
Ajoutez le référentiel Helm du plugin pour appareils NVIDIA :
helm repo add nvidia https://nvidia.github.io/k8s-device-plugin helm repo update
-
Créez des valeurs personnalisées pour le plug-in de l'appareil :
cat <<EOF > nvidia-device-plugin-values.yaml gfd: enabled: true nfd: enabled: true tolerations: - key: [nvidia.com/gpu](http://nvidia.com/gpu) operator: Exists effect: NoSchedule EOF
-
Installez le plug-in pour appareil NVIDIA :
helm install nvidia-device-plugin nvidia/nvidia-device-plugin \ --namespace nvidia-device-plugin \ --create-namespace \ --version v0.17.1 \ --values nvidia-device-plugin-values.yaml
Étape 3 : Déploiement du pilote NVIDIA DRA Helm (graphique Helm)
-
Créez un fichier de
dra-driver-values.yaml
valeurs pour le pilote DRA :--- nvidiaDriverRoot: / gpuResourcesEnabledOverride: true resources: gpus: enabled: true computeDomains: enabled: true # Enable for GB200 IMEX support controller: tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule kubeletPlugin: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: "nvidia.com/gpu.present" operator: In values: ["true"] tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule
-
Ajoutez le référentiel NVIDIA NGC Helm :
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia helm repo update
-
Installez le pilote NVIDIA DRA :
helm install nvidia-dra-driver nvidia/nvidia-dra-driver-gpu \ --version="25.3.0-rc.2" \ --namespace nvidia-dra-driver \ --create-namespace \ --values dra-driver-values.yaml
Étape 4 : vérifier l'installation du DRA
-
Vérifiez que les ressources de l'API DRA sont disponibles :
kubectl api-resources | grep [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1)
Le résultat attendu est le suivant :
deviceclasses [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1) false DeviceClass resourceclaims [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1) true ResourceClaim resourceclaimtemplates [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1) true ResourceClaimTemplate resourceslices [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1) false ResourceSlice
-
Vérifiez les classes d'appareils disponibles :
kubectl get deviceclasses
Voici un exemple de résultat attendu :
NAME AGE compute-domain-daemon.nvidia.com 4h39m compute-domain-default-channel.nvidia.com 4h39m gpu.nvidia.com 4h39m mig.nvidia.com 4h39m
Lorsqu'une instance de GPU G6 nouvellement créée rejoint votre cluster Amazon EKS avec le DRA activé, les actions suivantes se produisent :
-
Le pilote NVIDIA DRA détecte automatiquement le GPU A10G et en crée deux
resourceslices
sur ce nœud. -
La
gpu.nvidia.com
tranche enregistre le périphérique GPU A10G physique avec ses spécifications (mémoire, capacité de calcul, etc.). -
Étant donné que l'A10G ne prend pas en charge le partitionnement MIG, la
compute-domain.nvidia.com
tranche crée un domaine de calcul unique représentant l'ensemble du contexte de calcul du GPU. -
Ils
resourceslices
sont ensuite publiés sur le serveur d'API Kubernetes, ce qui rend les ressources GPU disponibles pour la planification.resourceclaims
Le planificateur DRA peut désormais allouer intelligemment ce GPU aux pods qui demandent des ressources GPU
resourceclaimtemplates
, offrant ainsi une gestion des ressources plus flexible par rapport aux approches traditionnelles de plug-in d'appareil. Cela se fait automatiquement sans intervention manuelle. Le nœud devient simplement disponible pour les charges de travail du GPU une fois que le pilote DRA a terminé le processus de découverte et d'enregistrement des ressources.Lorsque vous exécutez la commande suivante :
kubectl get resourceslices
Voici un exemple de résultat attendu :
NAME NODE DRIVER POOL AGE ip-100-64-129-47.ec2.internal-compute-domain.nvidia.com-rwsts ip-100-64-129-47.ec2.internal compute-domain.nvidia.com ip-100-64-129-47.ec2.internal 35m ip-100-64-129-47.ec2.internal-gpu.nvidia.com-6kndg ip-100-64-129-47.ec2.internal gpu.nvidia.com ip-100-64-129-47.ec2.internal 35m
-
Passez au Planifiez une charge de travail GPU simple à l'aide de l'allocation dynamique des ressources.
Planifiez une charge de travail GPU simple à l'aide de l'allocation dynamique des ressources
Pour planifier une charge de travail GPU simple à l'aide de l'allocation dynamique des ressources (DRA), procédez comme suit. Avant de poursuivre, assurez-vous d'avoir bien suiviConfigurez l'allocation dynamique des ressources pour une gestion avancée du GPU.
-
Créez une base
ResourceClaimTemplate
pour l'allocation du GPU avec un fichier nommébasic-gpu-claim-template.yaml
:--- apiVersion: v1 kind: Namespace metadata: name: gpu-test1 --- apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: namespace: gpu-test1 name: single-gpu spec: spec: devices: requests: - name: gpu deviceClassName: gpu.nvidia.com
-
Appliquez le modèle :
kubectl apply -f basic-gpu-claim-template.yaml
-
Vérifiez le statut :
kubectl get resourceclaimtemplates -n gpu-test1
Voici un exemple de sortie :
NAME AGE single-gpu 9m16s
-
Créez un Pod qui utilise le
ResourceClaimTemplate
avec un fichier nommébasic-gpu-pod.yaml
:--- apiVersion: v1 kind: Pod metadata: namespace: gpu-test1 name: gpu-pod labels: app: pod spec: containers: - name: ctr0 image: ubuntu:22.04 command: ["bash", "-c"] args: ["nvidia-smi -L; trap 'exit 0' TERM; sleep 9999 & wait"] resources: claims: - name: gpu0 resourceClaims: - name: gpu0 resourceClaimTemplateName: single-gpu nodeSelector: NodeGroupType: gpu-dra nvidia.com/gpu.present: "true" tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: "NoSchedule"
-
Appliquez et surveillez le Pod :
kubectl apply -f basic-gpu-pod.yaml
-
Vérifiez l'état du Pod :
kubectl get pod -n gpu-test1
Voici un exemple de sortie attendue :
NAME READY STATUS RESTARTS AGE gpu-pod 1/1 Running 0 13m
-
Vérifiez le
ResourceClaim
statut :kubectl get resourceclaims -n gpu-test1
Voici un exemple de sortie attendue :
NAME STATE AGE gpu-pod-gpu0-l76cg allocated,reserved 9m6s
-
Consultez les journaux du pod pour consulter les informations du processeur graphique :
kubectl logs gpu-pod -n gpu-test1
Voici un exemple de sortie attendue :
GPU 0: NVIDIA L4 (UUID: GPU-da7c24d7-c7e3-ed3b-418c-bcecc32af7c5)
Continuez vers Techniques d'optimisation du GPU avec allocation dynamique des ressources pour découvrir des techniques d'optimisation du GPU plus avancées à l'aide de la DRA.
Techniques d'optimisation du GPU avec allocation dynamique des ressources
Les charges de travail des GPU modernes nécessitent une gestion sophistiquée des ressources pour optimiser l'utilisation et la rentabilité. Le DRA permet plusieurs techniques d'optimisation avancées qui répondent à différents cas d'utilisation et à différentes capacités matérielles :
-
Le découpage dans le temps permet à plusieurs charges de travail de partager les ressources de calcul du GPU au fil du temps, ce qui le rend idéal pour les charges de travail d'inférence associées à une utilisation sporadique du GPU. Pour obtenir un exemple, consultez Optimisez les charges de travail du GPU grâce au découpage en tranches de temps.
-
Le service multiprocessus (MPS) permet l'exécution simultanée de plusieurs processus CUDA sur un seul GPU avec une meilleure isolation que le découpage en tranches temporelles. Pour obtenir un exemple, consultez Optimisez les charges de travail du GPU avec MPS.
-
Le GPU multi-instance (MIG) assure le partitionnement au niveau du matériel, en créant des instances de GPU isolées dotées de ressources de calcul et de mémoire dédiées. Pour obtenir un exemple, consultez Optimisez les charges de travail du GPU avec le GPU multi-instance.
-
L'échange de mémoire entre nœuds (IMEX) permet une communication cohérente en mémoire entre les nœuds pour un entraînement distribué sur les systèmes NVIDIA 00. GB2 Pour obtenir un exemple, consultez Optimisez les charges de travail du GPU avec IMEX à l'aide de GB2 00 instances P6e.
Ces techniques peuvent améliorer considérablement l'utilisation des ressources. Organisations signalent que l'utilisation du GPU augmente de 30 à 40 % avec l'allocation traditionnelle à 80 à 90 % avec des stratégies de partage optimisées. Le choix de la technique dépend des caractéristiques de la charge de travail, des exigences d'isolation et des capacités matérielles.
Optimisez les charges de travail du GPU grâce au découpage en tranches de temps
Le time-slicing permet à plusieurs charges de travail de partager les ressources de calcul du GPU en les planifiant pour qu'elles s'exécutent de manière séquentielle sur le même GPU physique. Il est idéal pour les charges de travail d'inférence associées à une utilisation sporadique du GPU.
Procédez comme suit.
-
Définissez un
ResourceClaimTemplate
pour le découpage temporel avec un fichier nommé :timeslicing-claim-template.yaml
--- apiVersion: v1 kind: Namespace metadata: name: timeslicing-gpu --- apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: name: timeslicing-gpu-template namespace: timeslicing-gpu spec: spec: devices: requests: - name: shared-gpu deviceClassName: gpu.nvidia.com config: - requests: ["shared-gpu"] opaque: driver: gpu.nvidia.com parameters: apiVersion: resource.nvidia.com/v1beta1 kind: GpuConfig sharing: strategy: TimeSlicing
-
Définissez un pod en utilisant le time-slicing avec un fichier nommé :
timeslicing-pod.yaml
--- # Pod 1 - Inference workload apiVersion: v1 kind: Pod metadata: name: inference-pod-1 namespace: timeslicing-gpu labels: app: gpu-inference spec: restartPolicy: Never containers: - name: inference-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "-c"] args: - | import torch import time import os print(f"=== POD 1 STARTING ===") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Current GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB") # Simulate inference workload for i in range(20): x = torch.randn(1000, 1000).cuda() y = torch.mm(x, x.t()) print(f"Pod 1 - Iteration {i+1} completed at {time.strftime('%H:%M:%S')}") time.sleep(60) else: print("No GPU available!") time.sleep(5) resources: claims: - name: shared-gpu-claim resourceClaims: - name: shared-gpu-claim resourceClaimTemplateName: timeslicing-gpu-template nodeSelector: NodeGroupType: "gpu-dra" nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule --- # Pod 2 - Training workload apiVersion: v1 kind: Pod metadata: name: training-pod-2 namespace: timeslicing-gpu labels: app: gpu-training spec: restartPolicy: Never containers: - name: training-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "-c"] args: - | import torch import time import os print(f"=== POD 2 STARTING ===") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Current GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB") # Simulate training workload with heavier compute for i in range(15): x = torch.randn(2000, 2000).cuda() y = torch.mm(x, x.t()) loss = torch.sum(y) print(f"Pod 2 - Training step {i+1}, Loss: {loss.item():.2f} at {time.strftime('%H:%M:%S')}") time.sleep(5) else: print("No GPU available!") time.sleep(60) resources: claims: - name: shared-gpu-claim-2 resourceClaims: - name: shared-gpu-claim-2 resourceClaimTemplateName: timeslicing-gpu-template nodeSelector: NodeGroupType: "gpu-dra" nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule
-
Appliquez le modèle et le pod :
kubectl apply -f timeslicing-claim-template.yaml kubectl apply -f timeslicing-pod.yaml
-
Surveillez les demandes de ressources :
kubectl get resourceclaims -n timeslicing-gpu -w
Voici un exemple de sortie :
NAME STATE AGE inference-pod-1-shared-gpu-claim-9p97x allocated,reserved 21s training-pod-2-shared-gpu-claim-2-qghnb pending 21s inference-pod-1-shared-gpu-claim-9p97x pending 105s training-pod-2-shared-gpu-claim-2-qghnb pending 105s inference-pod-1-shared-gpu-claim-9p97x pending 105s training-pod-2-shared-gpu-claim-2-qghnb allocated,reserved 105s inference-pod-1-shared-gpu-claim-9p97x pending 105s
Premier pod (inference-pod-1
)
-
État :
allocated,reserved
-
Signification : DRA a trouvé un GPU disponible et l'a réservé pour ce Pod
-
État du pod : démarre immédiatement
Deuxième module (training-pod-2
)
-
État :
pending
-
Signification : attendre que DRA configure le time-slicing sur le même GPU
-
État du pod : En attente de planification
-
L'État va passer de
pending
allocated,reserved
àrunning
Optimisez les charges de travail du GPU avec MPS
Le service multiprocessus (MPS) permet l'exécution simultanée de plusieurs contextes CUDA sur un seul GPU avec une meilleure isolation que le découpage en tranches temporelles.
Procédez comme suit.
-
Définissez un
ResourceClaimTemplate
pour MPS avec un fichier nommémps-claim-template.yaml
:--- apiVersion: v1 kind: Namespace metadata: name: mps-gpu --- apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: name: mps-gpu-template namespace: mps-gpu spec: spec: devices: requests: - name: shared-gpu deviceClassName: gpu.nvidia.com config: - requests: ["shared-gpu"] opaque: driver: gpu.nvidia.com parameters: apiVersion: resource.nvidia.com/v1beta1 kind: GpuConfig sharing: strategy: MPS
-
Définissez un Pod à l'aide de MPS avec un fichier nommé
mps-pod.yaml
:--- # Single Pod with Multiple Containers sharing GPU via MPS apiVersion: v1 kind: Pod metadata: name: mps-multi-container-pod namespace: mps-gpu labels: app: mps-demo spec: restartPolicy: Never containers: # Container 1 - Inference workload - name: inference-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "-c"] args: - | import torch import torch.nn as nn import time import os print(f"=== INFERENCE CONTAINER STARTING ===") print(f"Process ID: {os.getpid()}") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Current GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB") # Create inference model model = nn.Sequential( nn.Linear(1000, 500), nn.ReLU(), nn.Linear(500, 100) ).cuda() # Run inference for i in range(1, 999999): with torch.no_grad(): x = torch.randn(128, 1000).cuda() output = model(x) result = torch.sum(output) print(f"Inference Container PID {os.getpid()}: Batch {i}, Result: {result.item():.2f} at {time.strftime('%H:%M:%S')}") time.sleep(2) else: print("No GPU available!") time.sleep(60) resources: claims: - name: shared-gpu-claim request: shared-gpu # Container 2 - Training workload - name: training-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "-c"] args: - | import torch import torch.nn as nn import time import os print(f"=== TRAINING CONTAINER STARTING ===") print(f"Process ID: {os.getpid()}") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Current GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB") # Create training model model = nn.Sequential( nn.Linear(2000, 1000), nn.ReLU(), nn.Linear(1000, 500), nn.ReLU(), nn.Linear(500, 10) ).cuda() criterion = nn.MSELoss() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # Run training for epoch in range(1, 999999): x = torch.randn(64, 2000).cuda() target = torch.randn(64, 10).cuda() optimizer.zero_grad() output = model(x) loss = criterion(output, target) loss.backward() optimizer.step() print(f"Training Container PID {os.getpid()}: Epoch {epoch}, Loss: {loss.item():.4f} at {time.strftime('%H:%M:%S')}") time.sleep(3) else: print("No GPU available!") time.sleep(60) resources: claims: - name: shared-gpu-claim request: shared-gpu resourceClaims: - name: shared-gpu-claim resourceClaimTemplateName: mps-gpu-template nodeSelector: NodeGroupType: "gpu-dra" nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule
-
Appliquez le modèle et créez plusieurs pods MPS :
kubectl apply -f mps-claim-template.yaml kubectl apply -f mps-pod.yaml
-
Surveillez les demandes de ressources :
kubectl get resourceclaims -n mps-gpu -w
Voici un exemple de sortie :
NAME STATE AGE mps-multi-container-pod-shared-gpu-claim-2p9kx allocated,reserved 86s
Cette configuration illustre un véritable partage de GPU à l'aide du service multiprocessus NVIDIA (MPS) via l'allocation dynamique des ressources (DRA). Contrairement au time-slicing où les charges de travail utilisent à tour de rôle le GPU de manière séquentielle, le MPS permet aux deux conteneurs de s'exécuter simultanément sur le même GPU physique. L'essentiel est que le partage DRA MPS nécessite plusieurs conteneurs au sein d'un même pod, et non plusieurs pods distincts. Une fois déployé, le pilote DRA en alloue un ResourceClaim
au Pod et configure automatiquement le MPS pour permettre aux conteneurs d'inférence et d'entraînement de s'exécuter simultanément.
Chaque conteneur dispose de son propre espace mémoire GPU isolé et de ses propres ressources de calcul, le daemon MPS coordonnant l'accès au matériel sous-jacent. Vous pouvez vérifier que cela fonctionne en procédant comme suit :
-
Vérification
nvidia-smi
, qui affichera les deux conteneurs sous forme de processus M+C (MPS + Compute
) partageant le même périphérique GPU. -
Surveillance des journaux des deux conteneurs, qui afficheront des horodatages entrelacés prouvant une exécution simultanée.
Cette approche maximise l'utilisation du GPU en permettant aux charges de travail complémentaires de partager efficacement le matériel GPU coûteux, plutôt que de le laisser sous-utilisé par un seul processus.
Récipient 1 : inference-container
root@mps-multi-container-pod:/workspace# nvidia-smi
Wed Jul 16 21:09:30 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 570.158.01 Driver Version: 570.158.01 CUDA Version: 12.9 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA L4 On | 00000000:35:00.0 Off | 0 |
| N/A 48C P0 28W / 72W | 597MiB / 23034MiB | 0% E. Process |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| 0 N/A N/A 1 M+C python 246MiB |
+-----------------------------------------------------------------------------------------+
Conteneur 2 : training-container
root@mps-multi-container-pod:/workspace# nvidia-smi
Wed Jul 16 21:16:00 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 570.158.01 Driver Version: 570.158.01 CUDA Version: 12.9 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA L4 On | 00000000:35:00.0 Off | 0 |
| N/A 51C P0 28W / 72W | 597MiB / 23034MiB | 0% E. Process |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| 0 N/A N/A 1 M+C python 314MiB |
+-----------------------------------------------------------------------------------------+
Optimisez les charges de travail du GPU avec le GPU multi-instance
Le GPU multi-instance (MIG) assure le partitionnement au niveau du matériel, en créant des instances de GPU isolées dotées de ressources de calcul et de mémoire dédiées.
L'utilisation du partitionnement MIG dynamique avec différents profils nécessite l'opérateur GPU NVIDIAWITH0—REBOOT=true
dans la configuration de MIG Manager est essentielle à la réussite des déploiements MIG.
Vous avez besoin du pilote NVIDIA DRA
Étape 1 : Déployer l'opérateur GPU NVIDIA
-
Ajoutez le référentiel NVIDIA GPU Operator :
helm repo add nvidia https://nvidia.github.io/gpu-operator helm repo update
-
Créez un
gpu-operator-values.yaml
fichier :driver: enabled: false mig: strategy: mixed migManager: enabled: true env: - name: WITH_REBOOT value: "true" config: create: true name: custom-mig-parted-configs default: "all-disabled" data: config.yaml: |- version: v1 mig-configs: all-disabled: - devices: all mig-enabled: false # P4D profiles (A100 40GB) p4d-half-balanced: - devices: [0, 1, 2, 3] mig-enabled: true mig-devices: "1g.5gb": 2 "2g.10gb": 1 "3g.20gb": 1 - devices: [4, 5, 6, 7] mig-enabled: false # P4DE profiles (A100 80GB) p4de-half-balanced: - devices: [0, 1, 2, 3] mig-enabled: true mig-devices: "1g.10gb": 2 "2g.20gb": 1 "3g.40gb": 1 - devices: [4, 5, 6, 7] mig-enabled: false devicePlugin: enabled: true config: name: "" create: false default: "" toolkit: enabled: true nfd: enabled: true gfd: enabled: true dcgmExporter: enabled: true serviceMonitor: enabled: true interval: 15s honorLabels: false additionalLabels: release: kube-prometheus-stack nodeStatusExporter: enabled: false operator: defaultRuntime: containerd runtimeClass: nvidia resources: limits: cpu: 500m memory: 350Mi requests: cpu: 200m memory: 100Mi daemonsets: tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: "NoSchedule" nodeSelector: accelerator: nvidia priorityClassName: system-node-critical
-
Installez GPU Operator à l'aide du
gpu-operator-values.yaml
fichier :helm install gpu-operator nvidia/gpu-operator \ --namespace gpu-operator \ --create-namespace \ --version v25.3.1 \ --values gpu-operator-values.yaml
Ce graphique Helm déploie les composants suivants et plusieurs profils MIG :
-
Plug-in de périphérique (planification des ressources GPU)
-
DCGM Exporter (métriques et surveillance du GPU)
-
Node Feature Discovery (NFD - étiquetage du matériel)
-
Découverte des fonctionnalités du GPU (GFD - étiquetage spécifique au GPU)
-
MIG Manager (partitionnement GPU multi-instances)
-
Container Toolkit (environnement d'exécution du conteneur GPU)
-
Operator Controller (gestion du cycle de vie)
-
-
Vérifiez les pods de déploiement :
kubectl get pods -n gpu-operator
Voici un exemple de sortie :
NAME READY STATUS RESTARTS AGE gpu-feature-discovery-27rdq 1/1 Running 0 3h31m gpu-operator-555774698d-48brn 1/1 Running 0 4h8m nvidia-container-toolkit-daemonset-sxmh9 1/1 Running 1 (3h32m ago) 4h1m nvidia-cuda-validator-qb77g 0/1 Completed 0 3h31m nvidia-dcgm-exporter-cvzd7 1/1 Running 0 3h31m nvidia-device-plugin-daemonset-5ljm5 1/1 Running 0 3h31m nvidia-gpu-operator-node-feature-discovery-gc-67f66fc557-q5wkt 1/1 Running 0 4h8m nvidia-gpu-operator-node-feature-discovery-master-5d8ffddcsl6s6 1/1 Running 0 4h8m nvidia-gpu-operator-node-feature-discovery-worker-6t4w7 1/1 Running 1 (3h32m ago) 4h1m nvidia-gpu-operator-node-feature-discovery-worker-9w7g8 1/1 Running 0 4h8m nvidia-gpu-operator-node-feature-discovery-worker-k5fgs 1/1 Running 0 4h8m nvidia-mig-manager-zvf54 1/1 Running 1 (3h32m ago) 3h35m
-
Créez un cluster Amazon EKS avec un groupe de nœuds gérés par P4de pour tester les exemples MIG :
apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: dra-eks-cluster region: us-east-1 version: '1.33' managedNodeGroups: # P4DE MIG Node Group with Capacity Block Reservation - name: p4de-mig-nodes amiFamily: AmazonLinux2023 instanceType: p4de.24xlarge # Capacity settings desiredCapacity: 0 minSize: 0 maxSize: 1 # Use specific subnet in us-east-1b for capacity reservation subnets: - us-east-1b # AL2023 NodeConfig for RAID0 local storage only nodeadmConfig: apiVersion: node.eks.aws/v1alpha1 kind: NodeConfig spec: instance: localStorage: strategy: RAID0 # Node labels for MIG configuration labels: nvidia.com/gpu.present: "true" nvidia.com/gpu.product: "A100-SXM4-80GB" nvidia.com/mig.config: "p4de-half-balanced" node-type: "p4de" vpc.amazonaws.com/efa.present: "true" accelerator: "nvidia" # Node taints taints: - key: nvidia.com/gpu value: "true" effect: NoSchedule # EFA support efaEnabled: true # Placement group for high-performance networking placementGroup: groupName: p4de-placement-group strategy: cluster # Capacity Block Reservation (CBR) # Ensure CBR ID matches the subnet AZ with the Nodegroup subnet spot: false capacityReservation: capacityReservationTarget: capacityReservationId: "cr-abcdefghij" # Replace with your capacity reservation ID
NVIDIA GPU Operator utilise l'étiquette ajoutée aux nœuds
nvidia.com/mig.config: "p4de-half-balanced"
et partitionne le GPU avec le profil donné. -
Connectez-vous à l'
p4de
instance. -
Exécutez la commande suivante :
nvidia-smi -L
Vous devriez voir l'exemple de sortie suivant :
[root@ip-100-64-173-145 bin]# nvidia-smi -L GPU 0: NVIDIA A100-SXM4-80GB (UUID: GPU-ab52e33c-be48-38f2-119e-b62b9935925a) MIG 3g.40gb Device 0: (UUID: MIG-da972af8-a20a-5f51-849f-bc0439f7970e) MIG 2g.20gb Device 1: (UUID: MIG-7f9768b7-11a6-5de9-a8aa-e9c424400da4) MIG 1g.10gb Device 2: (UUID: MIG-498adad6-6cf7-53af-9d1a-10cfd1fa53b2) MIG 1g.10gb Device 3: (UUID: MIG-3f55ef65-1991-571a-ac50-0dbf50d80c5a) GPU 1: NVIDIA A100-SXM4-80GB (UUID: GPU-0eabeccc-7498-c282-0ac7-d3c09f6af0c8) MIG 3g.40gb Device 0: (UUID: MIG-80543849-ea3b-595b-b162-847568fe6e0e) MIG 2g.20gb Device 1: (UUID: MIG-3af1958f-fac4-59f1-8477-9f8d08c55029) MIG 1g.10gb Device 2: (UUID: MIG-401088d2-716f-527b-a970-b1fc7a4ac6b2) MIG 1g.10gb Device 3: (UUID: MIG-8c56c75e-5141-501c-8f43-8cf22f422569) GPU 2: NVIDIA A100-SXM4-80GB (UUID: GPU-1c7a1289-243f-7872-a35c-1d2d8af22dd0) MIG 3g.40gb Device 0: (UUID: MIG-e9b44486-09fc-591a-b904-0d378caf2276) MIG 2g.20gb Device 1: (UUID: MIG-ded93941-9f64-56a3-a9b1-a129c6edf6e4) MIG 1g.10gb Device 2: (UUID: MIG-6c317d83-a078-5c25-9fa3-c8308b379aa1) MIG 1g.10gb Device 3: (UUID: MIG-2b070d39-d4e9-5b11-bda6-e903372e3d08) GPU 3: NVIDIA A100-SXM4-80GB (UUID: GPU-9a6250e2-5c59-10b7-2da8-b61d8a937233) MIG 3g.40gb Device 0: (UUID: MIG-20e3cd87-7a57-5f1b-82e7-97b14ab1a5aa) MIG 2g.20gb Device 1: (UUID: MIG-04430354-1575-5b42-95f4-bda6901f1ace) MIG 1g.10gb Device 2: (UUID: MIG-d62ec8b6-e097-5e99-a60c-abf8eb906f91) MIG 1g.10gb Device 3: (UUID: MIG-fce20069-2baa-5dd4-988a-cead08348ada) GPU 4: NVIDIA A100-SXM4-80GB (UUID: GPU-5d09daf0-c2eb-75fd-3919-7ad8fafa5f86) GPU 5: NVIDIA A100-SXM4-80GB (UUID: GPU-99194e04-ab2a-b519-4793-81cb2e8e9179) GPU 6: NVIDIA A100-SXM4-80GB (UUID: GPU-c1a1910f-465a-e16f-5af1-c6aafe499cd6) GPU 7: NVIDIA A100-SXM4-80GB (UUID: GPU-c2cfafbc-fd6e-2679-e955-2a9e09377f78)
NVIDIA GPU Operator a correctement appliqué le profil p4de-half-balanced
MIG à votre instance P4DE, créant ainsi des partitions GPU au niveau du matériel telles que configurées. Voici comment fonctionne le partitionnement :
L'opérateur du GPU a appliqué cette configuration à partir de votre profil MIG intégré :
p4de-half-balanced:
- devices: [0, 1, 2, 3] # First 4 GPUs: MIG enabled
mig-enabled: true
mig-devices:
"1g.10gb": 2 # 2x small instances (10GB each)
"2g.20gb": 1 # 1x medium instance (20GB)
"3g.40gb": 1 # 1x large instance (40GB)
- devices: [4, 5, 6, 7] # Last 4 GPUs: Full GPUs
mig-enabled: false
À partir de vos nvidia-smi -L
résultats, voici ce que l'opérateur du GPU a créé :
-
compatible MiG GPUs (0-3) : partitionné du matériel
-
GPU 0 : NVIDIA A100- SXM4 -80 Go
-
Appareil MIG 3g.40 Go 0 — Charges de travail importantes (40 Go de mémoire, 42) SMs
-
Appareil 1 MIG 2 g/20 Go — Charges de travail moyennes (20 Go de mémoire, 28) SMs
-
Appareil MIG 1 g.10 Go 2 — Petites charges de travail (10 Go de mémoire, 14) SMs
-
Appareil MIG 1 g.10 Go 3 — Petites charges de travail (10 Go de mémoire, 14) SMs
-
-
GPU 1 : NVIDIA A100- -80 GO SXM4
-
Appareil MIG 3g.40gb 0 — Disposition de partition identique
-
Appareil MIG 2g.20gb 1
-
Appareil MIG 1g.10gb 2
-
Appareil MIG 1g.10gb 3
-
-
GPU 2 et GPU 3 : même schéma que le GPU 0 et le GPU 1
-
-
Complet GPUs (4-7) : pas de partitionnement MIG
-
GPU 4 : NVIDIA A100- SXM4 -80 Go — GPU complet de 80 Go
-
GPU 5 : NVIDIA A100- SXM4 -80 Go — GPU complet de 80 Go
-
GPU 6 : NVIDIA A100- SXM4 -80 Go — GPU complet de 80 Go
-
GPU 7 : NVIDIA A100- SXM4 -80 Go — GPU complet de 80 Go
-
Une fois que l'opérateur GPU NVIDIA a créé les partitions MIG, le pilote NVIDIA DRA détecte automatiquement ces instances isolées du matériel et les rend disponibles pour une allocation dynamique des ressources dans Kubernetes. Le pilote DRA découvre chaque instance MIG avec son profil spécifique (1g.10 Go, 2g.20 Go, 3g.40 Go) et les expose en tant que ressources planifiables via la classe de périphérique. mig.nvidia.com
Le pilote DRA surveille en permanence la topologie MIG et tient à jour un inventaire des instances disponibles dans l'ensemble. GPUs Lorsqu'un Pod demande un profil MIG spécifique via unResourceClaimTemplate
, le pilote DRA sélectionne intelligemment une instance MIG appropriée parmi n'importe quel GPU disponible, permettant ainsi une véritable mutualisation au niveau du matériel. Cette allocation dynamique permet à plusieurs charges de travail isolées de s'exécuter simultanément sur le même GPU physique tout en maintenant des limites de ressources strictes et des garanties de performances.
Étape 2 : Tester l'allocation des ressources MIG
Passons maintenant à quelques exemples pour montrer comment DRA alloue dynamiquement des instances MIG à différentes charges de travail. Déployez resourceclaimtemplates
et testez les pods pour voir comment le pilote DRA répartit les charges de travail entre les partitions MIG disponibles, permettant ainsi à plusieurs conteneurs de partager les ressources du GPU avec une isolation au niveau du matériel.
-
Créez
mig-claim-template.yaml
pour contenir le MIGresourceclaimtemplates
:apiVersion: v1 kind: Namespace metadata: name: mig-gpu --- # Template for 3g.40gb MIG instance (Large training) apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: name: mig-large-template namespace: mig-gpu spec: spec: devices: requests: - name: mig-large deviceClassName: mig.nvidia.com selectors: - cel: expression: | device.attributes['gpu.nvidia.com'].profile == '3g.40gb' --- # Template for 2g.20gb MIG instance (Medium training) apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: name: mig-medium-template namespace: mig-gpu spec: spec: devices: requests: - name: mig-medium deviceClassName: mig.nvidia.com selectors: - cel: expression: | device.attributes['gpu.nvidia.com'].profile == '2g.20gb' --- # Template for 1g.10gb MIG instance (Small inference) apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: name: mig-small-template namespace: mig-gpu spec: spec: devices: requests: - name: mig-small deviceClassName: mig.nvidia.com selectors: - cel: expression: | device.attributes['gpu.nvidia.com'].profile == '1g.10gb'
-
Appliquez les trois modèles :
kubectl apply -f mig-claim-template.yaml
-
Exécutez la commande suivante :
kubectl get resourceclaimtemplates -n mig-gpu
Voici un exemple de sortie :
NAME AGE mig-large-template 71m mig-medium-template 71m mig-small-template 71m
-
Créez
mig-pod.yaml
pour planifier plusieurs tâches afin d'en tirer partiresourceclaimtemplates
:--- # ConfigMap containing Python scripts for MIG pods apiVersion: v1 kind: ConfigMap metadata: name: mig-scripts-configmap namespace: mig-gpu data: large-training-script.py: | import torch import torch.nn as nn import torch.optim as optim import time import os print(f"=== LARGE TRAINING POD (3g.40gb) ===") print(f"Process ID: {os.getpid()}") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Using GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1e9:.1f} GB") # Large model for 3g.40gb instance model = nn.Sequential( nn.Linear(2048, 1024), nn.ReLU(), nn.Linear(1024, 512), nn.ReLU(), nn.Linear(512, 256), nn.ReLU(), nn.Linear(256, 10) ).cuda() optimizer = optim.Adam(model.parameters()) criterion = nn.CrossEntropyLoss() print(f"Model parameters: {sum(p.numel() for p in model.parameters())}") # Training loop for epoch in range(100): # Large batch for 3g.40gb x = torch.randn(256, 2048).cuda() y = torch.randint(0, 10, (256,)).cuda() optimizer.zero_grad() output = model(x) loss = criterion(output, y) loss.backward() optimizer.step() if epoch % 10 == 0: print(f"Large Training - Epoch {epoch}, Loss: {loss.item():.4f}, GPU Memory: {torch.cuda.memory_allocated()/1e9:.2f}GB") time.sleep(3) print("Large training completed on 3g.40gb MIG instance") medium-training-script.py: | import torch import torch.nn as nn import torch.optim as optim import time import os print(f"=== MEDIUM TRAINING POD (2g.20gb) ===") print(f"Process ID: {os.getpid()}") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Using GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1e9:.1f} GB") # Medium model for 2g.20gb instance model = nn.Sequential( nn.Linear(1024, 512), nn.ReLU(), nn.Linear(512, 256), nn.ReLU(), nn.Linear(256, 10) ).cuda() optimizer = optim.Adam(model.parameters()) criterion = nn.CrossEntropyLoss() print(f"Model parameters: {sum(p.numel() for p in model.parameters())}") # Training loop for epoch in range(100): # Medium batch for 2g.20gb x = torch.randn(128, 1024).cuda() y = torch.randint(0, 10, (128,)).cuda() optimizer.zero_grad() output = model(x) loss = criterion(output, y) loss.backward() optimizer.step() if epoch % 10 == 0: print(f"Medium Training - Epoch {epoch}, Loss: {loss.item():.4f}, GPU Memory: {torch.cuda.memory_allocated()/1e9:.2f}GB") time.sleep(4) print("Medium training completed on 2g.20gb MIG instance") small-inference-script.py: | import torch import torch.nn as nn import time import os print(f"=== SMALL INFERENCE POD (1g.10gb) ===") print(f"Process ID: {os.getpid()}") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Using GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1e9:.1f} GB") # Small model for 1g.10gb instance model = nn.Sequential( nn.Linear(512, 256), nn.ReLU(), nn.Linear(256, 10) ).cuda() print(f"Model parameters: {sum(p.numel() for p in model.parameters())}") # Inference loop for i in range(200): with torch.no_grad(): # Small batch for 1g.10gb x = torch.randn(32, 512).cuda() output = model(x) prediction = torch.argmax(output, dim=1) if i % 20 == 0: print(f"Small Inference - Batch {i}, Predictions: {prediction[:5].tolist()}, GPU Memory: {torch.cuda.memory_allocated()/1e9:.2f}GB") time.sleep(2) print("Small inference completed on 1g.10gb MIG instance") --- # Pod 1: Large training workload (3g.40gb) apiVersion: v1 kind: Pod metadata: name: mig-large-training-pod namespace: mig-gpu labels: app: mig-large-training workload-type: training spec: restartPolicy: Never containers: - name: large-training-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "/scripts/large-training-script.py"] volumeMounts: - name: script-volume mountPath: /scripts readOnly: true resources: claims: - name: mig-large-claim resourceClaims: - name: mig-large-claim resourceClaimTemplateName: mig-large-template nodeSelector: node.kubernetes.io/instance-type: p4de.24xlarge nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule volumes: - name: script-volume configMap: name: mig-scripts-configmap defaultMode: 0755 --- # Pod 2: Medium training workload (2g.20gb) - can run on SAME GPU as Pod 1 apiVersion: v1 kind: Pod metadata: name: mig-medium-training-pod namespace: mig-gpu labels: app: mig-medium-training workload-type: training spec: restartPolicy: Never containers: - name: medium-training-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "/scripts/medium-training-script.py"] volumeMounts: - name: script-volume mountPath: /scripts readOnly: true resources: claims: - name: mig-medium-claim resourceClaims: - name: mig-medium-claim resourceClaimTemplateName: mig-medium-template nodeSelector: node.kubernetes.io/instance-type: p4de.24xlarge nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule volumes: - name: script-volume configMap: name: mig-scripts-configmap defaultMode: 0755 --- # Pod 3: Small inference workload (1g.10gb) - can run on SAME GPU as Pod 1 & 2 apiVersion: v1 kind: Pod metadata: name: mig-small-inference-pod namespace: mig-gpu labels: app: mig-small-inference workload-type: inference spec: restartPolicy: Never containers: - name: small-inference-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "/scripts/small-inference-script.py"] volumeMounts: - name: script-volume mountPath: /scripts readOnly: true resources: claims: - name: mig-small-claim resourceClaims: - name: mig-small-claim resourceClaimTemplateName: mig-small-template nodeSelector: node.kubernetes.io/instance-type: p4de.24xlarge nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule volumes: - name: script-volume configMap: name: mig-scripts-configmap defaultMode: 0755
-
Appliquez cette spécification, qui devrait déployer trois pods :
kubctl apply -f mig-pod.yaml
Ces pods doivent être programmés par le pilote DRA.
-
Consultez les journaux du pilote DRA Pod et vous verrez un résultat similaire à celui-ci :
I0717 21:50:22.925811 1 driver.go:87] NodePrepareResource is called: number of claims: 1 I0717 21:50:22.932499 1 driver.go:129] Returning newly prepared devices for claim '933e9c72-6fd6-49c5-933c-a896407dc6d1': [&Device{RequestNames:[mig-large],PoolName:ip-100-64-173-145.ec2.internal,DeviceName:gpu-0-mig-9-4-4,CDIDeviceIDs:[k8s.gpu.nvidia.com/device=**gpu-0-mig-9-4-4**],}] I0717 21:50:23.186472 1 driver.go:87] NodePrepareResource is called: number of claims: 1 I0717 21:50:23.191226 1 driver.go:129] Returning newly prepared devices for claim '61e5ddd2-8c2e-4c19-93ae-d317fecb44a4': [&Device{RequestNames:[mig-medium],PoolName:ip-100-64-173-145.ec2.internal,DeviceName:gpu-2-mig-14-0-2,CDIDeviceIDs:[k8s.gpu.nvidia.com/device=**gpu-2-mig-14-0-2**],}] I0717 21:50:23.450024 1 driver.go:87] NodePrepareResource is called: number of claims: 1 I0717 21:50:23.455991 1 driver.go:129] Returning newly prepared devices for claim '1eda9b2c-2ea6-401e-96d0-90e9b3c111b5': [&Device{RequestNames:[mig-small],PoolName:ip-100-64-173-145.ec2.internal,DeviceName:gpu-1-mig-19-2-1,CDIDeviceIDs:[k8s.gpu.nvidia.com/device=**gpu-1-mig-19-2-1**],}]
-
Vérifiez le
resourceclaims
pour connaître l'état du Pod :kubectl get resourceclaims -n mig-gpu -w
Voici un exemple de sortie :
NAME STATE AGE mig-large-training-pod-mig-large-claim-6dpn8 pending 0s mig-large-training-pod-mig-large-claim-6dpn8 pending 0s mig-large-training-pod-mig-large-claim-6dpn8 allocated,reserved 0s mig-medium-training-pod-mig-medium-claim-bk596 pending 0s mig-medium-training-pod-mig-medium-claim-bk596 pending 0s mig-medium-training-pod-mig-medium-claim-bk596 allocated,reserved 0s mig-small-inference-pod-mig-small-claim-d2t58 pending 0s mig-small-inference-pod-mig-small-claim-d2t58 pending 0s mig-small-inference-pod-mig-small-claim-d2t58 allocated,reserved 0s
Comme vous pouvez le constater, tous les pods sont passés de « en attente » à «
allocated,reserved
par le pilote DRA ». -
Exécutez
nvidia-smi
depuis le nœud. Vous remarquerez que trois processeurs Python sont en cours d'exécution :root@ip-100-64-173-145 bin]# nvidia-smi +-----------------------------------------------------------------------------------------+ | NVIDIA-SMI 570.158.01 Driver Version: 570.158.01 CUDA Version: 12.8 | |-----------------------------------------+------------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+========================+======================| | 0 NVIDIA A100-SXM4-80GB On | 00000000:10:1C.0 Off | On | | N/A 63C P0 127W / 400W | 569MiB / 81920MiB | N/A Default | | | | Enabled | +-----------------------------------------+------------------------+----------------------+ | 1 NVIDIA A100-SXM4-80GB On | 00000000:10:1D.0 Off | On | | N/A 56C P0 121W / 400W | 374MiB / 81920MiB | N/A Default | | | | Enabled | +-----------------------------------------+------------------------+----------------------+ | 2 NVIDIA A100-SXM4-80GB On | 00000000:20:1C.0 Off | On | | N/A 63C P0 128W / 400W | 467MiB / 81920MiB | N/A Default | | | | Enabled | +-----------------------------------------+------------------------+----------------------+ | 3 NVIDIA A100-SXM4-80GB On | 00000000:20:1D.0 Off | On | | N/A 57C P0 118W / 400W | 249MiB / 81920MiB | N/A Default | | | | Enabled | +-----------------------------------------+------------------------+----------------------+ | 4 NVIDIA A100-SXM4-80GB On | 00000000:90:1C.0 Off | 0 | | N/A 51C P0 77W / 400W | 0MiB / 81920MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ | 5 NVIDIA A100-SXM4-80GB On | 00000000:90:1D.0 Off | 0 | | N/A 46C P0 69W / 400W | 0MiB / 81920MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ | 6 NVIDIA A100-SXM4-80GB On | 00000000:A0:1C.0 Off | 0 | | N/A 52C P0 74W / 400W | 0MiB / 81920MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ | 7 NVIDIA A100-SXM4-80GB On | 00000000:A0:1D.0 Off | 0 | | N/A 47C P0 72W / 400W | 0MiB / 81920MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ +-----------------------------------------------------------------------------------------+ | MIG devices: | +------------------+----------------------------------+-----------+-----------------------+ | GPU GI CI MIG | Memory-Usage | Vol| Shared | | ID ID Dev | BAR1-Usage | SM Unc| CE ENC DEC OFA JPG | | | | ECC| | |==================+==================================+===========+=======================| | 0 2 0 0 | 428MiB / 40192MiB | 42 0 | 3 0 2 0 0 | | | 2MiB / 32767MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 0 3 0 1 | 71MiB / 19968MiB | 28 0 | 2 0 1 0 0 | | | 0MiB / 16383MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 0 9 0 2 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 0 10 0 3 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 1 1 0 0 | 107MiB / 40192MiB | 42 0 | 3 0 2 0 0 | | | 0MiB / 32767MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 1 5 0 1 | 71MiB / 19968MiB | 28 0 | 2 0 1 0 0 | | | 0MiB / 16383MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 1 13 0 2 | 161MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 2MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 1 14 0 3 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 2 1 0 0 | 107MiB / 40192MiB | 42 0 | 3 0 2 0 0 | | | 0MiB / 32767MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 2 5 0 1 | 289MiB / 19968MiB | 28 0 | 2 0 1 0 0 | | | 2MiB / 16383MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 2 13 0 2 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 2 14 0 3 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 3 1 0 0 | 107MiB / 40192MiB | 42 0 | 3 0 2 0 0 | | | 0MiB / 32767MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 3 5 0 1 | 71MiB / 19968MiB | 28 0 | 2 0 1 0 0 | | | 0MiB / 16383MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 3 13 0 2 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 3 14 0 3 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ +-----------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=========================================================================================| **| 0 2 0 64080 C python 312MiB | | 1 13 0 64085 C python 118MiB | | 2 5 0 64073 C python 210MiB |** +-----------------------------------------------------------------------------------------+
Optimisez les charges de travail du GPU avec IMEX à l'aide de GB2 00 instances P6e
L'IMEX (Internode Memory Exchange) permet une communication cohérente en mémoire entre les nœuds pour un entraînement distribué sur NVIDIA 00. GB2 UltraClusters
Procédez comme suit.
-
Définissez un
ComputeDomain
pour l'entraînement multi-nœuds avec un fichier nomméimex-compute-domain.yaml
:apiVersion: resource.nvidia.com/v1beta1 kind: ComputeDomain metadata: name: distributed-training-domain namespace: default spec: numNodes: 2 channel: resourceClaimTemplate: name: imex-channel-template
-
Définissez un Pod en utilisant les canaux IMEX avec un fichier nommé
imex-pod.yaml
:apiVersion: v1 kind: Pod metadata: name: imex-distributed-training namespace: default labels: app: imex-training spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: nvidia.com/gpu.clique operator: Exists containers: - name: distributed-training image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["bash", "-c"] args: - | echo "=== IMEX Channel Verification ===" ls -la /dev/nvidia-caps-imex-channels/ echo "" echo "=== GPU Information ===" nvidia-smi echo "" echo "=== NCCL Test (if available) ===" python -c " import torch import torch.distributed as dist import os print(f'CUDA available: {torch.cuda.is_available()}') print(f'CUDA device count: {torch.cuda.device_count()}') if torch.cuda.is_available(): for i in range(torch.cuda.device_count()): print(f'GPU {i}: {torch.cuda.get_device_name(i)}') # Check for IMEX environment variables imex_vars = [k for k in os.environ.keys() if 'IMEX' in k or 'NVLINK' in k] if imex_vars: print('IMEX Environment Variables:') for var in imex_vars: print(f' {var}={os.environ[var]}') print('IMEX channel verification completed') " # Keep container running for inspection sleep 3600 resources: claims: - name: imex-channel-0 - name: imex-channel-1 resourceClaims: - name: imex-channel-0 resourceClaimTemplateName: imex-channel-template - name: imex-channel-1 resourceClaimTemplateName: imex-channel-template tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule
Note
Cela nécessite des instances P6e GB2 00.
-
Déployez IMEX en appliquant les modèles
ComputeDomain
et :kubectl apply -f imex-claim-template.yaml kubectl apply -f imex-compute-domain.yaml kubectl apply -f imex-pod.yaml
-
Vérifiez le
ComputeDomain
statut.kubectl get computedomain distributed-training-domain
-
Surveillez le déploiement du daemon IMEX.
kubectl get pods -n nvidia-dra-driver -l [resource.nvidia.com/computeDomain](http://resource.nvidia.com/computeDomain)
-
Vérifiez les canaux IMEX dans le Pod :
kubectl exec imex-distributed-training -- ls -la /dev/nvidia-caps-imex-channels/
-
Consultez les journaux du Pod :
kubectl logs imex-distributed-training
Voici un exemple de résultat attendu :
=== IMEX Channel Verification === total 0 drwxr-xr-x. 2 root root 80 Jul 8 10:45 . drwxr-xr-x. 6 root root 380 Jul 8 10:45 .. crw-rw-rw-. 1 root root 241, 0 Jul 8 10:45 channel0 crw-rw-rw-. 1 root root 241, 1 Jul 8 10:45 channel1
Pour plus d'informations, consultez l'exemple NVIDIA