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
Astuce
Inscrivez-vous
Optimisation des ressources GPU et gestion des coûts
Planifiez les charges de travail en fonction des exigences du processeur graphique à l'aide d'étiquettes Well-Known
Pour les AI/ML charges de travail sensibles à différentes caractéristiques du GPU (par exemple, GPU, mémoire GPU), nous vous recommandons de spécifier les exigences en matière de GPU à l'aide d'étiquettes de planification connues
Exemple
Par exemple, en utilisant le sélecteur de nœud de nom 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
Utiliser le plugin Kubernetes Device pour exposer les GPU
Pour exposer les GPU sur les nœuds, le pilote GPU NVIDIA doit être installé sur le système d'exploitation du nœud et l'exécution du conteneur doit être configurée pour permettre au planificateur Kubernetes d'attribuer des pods aux nœuds dotés de GPU disponibles. Le processus de configuration du plug-in NVIDIA Kubernetes Device 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 NVIDIA Kubernetes Device
est préinstallé et prêt à être utilisé, ce qui permet la prise en charge du GPU dès sa sortie de l'emballage. Aucune configuration supplémentaire n'est requise pour exposer les GPU au planificateur Kubernetes. -
AMI accélérée AL2023
: cette AMI inclut le pilote GPU NVIDIA mais le plug-in https://github.com/NVIDIA/k8s-device-plugin NVIDIA Kubernetes Device 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 ClusterConfig, l'AMI appropriéeeksctlsera automatiquement sélectionnée et le plug-in NVIDIA Kubernetes Device sera installé. Pour en savoir plus, consultez la section relative à la prise en charge desGPU dans la documentation eksctl.
Si vous décidez d'utiliser les AMI accélérées EKS et l'opérateur GPU NVIDIA
Pour vérifier que le plug-in NVIDIA Device est actif et que les GPU sont correctement exposés, exécutez :
kubectl describe node | grep nvidia.com/gpu
Cette commande vérifie si la nvidia.com/gpu ressource correspond à la capacité et aux ressources allouables du nœud. Par exemple, un nœud doté d'un seul GPU doit s'affichernvidia.com/gpu: 1. Consultez le Guide de planification des GPU de Kubernetes
Utilisez de nombreux types d'instances EC2 différents
L'utilisation d'autant de types d'instances EC2 différents que possible constitue une bonne pratique importante en matière d'évolutivité sur Amazon EKS, comme indiqué dans la Plan de données Kubernetes section. Cette recommandation s'applique également aux instances dotées d'un matériel accéléré (par exemple, des GPU). Si vous créez un cluster qui utilise un seul type d'instance et que vous essayez d'augmenter le nombre de nœuds au-delà de la capacité de la région, vous risquez de recevoir une erreur de capacité insuffisante (ICE), indiquant qu'aucune instance n'est disponible. Il est important de comprendre les caractéristiques uniques de vos AI/ML charges de travail avant de les diversifier de manière arbitraire. Passez en revue les types d'instances disponibles à l'aide de l'outil
Les instances de calcul accéléré sont proposées dans différents modèles d'achat pour s'adapter aux charges de travail à court, moyen terme et stables. Pour les charges de travail à court terme, flexibles et tolérantes aux pannes, pour lesquelles vous souhaiteriez éviter de faire une réservation, examinez les instances Spot. Les blocs de capacité, On-Demand les instances et les plans d'économie vous permettent de provisionner des instances de calcul accélérées pour une durée de charge de travail à moyen et long terme. Pour augmenter les chances d'accéder à la capacité requise dans le cadre de votre option d'achat préférée, il est recommandé d'utiliser une liste variée de types d'instances et de zones de disponibilité. Sinon, si vous rencontrez des ICE pour un modèle d'achat spécifique, réessayez d'utiliser un autre modèle.
Exemple L'exemple suivant montre comment permettre à un Karpenter de NodePool provisionner des instances G et P supérieures à des générations 3 (par exemple, p3). Pour plus d'informations, consultez la section Meilleures pratiques d'évolutivité d'EKS.
- key: karpenter.k8s.aws/instance-category operator: In values: ["g", "p"] # Diversifies across G-series and P-series - key: karpenter.k8s.aws/instance-generation operator: Gt values: ["3"] # Selects instance generations greater than 3
Pour plus d'informations sur l'utilisation des instances Spot pour les GPU, consultez « Envisagez d'utiliser les instances Spot Amazon EC2 pour les GPU avec Karpenter » ci-dessous.
Envisagez d'utiliser des instances Spot Amazon EC2 pour les GPU avec Karpenter
Les instances Amazon EC2 Spot vous permettent de tirer parti de la capacité EC2 inutilisée dans le cloud AWS et sont disponibles avec une réduction allant jusqu'à 90 % par rapport aux On-Demand prix. Les instances Spot Amazon EC2 peuvent être interrompues avec un préavis de deux minutes lorsqu'EC2 a besoin de retrouver sa capacité. Pour plus d'informations, consultez Spot Instances dans le guide de l'utilisateur Amazon EC2. Amazon EC2 Spot peut constituer un excellent choix pour les charges de travail tolérantes aux pannes, sans état et flexibles (heure et type d'instance). Pour en savoir plus sur le moment d'utiliser les instances Spot, consultez la section Meilleures pratiques en matière d'instances Spot EC2. Vous pouvez également utiliser les instances Spot pour les AI/ML charges de travail si c'est Spot-friendly le cas.
Cas d’utilisation
Spot-friendly les charges de travail peuvent être des mégadonnées, des charges de travail conteneurisées, des serveurs Web sans état CI/CD, le calcul haute performance (HPC) et des charges de travail de rendu. Les instances Spot ne sont pas adaptées aux charges de travail rigides, dotées d'états, intolérantes aux pannes ou étroitement couplées entre les nœuds d'instance (par exemple, les charges de travail comportant des processus parallèles qui dépendent fortement les uns des autres pour le calcul et nécessitent une communication constante entre les nœuds, telles que les applications informatiques MPI-based hautes performances telles que la dynamique des fluides ou les bases de données distribuées avec des interdépendances complexes). Voici les cas d'utilisation spécifiques que nous recommandons (sans ordre particulier) :
-
Real-time inférence en ligne : utilisez les instances Spot pour optimiser les coûts de mise à l'échelle de vos charges de travail d'inférence en temps réel, à condition que vos charges de travail soient adaptées au spot. En d'autres termes, le temps d'inférence est inférieur à deux minutes, l'application est tolérante aux pannes et peut s'exécuter sur différents types d'instances. Garantissez une haute disponibilité grâce à la diversité des instances (par exemple, entre plusieurs types d'instances et zones de disponibilité) ou à des réservations, tout en mettant en œuvre une tolérance aux pannes au niveau des applications pour gérer les éventuelles interruptions ponctuelles.
-
Hyper-parameter réglage : utilisez les instances Spot pour exécuter des tâches de réglage exploratoires de manière opportuniste, car les interruptions peuvent être tolérées sans perte significative, en particulier pour les expériences de courte durée.
-
Augmentation des données : utilisez les instances Spot pour effectuer des tâches de prétraitement et d'augmentation des données qui peuvent être redémarrées à partir des points de contrôle en cas d'interruption, ce qui les rend idéales pour la disponibilité variable de Spot.
-
Fine-tuning modèles : utilisez des instances Spot pour effectuer des réglages précis grâce à des mécanismes de points de contrôle robustes pour revenir au dernier état enregistré, minimisant ainsi l'impact des interruptions d'instance.
-
Inférence par lots : utilisez les instances Spot pour traiter de gros lots de demandes d'inférence hors ligne en temps réel, ce qui permet de suspendre et de reprendre les tâches, ce qui permet de tirer le meilleur parti des économies de coûts réalisées par Spot et de gérer les interruptions potentielles liées aux nouvelles tentatives ou à la diversification.
-
Sous-ensembles de formation opportunistes : utilisez des instances Spot pour les charges de travail de formation marginales ou expérimentales (par exemple, des modèles plus petits avec 10 millions de paramètres), où les interruptions sont acceptables et où des optimisations d'efficacité telles que la diversification entre les types d'instances ou les régions peuvent être appliquées, mais cela n'est pas recommandé pour la formation à l'échelle de production en raison de perturbations potentielles.
Considérations
Pour utiliser les instances Spot pour accélérer les charges de travail sur Amazon EKS, il convient de prendre en compte un certain nombre de points essentiels (sans ordre particulier) :
-
Utilisez Karpenter pour gérer les instances Spot avec la consolidation avancée activée. En spécifiant Karpenter. sh/capacity-tapez « spot » dans votre Karpenter NodePool, Karpenter provisionnera les instances Spot par défaut sans aucune configuration supplémentaire. Cependant, pour activer la Spot-to-Spot consolidation avancée, qui remplace les nœuds Spot sous-utilisés par des alternatives Spot moins coûteuses, vous devez activer le SpotToSpotConsolidation feature gate en
définissant --feature-gates SpotToSpotConsolidation =true dans les arguments du contrôleur Karpenter ou via la variable d'environnement FEATURE_GATES. Karpenter utilise la stratégie d'allocation optimisée en termes de prix/capacités pour provisionner des instances EC2. En fonction des NodePool exigences et des contraintes des modules, Karpenter classe les modules non planifiables et envoie un ensemble varié de types d'instances à l'API Amazon EC2 Fleet. https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-request-type.html Vous pouvez utiliser l'outil EC2 Instance Type Explorer pour générer une liste de types d'instances qui correspondent à vos besoins de calcul spécifiques. -
Assurez-vous que les charges de travail sont sans état, tolérantes aux pannes et flexibles. Les charges de travail doivent être sans état, tolérantes aux pannes et flexibles en termes de taille. instance/GPU Cela permet une reprise fluide après les interruptions de Spot, et la flexibilité des instances vous permet de rester sur Spot plus longtemps. Activez la gestion des interruptions https://karpenter.sh/docs/concepts/disruption/#interruption
ponctuelles dans Karpenter en configurant la valeur settings.InterruptionQueue Helm avec le nom de la file d'attente AWS SQS pour détecter les événements d'interruption ponctuelle. Par exemple, lors de l'installation via Helm, utilisez --set « settings.interruptionQueue=$ {CLUSTER_NAME} ». Pour voir un exemple, consultez le guide Getting Started with Karpenter. Lorsque Karpenter détecte un événement d'interruption ponctuelle, il bloque, souille, vide et arrête automatiquement le ou les nœuds avant l'événement d'interruption afin de maximiser la période de grâce de résiliation des pods. Dans le même temps, Karpenter démarrera immédiatement un nouveau nœud afin qu'il soit prêt dès que possible. -
Évitez de trop contraindre la sélection du type d'instance. Vous devez éviter autant que possible de limiter les types d'instances. En ne limitant pas les types d'instances, vous augmentez les chances d'acquérir de la capacité Spot à grande échelle tout en réduisant la fréquence des interruptions d'instance Spot à moindre coût. Par exemple, évitez de vous limiter à des types spécifiques (par exemple, g5.xlarge). Envisagez de spécifier un ensemble varié de catégories et de générations d'instances à l'aide de clés telles que karpenter.k8s. aws/instance-category et karpenter.k8s. aws/instance-génération. Karpenter facilite la diversification de la capacité des instances ponctuelles et à la demande sur plusieurs types d'instances et zones de disponibilité (AZ). De plus, si votre AI/ML charge de travail nécessite un nombre spécifique ou limité d'accélérateurs mais qu'elle est flexible d'une région à l'autre, vous pouvez utiliser Spot Placement Score pour identifier dynamiquement la région optimale pour déployer votre charge de travail avant le lancement.
-
Élargir les NodePool exigences pour inclure un plus grand nombre de familles d'instances EC2 similaires. Chaque pool d'instances Spot se compose d'une capacité d'instance EC2 inutilisée pour un type d'instance spécifique dans une zone de disponibilité (AZ) spécifique. Lorsque Karpenter essaie de provisionner un nouveau nœud, il sélectionne un type d'instance qui correspond à ses exigences. NodePool Si aucun type d'instance compatible ne possède de capacité Spot dans aucune zone de disponibilité, le provisionnement échoue. Pour éviter ce problème, autorisez des instances de série G plus étendues (génération 4 ou supérieure) de NVIDIA, quelles que soient leur taille et leur zone de disponibilité (AZ), tout en tenant compte des besoins matériels tels que la mémoire GPU ou le Ray Tracing. Comme les instances peuvent être de différents types, vous devez vous assurer que votre charge de travail est capable de s'exécuter sur chaque type et que les performances que vous obtenez répondent à vos besoins.
-
Tirez parti de toutes les zones de disponibilité d'une région. La capacité disponible varie en fonction de la zone de disponibilité (AZ). Un type d'instance spécifique peut être indisponible dans une zone de disponibilité mais abondant dans une autre. Chaque combinaison unique d'un type d'instance et d'une zone de disponibilité constitue un pool de capacité Spot distinct. En sollicitant la capacité de toutes les zones de zone d'activité d'une région correspondant à vos NodePool besoins Karpenter, vous recherchez efficacement plus de pools à la fois. Cela permet de maximiser le nombre de pools de capacités Spot et donc d'augmenter la probabilité d'acquérir de la capacité Spot. Pour ce faire, dans votre NodePool configuration, omettez le topology.kubernetes. io/zone touche entièrement pour permettre à Karpenter de sélectionner parmi tous les AZ disponibles dans la région, ou de répertorier explicitement les AZ à l'aide de l'opérateur : In et de fournir les valeurs (par exemple, us-west-2a).
-
Envisagez d'utiliser le Spot Placement Score (SPS) pour avoir une visibilité sur les chances d'accéder avec succès à la capacité requise à l'aide d'instances Spot. Le Spot Placement Score (SPS) est un outil qui fournit un score pour vous aider à évaluer les chances de réussite d'une demande Spot. Lorsque vous utilisez SPS, vous spécifiez d'abord vos besoins de calcul pour vos instances Spot, puis Amazon EC2 renvoie les 10 principales régions ou zones de disponibilité (AZ) dans lesquelles votre demande Spot est susceptible d'aboutir. Les régions et les zones de disponibilité sont évaluées sur une échelle de 1 à 10. Un score de 10 indique que votre demande Spot a de fortes chances de succès, mais qu'elle n'est pas garantie. Un score de 1 indique que votre demande Spot a peu de chances d’aboutir. Le même score peut être renvoyé pour différentes régions ou zones de disponibilité. Pour en savoir plus, consultez les conseils pour créer un tableau de bord de suivi des scores de placement Spot sur AWS. Comme la capacité Spot fluctue en permanence, SPS vous aidera à identifier la combinaison de types d'instances, de zones de disponibilité et de régions la mieux adaptée à vos contraintes de charge de travail (flexibilité, performances, taille, etc.). Si votre AI/ML charge de travail nécessite des accélérateurs spécifiques ou un nombre limité, mais qu'elle est flexible d'une région à l'autre, vous pouvez utiliser le score de placement Spot pour identifier dynamiquement la région optimale pour déployer votre charge de travail avant le lancement. Pour vous aider à déterminer automatiquement la probabilité d'acquérir de la capacité Spot, nous vous proposons des conseils pour créer un tableau de bord de suivi SPS. Cette solution surveille les scores SPS au fil du temps à l'aide d'une configuration YAML pour des configurations diversifiées (par exemple, les exigences en matière d'instance, y compris les GPU), stocke les métriques et fournit des tableaux de bord pour comparer les configurations. CloudWatch Définissez des tableaux de bord par charge de travail afin d'évaluer les besoins en matière de vCPU, de mémoire et de GPU, en garantissant des configurations optimales pour les clusters EKS, notamment en tenant compte de l'utilisation d'autres régions AWS. Pour en savoir plus, consultez Comment fonctionne le score de placement Spot.
-
Gérez avec élégance les interruptions et les tests ponctuels. Pour un module dont la période de résiliation est supérieure à deux minutes, l'ancien nœud sera interrompu avant que ces modules ne soient reprogrammés, ce qui pourrait avoir un impact sur la disponibilité de la charge de travail. Prenez en compte le préavis d'interruption ponctuel de deux minutes lors de la conception de vos applications, implémentez le point de contrôle dans les applications de longue durée (par exemple, enregistrer la progression vers un stockage persistant comme Amazon S3) pour qu'il reprenne après des interruptions, prolongez la résiliation GracePeriodSeconds (par défaut de 30 secondes) dans les spécifications Pod pour laisser plus de temps à un arrêt progressif, et gérez les interruptions à l'aide des crochets de cycle de vie PrestOP (signaux and/or SIGTERM) dans votre application pour des activités d'arrêt progressif telles que le nettoyage, la sauvegarde de l'état et la fermeture de connexion. Pour les charges de travail en temps réel, pour lesquelles la mise à l'échelle du temps est importante et où les charges de travail mettent plus de deux minutes pour que l'application soit prête à traiter le trafic, envisagez d'optimiser les temps de démarrage des conteneurs et de chargement des modèles de machine learning en passant en revue Stockage les meilleures pratiques. Mise à l'échelle et performances des applications Pour tester un nœud de remplacement, utilisez AWS Fault Injection Service
(FIS) pour simuler des interruptions ponctuelles.
Outre ces bonnes pratiques Spot de base, tenez compte de ces facteurs lors de la gestion des charges de travail GPU sur Amazon EKS. Contrairement aux CPU-based charges de travail, les charges de travail des GPU sont particulièrement sensibles aux détails matériels tels que les capacités du GPU et la mémoire GPU disponible. Les charges de travail des GPU peuvent être limitées par les types d'instances qu'ils peuvent utiliser, avec moins d'options disponibles par rapport aux processeurs. Dans un premier temps, déterminez si votre charge de travail est flexible en matière d'instance. Si vous ne savez pas combien de types d'instances votre charge de travail peut utiliser, testez-les individuellement pour garantir la compatibilité et les fonctionnalités. Déterminez dans quelle mesure vous pouvez être flexible pour diversifier autant que possible, tout en confirmant que la diversification permet à la charge de travail de fonctionner et en comprenant tout impact sur les performances (par exemple, sur le débit ou le délai d'exécution). Dans le cadre de la diversification de vos charges de travail, tenez compte des points suivants :
-
Vérifiez la compatibilité de CUDA et du framework. Vos charges de travail GPU peuvent être optimisées pour du matériel ou des types de GPU spécifiques (par exemple, V100 en p3 contre A100 en p4), ou écrites pour des versions spécifiques de CUDA pour des bibliothèques telles que, par exemple TensorFlow, assurez-vous de vérifier la compatibilité de vos charges de travail. Cette compatibilité est cruciale pour éviter les erreurs d'exécution, les pannes, les défaillances de l'accélération du GPU (par exemple, des versions de CUDA incompatibles avec des frameworks tels que PyTorch ou TensorFlow pouvant empêcher l'exécution), ou la capacité à tirer parti de fonctionnalités matérielles telles que FP16/INT8 la précision.
-
Mémoire GPU. Assurez-vous d'évaluer les besoins en mémoire de vos modèles et de définir le profil de l'utilisation de la mémoire de votre modèle pendant l'exécution à l'aide d'outils tels que l'exportateur DCGM
et définissez la mémoire GPU minimale requise pour le type d'instance dans des labels connus tels que karpenter.k8s. aws/instance-mémoire GPU. La VRAM GPU varie selon les types d'instances (par exemple, NVIDIA T4 possède 16 Go, A10G 24 Go, V100 16 à 32 Go) et les modèles ML (par exemple, les modèles linguistiques volumineux) peuvent dépasser la mémoire disponible, provoquant des erreurs de manque de mémoire (OOM) ou des pannes. Pour les instances Spot dans EKS, cela peut limiter la diversification. Par exemple, vous ne pouvez pas inclure des types de VRAM inférieurs si votre modèle ne convient pas, ce qui peut limiter l'accès aux pools de capacité et augmenter le risque d'interruption. Notez que pour l'inférence d'un seul GPU et d'un seul nœud (par exemple, plusieurs pods planifiés sur le même nœud pour utiliser ses ressources GPU), cela peut limiter la diversification, car vous ne pouvez inclure que des types d'instances avec suffisamment de VRAM dans votre configuration Spot. -
Floating-point précision et performance. Les architectures GPU Nvidia n'ont pas toutes la même précision en virgule flottante (par exemple, FP16/INT8). Évaluez les performances des types de base (CUDA/Tensor/RT) et la précision en virgule flottante requises pour vos charges de travail. L'utilisation d'un GPU moins cher et moins performant ne signifie pas qu'il est meilleur. Pensez donc à évaluer les performances en termes de travail effectué dans un délai précis pour comprendre l'impact de la diversification.
Scénario : Diversification des charges de travail d'inférence en temps réel
Pour une charge de travail d'inférence en ligne en temps réel sur les instances Spot, vous pouvez configurer un Karpenter NodePool afin de diversifier les familles et les générations d'instances GPU compatibles. Cette approche garantit une haute disponibilité en s'appuyant sur plusieurs pools Spot, tout en maintenant les performances grâce à des contraintes liées aux capacités du GPU, à la mémoire et à l'architecture. Il permet d'utiliser des alternatives lorsque la capacité des instances est limitée, de minimiser les interruptions et d'optimiser la latence d'inférence. Cet exemple NodePool indique qu'il faut utiliser des instances des séries g et p supérieures à 3, qui disposent de plus de 20 Go de mémoire GPU.
Exemple
apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: gpu-inference-spot spec: template: metadata: labels: role: gpu-spot-worker spec: requirements: - key: karpenter.sh/capacity-type operator: In values: ["spot"] # Use Spot Instances - key: karpenter.k8s.aws/instance-category operator: In values: ["g", "p"] # Diversifies across G-series and P-series - key: karpenter.k8s.aws/instance-generation operator: Gt values: ["3"] # Selects instance generations greater than 3 - key: kubernetes.io/arch operator: In values: ["amd64"] # Specifies AMD64 architecture, compatible with NVIDIA GPUs - key: karpenter.k8s.aws/instance-gpu-memory operator: Gt values: ["20480"] # Ensures more than 20GB (20480 MiB) total GPU memory taints: - key: nvidia.com/gpu effect: NoSchedule nodeClassRef: name: gpu-inference-ec2 group: karpenter.k8s.aws kind: EC2NodeClass expireAfter: 720h limits: cpu: 100 memory: 100Gi disruption: consolidationPolicy: WhenEmptyOrUnderutilized consolidateAfter: 5m # Enables consolidation of underutilized nodes after 5 minutes
Mettre en œuvre des points de contrôle pour les tâches d'entraînement de longue durée
Le point de contrôle est une technique de tolérance aux pannes qui consiste à enregistrer périodiquement l'état d'un processus, afin de lui permettre de reprendre à partir du dernier point enregistré en cas d'interruption. Dans le domaine de l'apprentissage automatique, il est généralement associé à la formation, dans le cadre de laquelle des tâches de longue durée peuvent réduire le poids du modèle et l'état de l'optimiseur pour reprendre l'entraînement après des défaillances, telles que des problèmes matériels ou des interruptions d'instance ponctuelle.
Vous utilisez des points de contrôle pour enregistrer l'état des modèles d'apprentissage automatique (ML) pendant l'entraînement. Les points de contrôle sont des instantanés du modèle et peuvent être configurés par les fonctions de rappel de cadres ML. Vous pouvez utiliser les points de contrôle enregistrés pour redémarrer une tâche d’entraînement à partir du dernier point de contrôle enregistré. À l'aide de points de contrôle, vous enregistrez les instantanés de vos modèles en cours d'entraînement en raison d'une interruption inattendue de la tâche ou de l'instance de formation. Cela vous permet de reprendre l'entraînement du modèle à l'avenir à partir d'un point de contrôle. Outre la mise en œuvre d'un système de résilience des nœuds, nous vous recommandons de mettre en œuvre des points de contrôle pour atténuer l'impact des interruptions, notamment celles causées par des pannes matérielles ou des interruptions d'instances Amazon EC2 Spot.
Sans points de contrôle, les interruptions peuvent entraîner une perte de temps de calcul et une perte de progression, ce qui est coûteux pour les tâches de formation de longue durée. Le point de contrôle permet aux tâches de sauvegarder leur état périodiquement (par exemple, les poids du modèle et les états de l'optimiseur) et de reprendre à partir du dernier point de contrôle (dernier lot traité) après une interruption. Pour implémenter le point de contrôle, concevez votre application de manière à traiter les données par lots volumineux et à enregistrer les résultats intermédiaires dans un stockage permanent, tel qu'un compartiment Amazon S3 via le pilote CSI Mountpoint for Amazon S3 pendant que la formation progresse.
Cas d’utilisation
Le point de contrôle est particulièrement utile dans des scénarios spécifiques pour trouver un équilibre entre la tolérance aux pannes et les coûts de performance. Envisagez d'utiliser le point de contrôle dans les cas suivants :
-
La durée du travail dépasse quelques heures : pour les tâches de formation de longue durée (par exemple, plus de 1 à 2 heures pour les petits modèles ou days/weeks pour les grands modèles de base avec des milliards de paramètres), où la perte de progression due aux interruptions est coûteuse. Des travaux plus courts peuvent ne pas justifier les I/O frais généraux.
-
Pour les instances Spot ou les pannes matérielles : dans les environnements sujets à des interruptions, tels que EC2 Spot (préavis de 2 minutes) ou à des pannes matérielles (par exemple, des erreurs de mémoire GPU), le point de contrôle permet une reprise rapide, rendant Spot viable pour réaliser des économies sur les charges de travail tolérantes aux pannes.
-
Entraînement distribué à grande échelle : pour les configurations comportant hundreds/thousands des accélérateurs (par exemple, plus de 100 GPU), où le temps moyen entre les pannes diminue de façon linéaire avec l'échelle. Utilisez-le pour le model/data parallélisme afin de gérer l'accès simultané aux points de contrôle et d'éviter les redémarrages complets.
-
Large-scale modèles nécessitant des ressources élevées : dans le cadre de la formation LLM à l'échelle du pétaoctet, où les pannes sont inévitables en raison de la taille du cluster ; les approches hiérarchisées (locales rapides toutes les 5 à 30 minutes pour les transitoires, durables toutes les heures pour les pannes majeures) optimisent le temps de restauration par rapport à l'efficacité.
Utilisez des 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 ultérieure 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 pour les tâches nécessitant beaucoup de calcul, telles que la formation des modèles et la mise au point. La tarification d'EC2 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 des GPU 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 à court terme ou les réservations de On-Demand capacité (ODCR) pour une assurance de capacité à usage général.
-
Les ODCR vous permettent de réserver de la capacité d'instance EC2 (par exemple, des instances GPU telles que g5 ou p5) dans une zone de disponibilité spécifique pendant une certaine durée, garantissant ainsi la disponibilité, même en cas de forte demande. Les ODCR n'ont aucun engagement à long terme, mais vous payez le On-Demand tarif pour la capacité réservée, qu'elle soit utilisée ou inactive. Dans EKS, les ODCR sont pris en charge par des types de nœuds tels que Karpenter
et des groupes de nœuds gérés. Pour hiérarchiser les ODCR dans Karpenter, configurez le NodeClass pour utiliser le champ. capacityReservationSelectorTermsConsultez la NodePools documentation https://karpenter.sh/docs/concepts/nodeclasses/#speccapacityreservationselectortermsKarpenter. -
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 une capacité pour une période définie (généralement de 24 heures à 182 jours) à compter d'une date ultérieure, en ne payant que pour le temps réservé. Ils sont prépayés, nécessitent une planification préalable des besoins en capacité et ne prennent pas en charge la mise à l'échelle automatique, mais ils sont colocalisés dans EC2 pour un réseau à faible latence. UltraClusters Ils ne facturent que pour la période réservée. Pour en savoir plus, consultez 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 rubrique 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 On-Demand les réservations ponctuelles ou de On-Demand capacité Amazon EC2 (ODCR) pour les instances G Amazon EC2
Pour les instances Amazon EC2 G On-Demand, considérez les différentes options d'achat parmi les instances Spot Amazon EC2 et les réservations de On-Demand capacité. Les ODCR vous permettent de réserver de la capacité d'instance EC2 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, les ODCR 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 différentes fonctionnalités GPU, telles que l'inférence ou les graphiques. Lorsque vous utilisez les instances Spot Amazon EC2, il est essentiel de pouvoir choisir différents types d'instances, tailles et zones de disponibilité pour pouvoir rester sur Spot plus longtemps.
Les ODCR n'ont aucun engagement à long terme, mais vous payez le On-Demand tarif pour la capacité réservée, qu'elle soit utilisée ou inactive. Les ODCR peuvent être créés pour une utilisation immédiate ou planifiés pour une date ultérieure, ce qui offre une flexibilité dans la planification des capacités. Dans Amazon EKS, les ODCR sont pris en charge par des types de nœuds tels que Karpenter capacityReservationSelectorTerms Consultez la NodePools documentation https://karpenter.sh/docs/concepts/nodepools/
Envisagez d'autres types et tailles d'instances accélérées
Il est essentiel de sélectionner l'instance accélérée et la taille appropriées pour optimiser à la fois les performances et les coûts de vos charges de travail de machine learning sur Amazon EKS. Par exemple, les différentes familles d'instances GPU ont des performances et des fonctionnalités différentes, telles que la mémoire GPU. Pour vous aider à choisir l'option la plus rentable, consultez les instances GPU disponibles sur la page Types d'instances
Si vous utilisez une instance GPU dans un nœud EKS, le nvidia-device-plugin-daemonset pod sera placé par défaut dans l'kube-systemespace de noms. Pour savoir rapidement si vous utilisez pleinement le ou les GPU de votre instance, vous pouvez utiliser https://docs.nvidia.com/deploy/nvidia-smi/index.html
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.memorycette valeur est proche de 100 %, votre ou 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.gpuvaleur 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 %, cela signifie que vos codes utilisent pleinement la capacité de calcul du GPU. -
Le
-l 5drapeau indique de publier les métriques toutes les 5 secondes. Dans le cas d'un seul type d'instance GPU, l'indicateur de requête d'index n'est pas nécessaire.
Pour en savoir plus, consultez la section Instances GPU dans la documentation AWS.
Optimisez l'allocation des ressources GPU à l'aide Time-Slicing du MIG et de 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 GPU. Pour les charges de travail à faible volume ou complexes, le découpage temporel 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 sont provisionnés et que les pods sont planifiés sur les GPU appropriés pour la charge de travail (par exemple,)
karpenter.k8s.aws/instance-gpu-name: "a100" -
Time-Slicing: planifie les charges de travail pour partager les ressources de calcul d'un GPU au fil du temps, ce qui permet une exécution simultanée sans partitionnement physique. C'est la solution idéale pour les charges de travail dont les exigences de calcul sont variables, mais qui peuvent ne pas être isolées de la mémoire.
-
Multi-Instance GPU (MIG) : le MIG permet de partitionner un seul GPU NVIDIA en plusieurs instances isolées et est compatible avec les GPU NVIDIA Ampere (par exemple, un GPU A100), NVIDIA Hopper (par exemple, un GPU H100) et NVIDIA Blackwell (par exemple, des GPU Blackwell). 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 GPU, y compris dans des scénarios tels que la diffusion de plusieurs modèles avec différentes tailles de lots grâce au découpage temporel.
-
Allocation fractionnée du GPU : utilise la 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 Run:ai plateforme, 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 plug-in NVIDIA Device, qui expose les GPU en tant que ressources programmables et prend en charge le découpage en temps et le MIG. Pour en savoir plus, consultez les sections Time-Slicing GPU dans Kubernetes
Exemple
Par exemple, pour activer le découpage temporel à l'aide du plug-in 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 de 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 une restauration automatique
Pour les tâches de formation distribuées sur Amazon EKS qui nécessitent de fréquentes communications entre nœuds, telles que la formation de modèles multi-GPU sur plusieurs nœuds, des problèmes matériels tels que des pannes GPU ou EFA peuvent perturber les tâches de formation. Ces interruptions peuvent entraîner une perte de progression de la 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 pannes matérielles, telles que les pannes 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 réparation automatique 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 de mécanismes Kubernetes standard, 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 une 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
Readyles conditions spécifiques au matériel accéléré afin d'identifier les problèmes tels que les défaillances du GPU ou du réseau. Lorsqu'un nœud est considéré comme défectueux, Node Auto Repair le bloque 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 de la tâche. -
L'agent de contrôle de santé SageMaker HyperPod
approfondi et de surveillance de l'état surveille en permanence l'état de santé du GPU et des Trainium-based instances. 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 considéré comme défectueux, le remplacement automatique du matériel défectueux, tel que les GPU, est HyperPod déclenché. Il détecte les défaillances liées au réseau pour EFA grâce à ses bilans de santé de base par défaut et prend en charge la reprise automatique des tâches de formation interrompues, permettant ainsi 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 EFA-specific des indicateurs tels que les erreurs RDMA (Remote Direct Memory Access) et les suppressions de paquets, assurez-vous que le pilote AWS EFA est installé. En outre, nous vous recommandons de déployer l'CloudWatch Observability Add-on ou d'utiliser des outils tels que DCGM Exporter avec Prometheus et Grafana pour surveiller l'EFA, le GPU et SageMaker HyperPod, pour les métriques spécifiques liées à ses fonctionnalités.
Désactivez 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 afin
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 pods ou du rechargement des données, ce qui peut être coûteux pour les tâches d'inférence par lots de longue durée. Pour remédier à ce problème, vous pouvez définir la consolidationPolicy valeur WhenEmpty et configurer une consolidateAfter durée, par exemple 1 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 de démarrage des pods pour les charges de travail d'inférence par lots complexes et d'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 TTL SecondsAfterFinished pour automatiser les tâches Clean-Up Kubernetes
Nous vous recommandons de configurer ttlSecondsAfterFinished les tâches Kubernetes dans Amazon EKS pour supprimer automatiquement les objets de tâche terminés. Les objets de travail persistants consomment des ressources de 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 la suppression des tâches peu de temps après leur achèvement, ce qui permet de garder votre cluster en ordre. Pour plus de détails, reportez-vous à la section Nettoyage automatique des tâches
Configurer la Low-Priority préemption des tâches pour Higher-Priority Jobs/workloads
Pour les AI/ML charges de travail à priorité mixte sur Amazon EKS, vous pouvez configurer la préemption des tâches de 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, l'inférence par lots, le traitement des données), les services non batch (par exemple, les tâches en arrière-plan, les tâches cron) ou les CPU/memory-intensive travaux (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 les plus prioritaires ont besoin de ressources, garantissant ainsi une allocation efficace des ressources sur les nœuds dotés de GPU, de processeurs ou de mémoire. Nous vous recommandons d'utiliser Kubernetes PriorityClass pour attribuer des priorités et contrôler le comportement en matière PodDisruptionBudget d'expulsion.
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: low-priority value: 100 --- spec: priorityClassName: low-priority
Consultez la documentation sur les priorités et la préemption de Kubernetes pour plus d'informations.
Évolutivité et performances des applications
Personnalisez la capacité de calcul pour les charges de travail de machine learning 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 de nœuds aux caractéristiques de votre charge de travail et à vos engagements financiers. Vous trouverez ci-dessous deux approches à envisager : une mise à l'échelle juste à temps avec Karpenter
-
Just-in-time scalers de plans de données tels que Karpenter : pour les flux de travail ML dynamiques avec des demandes de calcul variables (par exemple, GPU-based inférence suivie d'un CPU-based tracé), nous vous recommandons d'utiliser des scalers de plan de données juste à temps tels que Karpenter.
-
Utilisez des groupes de nœuds statiques pour des charges de travail prévisibles : pour les 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 validés via des RI ou des ODCR.
Exemple
Voici un exemple de Karpenter diversifié NodePool g Amazon EC2 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 de formation :
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 limites et des tolérances pour empêcher la planification de charges de travail non accélérées sur des instances accélérées
La planification de charges de travail non accélérées sur des ressources GPU n'est pas efficace en termes de calcul. Nous vous recommandons d'utiliser des limites et une tolérance pour vous assurer 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 Kubernetes
Échelle basée sur les performances du modèle
Pour les charges de travail d'inférence, nous vous 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 surapprovisionner ou sous-approvisionner les ressources, ce qui a un impact sur les coûts et la latence. Pour en savoir plus, consultez la documentation https://keda.sh/
Allocation dynamique des ressources pour une gestion avancée des GPU
L'allocation dynamique des ressources (DRA)
-
Fine-grained Allocation de GPU
-
Mécanismes de partage avancés, tels que le Multi-Process service (MPS) et le Multi-Instance GPU (MIG)
-
Prise en charge des architectures matérielles de nouvelle génération, notamment NVIDIA GB200 UltraServers
L'allocation de GPU traditionnelle traite les GPU comme des ressources entières opaques, ce qui entraîne une sous-utilisation importante (souvent de 30 à 40 % dans les clusters de production). Cela se produit parce que les charges de travail bénéficient d'un accès exclusif à des GPU complets, même lorsqu'elles ne nécessitent que des ressources partielles. 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 de périphérique NVIDIA
Le plug-in de périphérique NVIDIA (à partir de la version0.12.0) prend en charge les mécanismes de partage du GPU, notamment le découpage en temps, le MPS et le MIG. Cependant, la DRA répond à des limites architecturales.
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.
ConfigMapsIl 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 via des étiquettes de nœuds, les charges de travail ne peuvent pas demander dynamiquement des configurations GPU spécifiques (taille de la mémoire et capacités de calcul) dans le cadre de la décision de planification.
-
Aucune coordination des ressources entre les 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 domaines NVLink pour des systèmes tels que NVIDIA GB200.
-
Contraintes du planificateur : le planificateur Kubernetes traite les ressources 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 complexes en matière de ressources.
-
Complexité de la configuration : la mise en place de différentes stratégies de partage nécessite un étiquetage minutieux
ConfigMapset multiple des nœuds, ce qui crée une complexité opérationnelle.
Solutions avec DRA
-
Sélection dynamique des ressources : 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
resourceclaimsmoment de la demande. Cela permet une mise en correspondance des ressources plus flexible. -
Prise en compte de la topologie : grâce à des paramètres structurés et à des sélecteurs de périphériques, DRA répond à des exigences complexes telles que la communication entre nœuds GPU et les interconnexions cohérentes en mémoire.
-
Cross-node gestion des ressources :
computeDomainspermet la coordination des ressources GPU distribuées sur plusieurs nœuds, ce qui est essentiel pour les systèmes tels que le GB200 avec canaux IMEX. -
Workload-specific configuration : chacune
ResourceClaimspécifie 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 du matériel et des caractéristiques des ressources.
Important : DRA ne remplace pas entièrement le plug-in du périphérique 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 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 de DRA varie en fonction de la famille d'instances Amazon EC2 et de l'architecture GPU, comme indiqué dans le tableau suivant.
| Famille d’instances | Type de GPU | Time-slicing | Support MIG | Support MPS | Assistance IMEX | Cas d’utilisation |
|---|---|---|---|---|---|---|
|
G5 |
NVIDIA A10G |
Oui |
Non |
Oui |
Non |
Charges de travail graphiques et d'inférence |
|
G6 |
NVIDIA L4 |
Oui |
Non |
Oui |
Non |
Inférence par IA et traitement vidéo |
|
G6e |
NVIDIA L40 |
Oui |
Non |
Oui |
Non |
Formation, inférence et graphisme |
|
P4d/P4de |
NVIDIA A100 |
Oui |
Oui |
Oui |
Non |
Large-scale formation et HPC |
|
P5 |
NVIDIA H100 |
Oui |
Oui |
Oui |
Non |
Formation sur le modèle de base |
|
P6 |
NVIDIA B200 |
Oui |
Oui |
Oui |
Non |
Modèles comportant des milliards ou des billions de paramètres, entraînement distribué et inférence |
|
P6e |
NVIDIA GB200 |
Oui |
Oui |
Oui |
Oui |
Modèles comportant des milliards ou des billions de paramètres, entraînement distribué et inférence |
Les descriptions de chaque fonctionnalité du tableau sont les suivantes :
-
Time-slicing: permet à plusieurs charges de travail de partager les ressources de calcul du GPU au fil du temps.
-
Multi-Instance GPU (MIG) : Hardware-level partitionnement qui crée des instances GPU isolées.
-
Multi-Process service (MPS) : permet l'exécution simultanée de plusieurs processus CUDA sur un seul GPU.
-
Internode Memory Exchange (IMEX) : Memory-coherent communication entre les nœuds pour le GB200. UltraServers
Ressources supplémentaires
Pour plus d'informations sur les pilotes Kubernetes DRA et NVIDIA DRA, consultez les ressources suivantes sur : GitHub
-
Allocation dynamique des ressources dans Kubernetes https://github.com/kubernetes/dynamic-resource-allocation
Configuration de l'allocation dynamique des ressources pour une gestion avancée des GPU
La rubrique suivante explique comment configurer l'allocation dynamique des ressources (DRA) pour une gestion avancée des GPU.
Conditions préalables
Avant d'implémenter DRA sur Amazon EKS, assurez-vous que votre environnement répond aux exigences suivantes.
Configuration du cluster
-
Cluster Amazon EKS exécutant une version
1.33ou une version ultérieure -
Groupes de nœuds gérés par Amazon EKS (DRA n'est actuellement pris en charge que par les groupes de nœuds gérés dotés d'AMI optimisées AL2023 et Bottlerocket pour NVIDIA, pas avec Karpenter)
-
GPU-enabled Nœuds de travail NVIDIA avec types d'instances appropriés
Composants requis
-
Version
0.17.1ou ultérieure du plug-in pour appareils NVIDIA -
Version du pilote NVIDIA DRA
25.3.0ou ultérieure
Étape 1 : créer un cluster avec un groupe de DRA-enabled nœuds à 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éploiement du plug-in de périphérique NVIDIA
Déployez le plug-in de périphérique NVIDIA pour activer la découverte de base du GPU :
-
Ajoutez le référentiel Helm du plug-in de périphérique 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 operator: Exists effect: NoSchedule EOF -
Installez le plug-in de périphérique NVIDIA :
helm install nvidia-device-plugin nvidia/nvidia-device-plugin \ --namespace nvidia-device-plugin \ --create-namespace \ --version 0.17.1 \ --values nvidia-device-plugin-values.yaml
Étape 3 : Déployer le diagramme Helm du pilote NVIDIA DRA
-
Créez un fichier de
dra-driver-values.yamlvaleurs 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érifiez l'installation de DRA
-
Vérifiez que les ressources de l'API DRA sont disponibles :
kubectl api-resources | grep resource.k8s.io/v1beta1Le résultat attendu est le suivant :
deviceclasses resource.k8s.io/v1beta1 false DeviceClass resourceclaims resource.k8s.io/v1beta1 true ResourceClaim resourceclaimtemplates resource.k8s.io/v1beta1 true ResourceClaimTemplate resourceslices resource.k8s.io/v1beta1 false ResourceSlice -
Vérifiez les classes d'appareils disponibles :
kubectl get deviceclassesVoici 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 4h39mLorsqu'une instance GPU G6 nouvellement créée rejoint votre cluster Amazon EKS avec DRA activé, les actions suivantes se produisent :
-
Le pilote NVIDIA DRA découvre automatiquement le GPU A10G et en crée deux
resourceslicessur ce nœud. -
La
gpu.nvidia.comtranche enregistre le périphérique GPU A10G physique avec ses spécifications (mémoire, capacité de calcul, etc.). -
Comme l'A10G ne prend pas en charge le partitionnement MIG, la
compute-domain.nvidia.comtranche crée un domaine de calcul unique représentant l'ensemble du contexte de calcul du GPU. -
Ils
resourceslicessont ensuite publiés sur le serveur API Kubernetes, ce qui rend les ressources GPU disponibles pour la planification.resourceclaimsLe 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 resourceslicesVoici 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 d'une allocation dynamique des ressources.
Planifiez une charge de travail GPU simple à l'aide d'une 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 continuer, assurez-vous d'avoir suiviConfiguration de l'allocation dynamique des ressources pour une gestion avancée des GPU.
-
Créez une base
ResourceClaimTemplatepour l'allocation du GPU à l'aide d'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-test1Voici un exemple de sortie :
NAME AGE single-gpu 9m16s -
Créez un Pod qui utilise le
ResourceClaimTemplateavec 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-test1Voici un exemple de sortie attendue :
NAME READY STATUS RESTARTS AGE gpu-pod 1/1 Running 0 13m -
Vérifiez le
ResourceClaimstatut :kubectl get resourceclaims -n gpu-test1Voici un exemple de sortie attendue :
NAME STATE AGE gpu-pod-gpu0-l76cg allocated,reserved 9m6s -
Consultez les journaux du pod pour voir les informations sur le GPU :
kubectl logs gpu-pod -n gpu-test1Voici un exemple de sortie attendue :
GPU 0: NVIDIA L4 (UUID: GPU-da7c24d7-c7e3-ed3b-418c-bcecc32af7c5)
Continuez à découvrir Techniques d'optimisation du GPU avec allocation dynamique des ressources des techniques d'optimisation GPU plus avancées à l'aide de DRA.
Techniques d'optimisation du GPU avec allocation dynamique des ressources
Les charges de travail GPU modernes nécessitent une gestion sophistiquée des ressources pour optimiser leur utilisation et leur rentabilité. DRA permet plusieurs techniques d'optimisation avancées qui répondent à différents cas d'utilisation et fonctionnalités matérielles :
-
Time-slicingpermet à plusieurs charges de travail de partager les ressources de calcul du GPU au fil du temps, ce qui en fait la solution idéale pour les charges de travail d'inférence avec une utilisation sporadique du GPU. Pour obtenir un exemple, consultez Optimisez les charges de travail des GPU grâce à la réduction du temps.
-
Multi-Process service (MPS) permet l'exécution simultanée de plusieurs processus CUDA sur un seul GPU avec une meilleure isolation que le découpage temporel. Pour obtenir un exemple, consultez Optimisez les charges de travail du GPU avec MPS.
-
Multi-Instance Le GPU (MIG) fournit un partitionnement au niveau matériel, créant des instances GPU isolées avec des ressources de calcul et de mémoire dédiées. Pour obtenir un exemple, consultez Optimisez les charges de travail du GPU avec le Multi-Instance GPU.
-
Internode Memory Exchange (IMEX) permet une communication cohérente en termes de mémoire entre les nœuds pour un entraînement distribué sur les systèmes NVIDIA GB200. Pour obtenir un exemple, consultez Optimisez les charges de travail du GPU avec IMEX à l'aide d'instances GB200 P6e.
Ces techniques peuvent améliorer considérablement l'utilisation des ressources. Les entreprises signalent que l'utilisation du GPU passe de 30 à 40 % avec une 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 des GPU grâce à la réduction du temps
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 avec une utilisation sporadique du GPU.
Procédez comme suit.
-
Définissez un
ResourceClaimTemplatepour 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 découpage temporel 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 -wVoici 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 (1training-pod-2)
-
État :
pending -
Signification : En attente que DRA configure le découpage temporel sur le même GPU
-
État du pod : En attente de programmation
-
L'État passera de
pendingallocated,reservedàrunning
Optimisez les charges de travail du GPU avec MPS
Multi-Process Le service (MPS) permet l'exécution simultanée de plusieurs contextes CUDA sur un seul GPU avec une meilleure isolation que le découpage temporel.
Procédez comme suit.
-
Définissez un
ResourceClaimTemplatepour 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 MPS Pods :
kubectl apply -f mps-claim-template.yaml kubectl apply -f mps-pod.yaml -
Surveillez les demandes de ressources :
kubectl get resourceclaims -n mps-gpu -wVoici un exemple de sortie :
NAME STATE AGE mps-multi-container-pod-shared-gpu-claim-2p9kx allocated,reserved 86s
Cette configuration démontre un véritable partage de GPU à l'aide de NVIDIA Multi-Process Service (MPS) via l'allocation dynamique des ressources (DRA). Contrairement au découpage temporel où les charges de travail utilisent à tour de rôle le GPU de manière séquentielle, MPS permet aux deux conteneurs de s'exécuter simultanément sur le même GPU physique. L'idée principale est que le partage DRA MPS nécessite plusieurs conteneurs au sein d'un seul pod, et non plusieurs pods séparés. Une fois déployé, le pilote DRA en alloue un ResourceClaim au Pod et configure automatiquement 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 démon MPS coordonnant l'accès au matériel sous-jacent. Vous pouvez vérifier que cela fonctionne en procédant comme suit :
-
nvidia-smiCoche, qui affichera les deux conteneurs comme des 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 à des charges de travail complémentaires de partager efficacement le matériel GPU coûteux, au lieu de le laisser sous-utilisé par un seul processus.
Conteneur 1 : conteneur d'inférence
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 : conteneur de formation
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 Multi-Instance GPU
Multi-instance Le GPU (MIG) fournit un partitionnement au niveau matériel, créant des instances GPU isolées avec des 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 NVIDIA. WITH0—REBOOT=true dans la configuration de MIG Manager est essentielle pour réussir les déploiements MIG.
Vous avez besoin du pilote NVIDIA DRA
Étape 1 : Déploiement de 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.yamlfichier :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.yamlfichier :helm install gpu-operator nvidia/gpu-operator \ --namespace gpu-operator \ --create-namespace \ --version v25.3.1 \ --values gpu-operator-values.yamlCe diagramme Helm déploie les composants suivants et plusieurs profils MIG :
-
Plug-in de périphérique (planification des ressources GPU)
-
Exportateur DCGM (métriques et surveillance du GPU)
-
Découverte des fonctionnalités des nœuds (NFD - étiquetage du matériel)
-
Découverte des fonctionnalités du GPU (GFD - GPU-specific étiquetage)
-
MIG Manager (partitionnement Multi-instance du GPU)
-
Container Toolkit (exécution du conteneur GPU)
-
Contrôleur d'opérateur (gestion du cycle de vie)
-
-
Vérifiez les pods de déploiement :
kubectl get pods -n gpu-operatorVoici 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é 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 IDNVIDIA 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'
p4deinstance. -
Exécutez la commande suivante :
nvidia-smi -LVous 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 matériel telles que configurées. Voici comment fonctionne le partitionnement :
L'opérateur 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 votre nvidia-smi -L sortie, voici ce que l'opérateur GPU a créé :
-
MIG-enabled GPU (0-3) : partitionnés matériellement
-
Processeur graphique 0 : NVIDIA A100-SXM4-80GB
-
Appareil MIG 3G.40 Go 0 — Charges de travail importantes (40 Go de mémoire, 42 SMS)
-
Appareil MIG 2 g/20 Go 1 — Charges de travail moyennes (20 Go de mémoire, 28 SMS)
-
Appareil MIG 1g.10 Go 2 : petites charges de travail (10 Go de mémoire, 14 SMS)
-
Appareil MIG 1g.10 Go 3 : petites charges de travail (10 Go de mémoire, 14 SMS)
-
-
Processeur graphique 1 : NVIDIA A100-SXM4-80GB
-
Périphérique 0 MIG 3g.40 Go — Disposition de partition identique
-
Appareil MIG 2g.20 Go 1
-
Appareil MIG 1g.10 Go 2
-
Appareil MIG 1g.10 Go 3
-
-
GPU 2 et GPU 3 : même schéma que les GPU 0 et GPU 1
-
-
GPU complets (4-7) : pas de partitionnement MIG
-
GPU 4 : NVIDIA A100-SXM4-80GB — GPU complet de 80 Go
-
GPU 5 : NVIDIA A100-SXM4-80GB — GPU complet de 80 Go
-
GPU 6 : NVIDIA A100-SXM4-80GB — GPU complet de 80 Go
-
GPU 7 : NVIDIA A100-SXM4-80GB — 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 matériellement 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ériques. mig.nvidia.com
Le pilote DRA surveille en permanence la topologie MIG et tient à jour un inventaire des instances disponibles sur tous les GPU. Lorsqu'un pod demande un profil MIG spécifique via unResourceClaimTemplate, le pilote DRA sélectionne intelligemment une instance MIG appropriée à partir de n'importe quel GPU disponible, ce qui permet une véritable mutualisation au niveau 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 les modules resourceclaimtemplates et testez pour voir comment le pilote DRA répartit les charges de travail sur les partitions MIG disponibles, permettant ainsi à plusieurs conteneurs de partager les ressources GPU avec une isolation au niveau matériel.
-
Créez
mig-claim-template.yamlpour 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-gpuVoici un exemple de sortie :
NAME AGE mig-large-template 71m mig-medium-template 71m mig-small-template 71m -
Créez
mig-pod.yamlpour 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.yamlCes pods doivent être programmés par le chauffeur DRA.
-
Vérifiez les journaux du pod du pilote DRA et vous verrez une sortie similaire à celle-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
resourceclaimspour voir l'état du Pod :kubectl get resourceclaims -n mig-gpu -wVoici 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 0sComme vous pouvez le constater, tous les pods ont été déplacés de « en attente » à « en attente »
allocated,reservedpar le pilote DRA. -
Exécutez
nvidia-smidepuis 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 d'instances GB200 P6e
L'IMEX (Internode Memory Exchange) permet une communication cohérente en termes de mémoire entre les nœuds pour un entraînement distribué sur NVIDIA GB200. UltraServers
Procédez comme suit.
-
Définissez un
ComputeDomainpour la formation multi-nœuds à l'aide d'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 à l'aide des 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: NoScheduleNote
Cela nécessite des instances P6e GB200.
-
Déployez IMEX en appliquant les modèles
ComputeDomainet :kubectl apply -f imex-claim-template.yaml kubectl apply -f imex-compute-domain.yaml kubectl apply -f imex-pod.yaml -
Vérifiez le
ComputeDomainstatut.kubectl get computedomain distributed-training-domain -
Surveillez le déploiement du démon IMEX.
kubectl get pods -n nvidia-dra-driver -l resource.nvidia.com/computeDomain -
Vérifiez les chaînes IMEX dans le Pod :
kubectl exec imex-distributed-training -- ls -la /dev/nvidia-caps-imex-channels/ -
Afficher les journaux du Pod :
kubectl logs imex-distributed-trainingVoici 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