Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.
Calcul et mise à l'échelle automatique
Optimisation des ressources GPU et gestion des coûts
Planifiez les charges de travail en fonction des exigences en matière de GPU à l'aide d'étiquettes connues
Pour les AI/ML charges de travail sensibles aux différentes caractéristiques du GPU (par exemple, GPU, mémoire GPU), nous recommandons de spécifier les exigences du GPU à l'aide d'étiquettes de planification connues
Exemple
Par exemple, en utilisant le sélecteur de nœud de nom du GPU lors de l'utilisation de Karpenter :
apiVersion: v1 kind: Pod metadata: name: gpu-pod-example spec: containers: - name: ml-workload image: <image> resources: limits: nvidia.com/gpu: 1 # Request one NVIDIA GPU nodeSelector: karpenter.k8s.aws/instance-gpu-name: "l40s" # Run on nodes with NVIDIA L40S GPUs
Utilisez le plugin Kubernetes Device pour exposer GPUs
Pour effectuer une exposition GPUs sur des nœuds, le pilote GPU NVIDIA doit être installé sur le système d'exploitation du nœud et le runtime du conteneur doit être configuré pour permettre au planificateur Kubernetes d'attribuer des pods aux nœuds disponibles. GPUs Le processus de configuration du plug-in d'appareil NVIDIA Kubernetes dépend de l'AMI accélérée EKS que vous utilisez :
-
AMI accélérée Bottlerocket : cette AMI inclut le pilote GPU NVIDIA et le plug-in pour appareil NVIDIA Kubernetes
est préinstallé et prêt à l'emploi, permettant ainsi un support GPU prêt à l'emploi. Aucune configuration supplémentaire n'est requise pour accéder GPUs au planificateur Kubernetes. -
AL2AMI accélérée 023 : cette AMI
inclut le pilote GPU NVIDIA, mais le plug-in de périphérique NVIDIA Kubernetes n'est pas préinstallé. Vous devez installer et configurer le plug-in de l'appareil séparément, généralement via un DaemonSet. Notez que si vous utilisez eksctl pour créer votre cluster et que vous spécifiez un type d'instance GPU (par exemple, g5.xlarge) dans votre ClusterConfig cluster, ileksctlsélectionnera automatiquement l'AMI appropriée et installera le plug-in de périphérique NVIDIA Kubernetes. Pour en savoir plus, consultez le support du GPUdans la documentation eksctl.
Si vous décidez d'utiliser l'opérateur EKS Accelerated AMIs et NVIDIA GPU
Pour vérifier que le plug-in de périphérique NVIDIA est actif et GPUs correctement exposé, exécutez :
kubectl describe node | grep nvidia.com/gpu
Cette commande vérifie si la nvidia.com/gpu ressource est dans la capacité du nœud et si les ressources sont allouables. Par exemple, un nœud doté d'un processeur graphique devrait s'affichernvidia.com/gpu: 1. Consultez le guide de planification du GPU Kubernetes
Utilisez de nombreux types d' EC2 instances
L'utilisation d'autant de types d' EC2 instances différents que possible est 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, GPUs). Si vous créez un cluster qui n'utilise qu'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 ICE (insuffisance de capacité), 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 procéder à une diversification arbitraire. Passez en revue les types d'instances disponibles à l'aide de l'outil EC2 Instance Type Explorer
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 en régime permanent. Pour les charges de travail flexibles et tolérantes aux pannes à court terme, pour lesquelles vous souhaiteriez éviter de faire une réservation, optez pour les instances Spot. Les blocs de capacité, les instances à la demande et les plans d'économie vous permettent de fournir 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 un modèle ICEs d'achat spécifique, réessayez en utilisant un autre modèle.
Exemple L'exemple suivant montre comment permettre à un Karpenter de NodePool provisionner des instances G et P supérieures aux générations 3 (par exemple, p3). Pour plus d'informations, consultez la section Bonnes 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 en savoir plus sur l'utilisation des instances Spot pour GPUs, consultez « Envisagez d'utiliser des instances Amazon EC2 Spot pour GPUs Karpenter » ci-dessous.
Envisagez d'utiliser des instances Amazon EC2 Spot pour GPUs Karpenter
Les instances Amazon EC2 Spot vous permettent de tirer parti de la EC2 capacité inutilisée dans le cloud AWS et sont disponibles avec une réduction allant jusqu'à 90 % par rapport aux prix à la demande. Les instances Amazon EC2 Spot peuvent être interrompues moyennant un préavis de deux minutes lorsqu'il est EC2 nécessaire de rétablir leur capacité. Pour plus d'informations, consultez la section Instances Spot dans le guide de EC2 l'utilisateur Amazon. Amazon EC2 Spot peut être un excellent choix pour les charges de travail tolérantes aux pannes, apatrides et flexibles (durée et type d'instance). Pour en savoir plus sur les circonstances dans lesquelles utiliser les instances Spot, consultez les meilleures pratiques en matière d'instances EC2 Spot. Vous pouvez également utiliser des instances Spot pour les AI/ML charges de travail si elles sont compatibles avec Spot.
Cas d’utilisation
Les charges de travail optimisées peuvent être le Big Data, les charges de travail conteneurisées, le CI/CD, les serveurs Web sans état, le calcul haute performance (HPC) et les charges de travail de rendu. Les instances Spot ne sont pas adaptées aux charges de travail rigides, dynamiques, 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 dont les calculs dépendent fortement les uns des autres et nécessitent une communication constante entre les nœuds, telles que les applications informatiques à hautes performances basées sur le protocole MPI, telles que la dynamique des fluides ou les bases de données distribuées présentant des interdépendances complexes). Voici les cas d'utilisation spécifiques que nous recommandons (sans ordre particulier) :
-
Inférence en ligne en temps réel : utilisez les instances Spot pour une mise à l'échelle optimisée en termes de coûts pour vos charges de travail d'inférence en temps réel, à condition que vos charges de travail soient adaptées à la localisation. En d'autres termes, le temps d'inférence est inférieur à deux minutes, l'application tolère les 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 de l'application pour gérer les interruptions ponctuelles potentielles.
-
Réglage des hyperparamètres : 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 redémarrer à partir des points de contrôle en cas d'interruption, ce qui les rend idéales pour la disponibilité variable de Spot.
-
Modèles de réglage précis : utilisez des instances Spot pour effectuer des réglages précis grâce à des mécanismes de point de contrôle robustes permettant de 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 de non-real-time manière à ce que les tâches puissent être interrompues et reprises, en optimisant les économies réalisées par Spot et en gérant les interruptions potentielles par le biais de nouvelles tentatives ou de la diversification.
-
Sous-ensembles de formation opportunistes : utilisez des instances ponctuelles pour des 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, bien que cela ne soit pas recommandé pour la formation à l'échelle de la production en raison de perturbations potentielles.
Considérations
Pour utiliser des instances Spot pour des charges de travail accélérées 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 type comme « spot » dans votre Karpenter NodePool, Karpenter fournira des instances Spot par défaut sans aucune configuration supplémentaire. Toutefois, pour permettre une 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 portail
des fonctionnalités 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 price-capacity-optimizedd'allocation pour approvisionner les EC2 instances. En fonction des NodePool exigences et des contraintes liées aux modules, Karpenter intègre des modules non planifiables et envoie un ensemble varié de types d'instances à l'API Amazon Fleet. EC2 Vous pouvez utiliser l'outil EC2 Instance Type Explorer pour générer une liste de types d'instances correspondant à vos besoins de calcul spécifiques. -
Assurez-vous que les charges de travail sont apatrides, tolérantes aux pannes et flexibles. Les charges de travail doivent être apatrides, tolérantes aux pannes et flexibles en termes de taille. instance/GPU Cela permet une reprise fluide après une interruption de Spot, et la flexibilité de l'instance vous permet de rester sur Spot plus longtemps. Activez la gestion des interruptions 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 remarque un événement d'interruption Spot, il déconnecte, dilue, vide et arrête automatiquement le ou les nœuds avant l'événement d'interruption afin de maximiser le délai 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 restreindre la sélection du type d'instance. Vous devez éviter autant que possible de restreindre 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 avec une fréquence d'interruption des instances Spot plus faible à moindre coût. Par exemple, évitez de vous limiter à des types spécifiques (par exemple, g5.xlarge). Envisagez de spécifier un ensemble diversifié de catégories et de générations d'instances à l'aide de clés telles que karpenter.k8s. aws/instance-category and karpenter.k8s.aws/instance-generation. Karpenter enables easier diversification of on-demand and Spot instance capacity across multiple instance types and Availability Zones (AZs). Moreover, if your AI/MLLa charge de travail nécessite un nombre spécifique ou limité d'accélérateurs, mais elle est flexible selon les régions. Vous pouvez utiliser le Spot Placement Score pour identifier dynamiquement la région optimale pour déployer votre charge de travail avant le lancement.
-
Élargissez les NodePool exigences pour inclure un plus grand nombre de familles d' EC2 instances similaires. Chaque pool d'instances Spot consiste en une capacité d' EC2 instance 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 aux exigences NodePool de Karpenter. 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 les instances NVIDIA de la série G (génération 4 ou supérieure) de NVIDIA, quelle que soit leur taille et leur zone de disponibilité (AZs), 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 mais abondant dans une autre. Chaque combinaison unique d'un type d'instance et d'une zone de disponibilité constitue un pool de capacité ponctuel distinct. En demandant des capacités AZs dans l'ensemble d'une région répondant à vos NodePool besoins en matière de Karpenter, vous recherchez efficacement plus de pools à la fois. Cela maximise le nombre de pools de capacités Spot et augmente donc la probabilité d'acquérir de la capacité Spot. Pour ce faire, dans votre NodePool configuration, omettez complètement la clé topology.kubernetes.io/zone pour permettre à Karpenter de sélectionner parmi toutes les options disponibles AZs dans la région, ou listez explicitement à l' AZs aide de l'opérateur : In et fournissez les valeurs (par exemple, us-west-2a).
-
Envisagez d'utiliser le Spot Placement Score (SPS) pour avoir une idée de la probabilité 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 succès d'une demande Spot. Lorsque vous utilisez SPS, vous spécifiez d'abord vos besoins en calcul pour vos instances Spot, puis Amazon EC2 renvoie les 10 principales régions ou zones de disponibilité (AZs) 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 réussir, mais qu'il n'est pas garanti qu'elle aboutisse. 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 instructions relatives à la création d'un tableau de bord de suivi des scores de placement ponctuel sur AWS. Comme la capacité du spot fluctue en permanence, SPS vous aidera à identifier la combinaison de types d'instances et de régions la mieux adaptée à vos contraintes de charge de travail (flexibilité, performance, taille, etc.). AZs Si votre AI/ML charge de travail nécessite un nombre spécifique ou limité d'accélérateurs, mais qu'elle est flexible entre les régions, 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 relatives aux instances GPUs), 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 pour évaluer les besoins en matière de vCPU, de mémoire et de GPU, afin de garantir des configurations optimales pour les clusters EKS, notamment en envisageant d'utiliser d'autres régions AWS. Pour en savoir plus, consultez Comment fonctionne le score de placement Spot.
-
Gérez les interruptions et testez Spot avec élégance. Pour un pod dont la période de résiliation est supérieure à deux minutes, l'ancien nœud sera interrompu avant que ces pods ne soient reprogrammés, ce qui peut avoir un impact sur la disponibilité de la charge de travail. Tenez compte du préavis d'interruption ponctuelle 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, enregistrez la progression vers le stockage persistant comme Amazon S3) pour reprendre après une interruption, prolongez le terminationGracePeriod délai de 30 secondes dans les spécifications du Pod pour laisser plus de temps à un arrêt progressif et gérez les interruptions en utilisant les signaux and/or SIGTERM de 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, où le temps de mise à l'échelle est important et où les charges de travail prennent 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 fondamentales, tenez compte de ces facteurs lors de la gestion des charges de travail du GPU sur Amazon EKS. Contrairement aux charges de travail basées sur le processeur, les charges de travail sur le processeur graphique sont particulièrement sensibles aux détails matériels tels que les capacités du processeur graphique et la mémoire graphique disponible. Les charges de travail du GPU peuvent être limitées par les types d'instances qu'ils peuvent utiliser, avec moins d'options disponibles par rapport à. CPUs Dans un premier temps, déterminez si votre charge de travail est flexible en termes d'instance. Si vous ne savez pas combien de types d'instances votre charge de travail peut utiliser, testez-les individuellement pour garantir leur compatibilité et leur fonctionnalité. Déterminez dans quelle mesure vous pouvez être flexible pour diversifier autant que possible, tout en confirmant que la diversification permet de maintenir la charge de travail et en comprenant les impacts 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é entre CUDA et le 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 CUDA spécifiques pour des bibliothèques telles que. Assurez-vous donc de vérifier la TensorFlow compatibilité de vos charges de travail. Cette compatibilité est essentielle pour éviter les erreurs d'exécution, les pannes, les défaillances d'accélération du GPU (par exemple, des versions CUDA incompatibles avec des frameworks similaires PyTorch ou TensorFlow susceptibles d'empêcher l'exécution) ou pour pouvoir tirer parti de fonctionnalités matérielles telles que FP16/precision. INT8
-
Mémoire GPU. Assurez-vous d'évaluer les besoins en mémoire de vos modèles et d'établir 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 de définir la mémoire GPU minimale requise pour le type d'instance dans des étiquettes connues telles que karpenter.k8s.aws/. instance-gpu-memory La VRAM du GPU varie selon le type d'instance (par exemple, NVIDIA T4 dispose de 16 Go, A10G de 24 Go, V100 de 16 à 32 Go) et les modèles ML (par exemple, les modèles de langage volumineux) peuvent dépasser la mémoire disponible, provoquant des erreurs (OOM) ou des pannes. out-of-memory Pour les instances Spot dans EKS, cela peut limiter la diversification. Par exemple, vous ne pouvez pas inclure de types de mémoire VRAM inférieure 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 à un seul GPU ou à 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 dotés d'une VRAM suffisante dans votre configuration Spot. -
Précision et performance en virgule flottante. 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 à virgule flottante requises pour vos charges de travail. Utiliser un processeur graphique moins cher et moins performant ne signifie pas nécessairement qu'il est meilleur. Pensez donc à évaluer les performances en termes de travail effectué dans un délai précis afin de comprendre l'impact de la diversification.
Scénario : Diversification pour les 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 de Spot, tout en maintenant les performances grâce à des contraintes sur les capacités, la mémoire et l'architecture du GPU. Il prend en charge l'utilisation d'alternatives lorsque la capacité de l'instance est limitée, en minimisant les interruptions et en optimisant la latence d'inférence. Cet exemple NodePool indique qu'il faut utiliser des instances des séries g et p supérieures à 3, dotées de plus de 20 Go de mémoire graphique.
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 le point de contrôle pour les tâches de formation 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 les tâches de longue durée peuvent permettre de réduire le poids des modèles et d'optimiser les états des optimiseurs afin de 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 des points de contrôle, vous enregistrez les instantanés de votre modèle pendant la formation 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 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 des instances Amazon EC2 Spot.
Sans points de contrôle, les interruptions peuvent entraîner une perte de temps de calcul et 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 d'enregistrer régulièrement leur état (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 importants et à enregistrer les résultats intermédiaires dans un stockage persistant, tel qu'un bucket 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 équilibrer la tolérance aux pannes avec la surcharge de performance. Envisagez d'utiliser le point de contrôle dans les cas suivants :
-
La durée des tâches dépasse quelques heures : pour les tâches de formation de longue durée (par exemple, > 1 à 2 heures pour les petits modèles, ou days/weeks pour les grands modèles de base comportant des milliards de paramètres), où la perte de progression due à des interruptions est coûteuse. Les emplois plus courts ne justifient peut-être pas 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 défaillances matérielles (par exemple, des erreurs de mémoire du GPU), le point de contrôle permet une reprise rapide, ce qui rend Spot viable et permet de 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, >100 GPUs), où le temps moyen entre les défaillances diminue de façon linéaire avec l'échelle. Utilisez le model/data parallélisme pour gérer l'accès simultané aux points de contrôle et éviter les redémarrages complets.
-
Modèles à grande échelle nécessitant de fortes ressources : dans le cadre de la formation LLM à l'échelle du pétaoctet, où les défaillances sont inévitables en raison de la taille du cluster, les approches à plusieurs niveaux (local rapide toutes les 5 à 30 minutes pour les transitoires, durable toutes les heures pour les pannes majeures) optimisent le temps de restauration par rapport à l'efficacité.
Utilisez les blocs de capacité ML pour garantir la capacité des instances P et Trainium
Les blocs de capacité pour le ML vous permettent de réserver des instances GPU très recherchées, en particulier des instances P (par exemple, p6-b200, p5, p5e, p5en, p4d, p4de) et des instances Trainium (par exemple, trn1, trn2), pour démarrer presque immédiatement ou à une date future afin de prendre en charge vos charges de travail d'apprentissage automatique (ML) de courte durée. Ces réservations sont idéales pour garantir la capacité nécessaire aux tâches de calcul intensives, telles que la formation et le réglage des modèles. EC2 La tarification de Capacity Blocks comprend des frais de réservation et des frais de système d'exploitation. Pour en savoir plus sur la tarification, consultez la section EC2 Capacity Blocks for ML pricing
Pour réserver GPUs pour les AI/ML charges de travail sur Amazon EKS afin de garantir une capacité prévisible, nous vous recommandons d'utiliser les blocs de capacité ML pour les réservations de capacité à court terme ou à la demande (ODCRs) pour une assurance de capacité à usage général.
-
ODCRs vous permettent de réserver de la capacité d' EC2 instance (par exemple, des instances GPU telles que g5 ou p5) dans une zone de disponibilité spécifique pendant une certaine durée, afin de garantir la disponibilité, même en cas de forte demande. ODCRs vous n'avez aucun engagement à long terme, mais vous payez le tarif à la demande pour la capacité réservée, qu'elle soit utilisée ou inutilisée. Dans EKS, ODCRs sont pris en charge par des types de nœuds tels que Karpenter
et des groupes de nœuds gérés. Pour établir des priorités ODCRs dans Karpenter, configurez le NodeClass pour utiliser le capacityReservationSelectorTermschamp. Consultez la NodePools documentation de Karpenter. -
Les blocs de capacité sont un mécanisme de réservation spécialisé pour les instances GPU (par exemple, p5, p4d) ou Trainium (trn1, trn2), conçu pour les charges de travail ML à court terme telles que la formation de modèles, le réglage fin ou l'expérimentation. Vous réservez des capacités pour une période définie (généralement de 24 heures à 182 jours) à compter d'une date future, en ne payant que pour le temps réservé. Ils sont prépayés, nécessitent une planification préalable en fonction des besoins en capacité et ne prennent pas en charge la mise à l'échelle automatique, mais ils sont regroupés pour un réseau à faible latence. EC2 UltraClusters Ils facturent uniquement pour la période réservée. Pour en savoir plus, reportez-vous à la section Rechercher et acheter des blocs de capacité, ou commencez par configurer des groupes de nœuds gérés avec des blocs de capacité en suivant les instructions de la section Créer un groupe de nœuds gérés avec des blocs de capacité pour le ML.
Réservez de la capacité via l'AWS Management Console et configurez vos nœuds pour utiliser des blocs de capacité ML. Planifiez les réservations en fonction des plannings de charge de travail et testez-les dans un cluster intermédiaire. Reportez-vous à la documentation sur les blocs de capacité pour plus d'informations.
Envisagez des réservations de capacité à la demande, Amazon EC2 Spot ou à la demande (ODCRs) pour les EC2 instances G Amazon
Pour les EC2 instances Amazon G, considérez les différentes options d'achat proposées par On-Demand, Amazon EC2 Spot Instances et On-Demand Capacity Reservations. ODCRsvous permettent de réserver de la capacité d' EC2 instance dans une zone de disponibilité spécifique pendant une certaine durée, garantissant ainsi la disponibilité même en cas de forte demande. Contrairement aux blocs de capacité ML, qui ne sont disponibles que pour les instances P et Trainium, ils ODCRs peuvent être utilisés pour un plus large éventail de types d'instances, y compris les instances G, ce qui les rend adaptés aux charges de travail nécessitant des capacités GPU différentes, telles que l'inférence ou les graphiques. Lorsque vous utilisez des instances Amazon EC2 Spot, il est essentiel de pouvoir varier les types d'instances, les tailles et les zones de disponibilité pour pouvoir rester sur Spot plus longtemps.
ODCRs vous n'avez aucun engagement à long terme, mais vous payez le tarif à la demande pour la capacité réservée, qu'elle soit utilisée ou inutilisée. ODCRs peuvent être créés pour une utilisation immédiate ou planifiés pour une date future, offrant ainsi une flexibilité dans la planification des capacités. Dans Amazon EKS, ODCRs sont pris en charge par des types de nœuds tels que KarpentercapacityReservationSelectorTerms champ. Consultez la NodePools documentation de Karpenter
Envisagez d'autres types et tailles d'instances accélérés
La sélection de l'instance accélérée et de la taille appropriées est essentielle pour optimiser à la fois les performances et les coûts de vos charges de travail ML sur Amazon EKS. Par exemple, les différentes familles d'instances de GPU ont des performances et des capacités différentes, telles que la mémoire GPU. Pour vous aider à choisir l'option la plus rentable, consultez les instances de GPU disponibles sur la EC2 page Types
Si vous utilisez une instance de GPU dans un nœud EKS, le nvidia-device-plugin-daemonset pod figurera par défaut dans l'kube-systemespace de noms. Pour savoir rapidement si vous utilisez pleinement le ou les GPU de votre instance, vous pouvez utiliser nvidia-smi
kubectl exec nvidia-device-plugin-daemonset-xxxxx \ -n kube-system -- nvidia-smi \ --query-gpu=index,power.draw,power.limit,temperature.gpu,utilization.gpu,utilization.memory,memory.free,memory.used \ --format=csv -l 5
-
Si
utilization.memorycette valeur est proche de 100 %, vos codes sont probablement liés à la mémoire. Cela signifie que le GPU (mémoire) est pleinement utilisé, mais cela pourrait suggérer qu'une optimisation plus poussée des performances devrait être étudiée. -
Si la
utilization.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 %, vos codes utilisent pleinement la capacité de calcul du GPU. -
Le
-l 5drapeau indique de sortir les métriques toutes les 5 secondes. Dans le cas d'un seul type d'instance de GPU, l'indicateur de requête d'index n'est pas nécessaire.
Pour en savoir plus, consultez les instances GPU dans la documentation AWS.
Optimisez l'allocation des ressources GPU grâce au découpage temporel, au MIG et à l'allocation fractionnée du GPU
Les limites de ressources statiques dans Kubernetes (par exemple, le nombre de processeurs, de mémoire, de GPU) peuvent entraîner un provisionnement excessif ou une sous-utilisation, en particulier pour les charges de travail dynamiques telles que l'inférence. AI/ML Il est important de sélectionner le bon processeur graphique. Pour les charges de travail à faible volume ou trop élevées, le découpage en tranches de temps permet à plusieurs charges de travail de partager un seul GPU en partageant ses ressources de calcul, ce qui peut améliorer l'efficacité et réduire le gaspillage. Le partage du GPU peut être réalisé grâce à différentes options :
-
Tirez parti des sélecteurs de nœuds et de l'affinité des nœuds pour influencer la planification : assurez-vous que les nœuds provisionnés et les pods sont planifiés en fonction de la GPUs charge de travail (par exemple,)
karpenter.k8s.aws/instance-gpu-name: "a100" -
Tranchage dans le temps : planifie les charges de travail pour partager les ressources de calcul d'un GPU au fil du temps, permettant ainsi une exécution simultanée sans partitionnement physique. C'est idéal pour les charges de travail soumises à des exigences de calcul variables, mais qui peuvent ne pas isoler la mémoire.
-
GPU multi-instance (MIG) : MIG permet de partitionner un seul GPU NVIDIA en plusieurs instances isolées et est compatible avec NVIDIA Ampere (par exemple, GPU A100), NVIDIA Hopper (par exemple, GPU H100) et NVIDIA Blackwell (par exemple, Blackwell). GPUs GPUs Chaque instance MIG reçoit des ressources de calcul et de mémoire dédiées, ce qui permet le partage des ressources dans des environnements mutualisés ou des charges de travail nécessitant des garanties de ressources, ce qui vous permet d'optimiser l'utilisation des ressources du GPU, y compris des scénarios tels que le service de plusieurs modèles avec des tailles de lots différentes par le biais d'un découpage temporel.
-
Allocation fractionnée du GPU : utilise une planification logicielle pour allouer des parties du calcul ou de la mémoire d'un GPU aux charges de travail, offrant ainsi une flexibilité pour les charges de travail dynamiques. Le planificateur NVIDIA KAI
, qui fait partie de la plateforme Run:AI, permet cela en permettant aux pods de demander des ressources GPU fractionnées.
Pour activer ces fonctionnalités dans EKS, vous pouvez déployer le plugin NVIDIA Device, qui expose les ressources GPUs sous forme de ressources planifiables et prend en charge le time-slicing et le MIG. Pour en savoir plus, consultez les sections Time-Slicing GPUs dans Kubernetes
Exemple
Par exemple, pour activer le time-slicing avec le plugin NVIDIA Device :
apiVersion: v1 kind: ConfigMap metadata: name: nvidia-device-plugin-config namespace: kube-system data: config.yaml: | version: v1 sharing: timeSlicing: resources: - name: nvidia.com/gpu replicas: 4 # Allow 4 pods to share each GPU
Exemple
Par exemple, pour utiliser KAI Scheduler pour l'allocation fractionnée du GPU, déployez-le aux côtés de l'opérateur GPU NVIDIA et spécifiez les ressources GPU fractionnées dans la spécification du pod :
apiVersion: v1 kind: Pod metadata: name: fractional-gpu-pod-example annotations: gpu-fraction: "0.5" # Annotation for 50% GPU labels: runai/queue: "default" # Required queue assignment spec: containers: - name: ml-workload image: nvcr.io/nvidia/pytorch:25.04-py3 resources: limits: nvidia.com/gpu: 1 nodeSelector: nvidia.com/gpu: "true" schedulerName: kai-scheduler
Résilience des nœuds et gestion des tâches de formation
Mettre en œuvre des contrôles de santé des nœuds avec restauration automatique
Pour les tâches de formation distribuées sur Amazon EKS qui nécessitent des communications fréquentes entre nœuds, telles que la formation de modèles multi-GPU sur plusieurs nœuds, les problèmes matériels tels que les pannes du GPU ou de l'EFA peuvent perturber les tâches de formation. Ces interruptions peuvent entraîner une perte de progression en matière de formation et une augmentation des coûts, en particulier pour les AI/ML charges de travail de longue durée qui reposent sur un matériel stable.
Pour renforcer la résilience face aux défaillances matérielles, telles que les pannes de GPU dans les clusters EKS exécutant des charges de travail GPU, nous vous recommandons de tirer parti de l'agent de surveillance des nœuds EKS avec Auto Repair ou d'Amazon SageMaker HyperPod. Alors que l'agent de surveillance des nœuds EKS avec réparation automatique fournit des fonctionnalités telles que la surveillance de l'état des nœuds et la réparation automatique à l'aide des mécanismes Kubernetes standard, il SageMaker HyperPod offre une résilience ciblée et des fonctionnalités supplémentaires spécialement conçues pour la formation ML à grande échelle, telles que des bilans de santé approfondis et la reprise automatique des tâches.
-
L'agent de surveillance des nœuds EKS avec Node Auto Repair surveille en permanence l'état des nœuds en lisant les journaux et en appliquant NodeConditions des conditions standard telles que
Readyles conditions spécifiques au matériel accéléré afin d'identifier les problèmes tels que les pannes de GPU ou de réseau. Lorsqu'un nœud est jugé insalubre, Node Auto Repair le cordon et le remplace par un nouveau nœud. La replanification des pods et le redémarrage des tâches s'appuient sur les mécanismes standard de Kubernetes et sur la politique de redémarrage des tâches. -
Les contrôles de santé SageMaker HyperPod
approfondis et l'agent de surveillance de l'état de santé surveillent en permanence l'état de santé des instances basées sur le GPU et Trainium. Il est adapté aux AI/ML charges de travail et utilise des étiquettes (par exemple node-health-status) pour gérer l'état des nœuds. Lorsqu'un nœud est jugé défectueux, HyperPod déclenche le remplacement automatique du matériel défectueux, par exemple GPUs. Il détecte les défaillances liées au réseau pour EFA par le biais de ses contrôles de santé de base par défaut et prend en charge la reprise automatique des tâches de formation interrompues, permettant ainsi aux tâches de poursuivre les tâches depuis le dernier point de contrôle, minimisant ainsi les interruptions pour les tâches de machine learning à grande échelle.
Pour l'agent de surveillance des nœuds EKS avec réparation automatique et les SageMaker HyperPod clusters utilisant EFA, afin de surveiller les métriques spécifiques à EFA, telles que les erreurs RDMA (Remote Direct Memory Access) et les pertes de paquets, assurez-vous que le pilote AWS EFA est installé. En outre, nous vous recommandons de déployer le module complémentaire CloudWatch Observability ou d'utiliser des outils tels que DCGM Exporter avec Prometheus et Grafana pour surveiller l'EFA, le GPU et, pour SageMaker HyperPod les indicateurs spécifiques liés à ses fonctionnalités.
Désactiver Karpenter Consolidation pour les charges de travail sensibles aux interruptions
Pour les charges de travail sensibles aux interruptions, telles que le traitement, les tâches de AI/ML prédiction à grande échelle ou la formation, nous recommandons d'ajuster les politiques de consolidation de Karpenter
La politique de WhenEmptyOrUnderutilized consolidation peut mettre fin aux nœuds prématurément, ce qui entraîne des délais d'exécution plus longs. Par exemple, les interruptions peuvent retarder la reprise des tâches en raison de la replanification des modules ou du rechargement des données, ce qui peut s'avérer coûteux pour les tâches d'inférence par lots de longue durée. Pour atténuer ce problème, vous pouvez définir la valeur WhenEmpty et consolidationPolicy configurer une consolidateAfter durée, telle qu'une heure, pour conserver les nœuds pendant les pics de charge de travail. Par exemple :
disruption: consolidationPolicy: WhenEmpty consolidateAfter: 60m
Cette approche améliore la latence au démarrage des modules pour les charges de travail d'inférence par lots complexes et autres tâches sensibles aux interruptions, telles que le traitement des données d'inférence en ligne en temps réel ou la formation de modèles, où le coût de l'interruption l'emporte sur les économies de coûts de calcul. Karpenter NodePool Disruption Budgets
Utiliser ttlSecondsAfter Finished pour nettoyer automatiquement les tâches Kubernetes
Nous vous recommandons de configurer ttlSecondsAfterFinished les tâches Kubernetes dans Amazon EKS pour qu'elles suppriment automatiquement les objets de tâche terminés. Les objets de travail persistants consomment les ressources du cluster, telles que la mémoire du serveur d'API, et compliquent la surveillance en encombrant les tableaux de bord (par exemple, Grafana, Amazon). CloudWatch Par exemple, la définition d'un TTL d'une heure garantit que les tâches sont supprimées peu de temps après leur fin, ce qui permet de garder votre cluster bien rangé. Pour plus de détails, reportez-vous à la section Nettoyage automatique des tâches terminées
Configurer la préemption des tâches de faible priorité pour les tâches et les charges de travail de priorité plus élevée
Pour les charges de AI/ML travail à priorité mixte sur Amazon EKS, vous pouvez configurer la préemption des tâches à faible priorité afin de garantir que les tâches les plus prioritaires (par exemple, l'inférence en temps réel) reçoivent des ressources rapidement. Sans préemption, les charges de travail peu prioritaires telles que les processus par lots (par exemple, inférence par lots, traitement des données), les services non batch (par exemple, tâches en arrière-plan, tâches cron) ou les tâches gourmandes en CPU et en mémoire (par exemple, les services Web) peuvent retarder les pods critiques en occupant des nœuds. La préemption permet à Kubernetes d'expulser les pods de faible priorité lorsque les pods de priorité élevée ont besoin de ressources, garantissant ainsi une allocation efficace des ressources sur les nœuds dotés de ou de mémoire. GPUs CPUs Nous vous recommandons d'utiliser Kubernetes PriorityClass pour attribuer des priorités et contrôler le comportement PodDisruptionBudget d'expulsion.
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: low-priority value: 100 --- spec: priorityClassName: low-priority
Consultez la documentation relative à la priorité et à la préemption de Kubernetes
Mise à l'échelle et performances des applications
Adaptez la capacité de calcul aux charges de travail ML avec Karpenter ou Static Nodes
Pour garantir une capacité de calcul rentable et réactive pour les flux de travail d'apprentissage automatique (ML) sur Amazon EKS, nous vous recommandons d'adapter votre stratégie de provisionnement des nœuds aux caractéristiques de votre charge de travail et à vos engagements en matière de coûts. Vous trouverez ci-dessous deux approches à envisager : le just-in-time dimensionnement avec Karpenter
-
Just-in-time scalers de plans de données tels que Karpenter : pour les flux de travail ML dynamiques soumis à des exigences de calcul variables (par exemple, inférence basée sur le GPU suivie d'un tracé basé sur le processeur), nous recommandons d'utiliser des scalers de plans de données tels que Karpenter. just-in-time
-
Utilisez des groupes de nœuds statiques pour des charges de travail prévisibles : pour des charges de travail ML prévisibles et stables ou lors de l'utilisation d'instances réservées, les groupes de nœuds gérés par EKS peuvent contribuer à garantir que la capacité réservée est entièrement provisionnée et utilisée, maximisant ainsi les économies. Cette approche est idéale pour des types d'instances spécifiques commis via RIs ou ODCRs.
Exemple
Voici un exemple de Karpenter diversifié NodePoolg Amazon lorsque la génération d'instances est supérieure à trois.
apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: gpu-inference spec: template: spec: nodeClassRef: group: karpenter.k8s.aws kind: EC2NodeClass name: default requirements: - key: karpenter.sh/capacity-type operator: In values: ["on-demand"] - key: karpenter.k8s.aws/instance-category operator: In values: ["g"] - key: karpenter.k8s.aws/instance-generation operator: Gt values: ["3"] - key: kubernetes.io/arch operator: In values: ["amd64"] taints: - key: nvidia.com/gpu effect: NoSchedule limits: cpu: "1000" memory: "4000Gi" nvidia.com/gpu: "10" *# Limit the total number of GPUs to 10 for the NodePool* disruption: consolidationPolicy: WhenEmpty consolidateAfter: 60m expireAfter: 720h
Exemple
Exemple d'utilisation de groupes de nœuds statiques pour une charge de travail d'entraînement :
apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: ml-cluster region: us-west-2 managedNodeGroups: - name: gpu-node-group instanceType: p4d.24xlarge minSize: 2 maxSize: 2 desiredCapacity: 2 taints: - key: nvidia.com/gpu effect: NoSchedule
Utilisez des contraintes et des tolérances pour empêcher que des charges de travail non accélérées ne soient planifiées sur des instances accélérées
La planification de charges de travail non accélérées sur les ressources GPU n'est pas efficace en termes de calcul. Nous vous recommandons d'utiliser des restrictions et des tolérances pour garantir que les pods de charges de travail non accélérées ne sont pas planifiés sur des nœuds inappropriés. Consultez la documentation de Kubernetes
Échelle basée sur les performances du modèle
Pour les charges de travail d'inférence, nous recommandons d'utiliser Kubernetes Event-Driven Autoscaling (KEDA) pour effectuer une mise à l'échelle en fonction des indicateurs de performance du modèle, tels que les demandes d'inférence ou le débit de jetons, avec des périodes de recharge appropriées. Les politiques de dimensionnement statique peuvent surprovisionner ou sous-allouer les ressources, ce qui a un impact sur les coûts et la latence. Pour en savoir plus, consultez la documentation KEDA
Allocation dynamique des ressources pour une gestion avancée du GPU
L'allocation dynamique des ressources (DRA)
-
Allocation précise du GPU
-
Mécanismes de partage avancés, tels que le service multi-processus (MPS) et le GPU multi-instance (MIG)
-
Support pour les architectures matérielles de nouvelle génération, notamment NVIDIA 00 GB2 UltraServers
L'allocation GPU traditionnelle traite les ressources GPUs comme des entiers opaques, ce qui entraîne une sous-utilisation significative (souvent 30 à 40 % dans les clusters de production). Cela se produit parce que les charges de travail bénéficient d'un accès exclusif à l'intégralité, GPUs même lorsqu'elles ne nécessitent que des ressources fractionnaires. DRA transforme ce modèle en introduisant une allocation déclarative structurée qui fournit au planificateur Kubernetes une visibilité complète sur les caractéristiques matérielles et les exigences en matière de charge de travail. Cela permet de prendre des décisions de placement intelligentes et de partager efficacement les ressources.
Avantages de l'utilisation de DRA au lieu du plug-in d'appareil NVIDIA
Le plug-in pour appareil NVIDIA (à partir de la version0.12.0) prend en charge les mécanismes de partage du GPU, notamment le time-slicing, le MPS et le MIG. Cependant, il existe des limites architecturales que le DRA corrige.
Limitations des plug-ins pour appareils NVIDIA
-
Configuration statique : les configurations de partage du GPU (répliques temporelles et paramètres MPS) nécessitent une préconfiguration à l'échelle du cluster.
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 par le biais d'étiquettes de nœuds, les charges de travail ne peuvent pas demander de manière dynamique des configurations GPU spécifiques (taille de mémoire et capacités de calcul) dans le cadre de la décision de planification.
-
Aucune coordination des ressources entre nœuds : impossible de gérer les ressources GPU distribuées sur plusieurs nœuds ou d'exprimer des exigences topologiques complexes, telles que les NVLink domaines pour des systèmes tels que NVIDIA GB2 00.
-
Contraintes du planificateur : le planificateur Kubernetes traite les ressources du GPU comme des entiers opaques, ce qui limite sa capacité à prendre des décisions tenant compte de la topologie ou à gérer des dépendances de ressources complexes.
-
Complexité de la configuration : la mise en place de différentes stratégies de partage nécessite un étiquetage multiple
ConfigMapset minutieux des nœuds, ce qui crée une complexité opérationnelle.
Solutions avec DRA
-
Sélection dynamique des ressources : le DRA permet aux charges de travail de spécifier des exigences détaillées (mémoire GPU, versions des pilotes et attributs spécifiques) au
resourceclaimsmoment de la demande. Cela permet une mise en correspondance des ressources plus flexible. -
Connaissance de la topologie : grâce à des paramètres structurés et à des sélecteurs de périphériques, le DRA répond à des exigences complexes telles que la communication GPU entre nœuds et les interconnexions cohérentes en mémoire.
-
Gestion des ressources entre nœuds :
computeDomainspermet de coordonner les ressources GPU distribuées sur plusieurs nœuds, ce qui est essentiel pour les systèmes tels que GB2 00 dotés de canaux IMEX. -
Configuration spécifique à la charge de travail : chacune
ResourceClaimdéfinit des stratégies et des configurations de partage différentes, ce qui permet un contrôle précis par charge de travail plutôt que des paramètres à l'échelle du cluster. -
Intégration améliorée du planificateur : DRA fournit au planificateur des informations détaillées sur les appareils et permet de prendre des décisions de placement plus intelligentes en fonction de la topologie matérielle et des caractéristiques des ressources.
Important : DRA ne remplace pas entièrement le plug-in de l'appareil NVIDIA. Le pilote NVIDIA DRA fonctionne conjointement avec le plug-in de l'appareil pour fournir des fonctionnalités améliorées. Le plug-in de l'appareil continue de gérer la découverte et la gestion de base du GPU, tandis que le DRA ajoute des fonctionnalités avancées d'allocation et de planification.
Instances prises en charge par DRA et leurs fonctionnalités
La prise en charge du DRA varie en fonction de la famille d' EC2 instances Amazon et de l'architecture GPU, comme indiqué dans le tableau suivant.
| Famille d’instances | Type de GPU | Trancher le temps | Support MIG | Support MPS | Support IMEX | Cas d’utilisation |
|---|---|---|---|---|---|---|
|
G5 |
NVIDIA A10 G |
Oui |
Non |
Oui |
Non |
Charges de travail graphiques et d'inférence |
|
G6 |
NVIDIA L4 |
Oui |
Non |
Oui |
Non |
Inférence basée sur l'IA et traitement vidéo |
|
G6e |
NVIDIA L40 |
Oui |
Non |
Oui |
Non |
Entraînement, inférence et graphisme |
|
P4D/P4de |
NVIDIA A100 |
Oui |
Oui |
Oui |
Non |
Formation à grande échelle et HPC |
|
P5 |
NVIDIA H100 |
Oui |
Oui |
Oui |
Non |
Formation sur les modèles de base |
|
P6 |
NVIDIA B200 |
Oui |
Oui |
Oui |
Non |
Modèles comportant des milliards ou des billions de paramètres, formation distribuée et inférence |
|
P6e |
NVIDIA GB2 00 |
Oui |
Oui |
Oui |
Oui |
Modèles comportant des milliards ou des billions de paramètres, formation distribuée et inférence |
Les descriptions de chaque fonctionnalité du tableau sont les suivantes :
-
Tranchage dans le temps : permet à plusieurs charges de travail de partager les ressources de calcul du GPU au fil du temps.
-
GPU multi-instance (MIG) : partitionnement au niveau du matériel qui crée des instances de GPU isolées.
-
Service multiprocessus (MPS) : permet l'exécution simultanée de plusieurs processus CUDA sur un seul GPU.
-
Internode Memory Exchange (IMEX) : communication cohérente en mémoire entre les nœuds pour 00. GB2 UltraServers
Ressources supplémentaires
Pour plus d'informations sur les pilotes Kubernetes DRA et NVIDIA DRA, consultez les ressources suivantes sur : GitHub
Configurez l'allocation dynamique des ressources pour une gestion avancée du GPU
La rubrique suivante explique comment configurer l'allocation dynamique des ressources (DRA) pour une gestion avancée du GPU.
Prérequis
Avant d'implémenter le DRA sur Amazon EKS, assurez-vous que votre environnement répond aux exigences suivantes.
Configuration du cluster
-
Cluster Amazon EKS en cours d'exécution (version
1.33ou ultérieure) -
Nœuds de travail compatibles avec le GPU NVIDIA dotés des types d'instances appropriés
Composants requis
-
Version du plugin pour appareil NVIDIA
0.17.1ou version ultérieure -
Version du pilote NVIDIA DRA
25.3.0ou ultérieure
Étape 1 : créer un cluster avec un groupe de nœuds compatible DRA à l'aide d'eksctl
-
Créez un fichier de configuration de cluster nommé
dra-eks-cluster.yaml:--- apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: dra-eks-cluster region: us-west-2 version: '1.33' managedNodeGroups: - name: gpu-dra-nodes amiFamily: AmazonLinux2023 instanceType: g6.12xlarge desiredCapacity: 2 minSize: 1 maxSize: 3 labels: node-type: "gpu-dra" nvidia.com/gpu.present: "true" taints: - key: nvidia.com/gpu value: "true" effect: NoSchedule -
Créez le cluster :
eksctl create cluster -f dra-eks-cluster.yaml
Étape 2 : Déployer le plug-in pour appareil NVIDIA
Déployez le plug-in pour appareil NVIDIA pour activer la découverte de base du GPU :
-
Ajoutez le référentiel Helm du plugin pour appareils NVIDIA :
helm repo add nvidia https://nvidia.github.io/k8s-device-plugin helm repo update -
Créez des valeurs personnalisées pour le plug-in de l'appareil :
cat <<EOF > nvidia-device-plugin-values.yaml gfd: enabled: true nfd: enabled: true tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule EOF -
Installez le plug-in pour appareil NVIDIA :
helm install nvidia-device-plugin nvidia/nvidia-device-plugin \ --namespace nvidia-device-plugin \ --create-namespace \ --version v0.17.1 \ --values nvidia-device-plugin-values.yaml
Étape 3 : Déploiement du pilote NVIDIA DRA Helm (graphique Helm)
-
Créez un fichier de
dra-driver-values.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érifier l'installation du 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 de GPU G6 nouvellement créée rejoint votre cluster Amazon EKS avec le DRA activé, les actions suivantes se produisent :
-
Le pilote NVIDIA DRA détecte automatiquement le GPU A10G et en crée deux
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.). -
Étant donné que 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 d'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 de l'allocation dynamique des ressources.
Planifiez une charge de travail GPU simple à l'aide de l'allocation dynamique des ressources
Pour planifier une charge de travail GPU simple à l'aide de l'allocation dynamique des ressources (DRA), procédez comme suit. Avant de poursuivre, assurez-vous d'avoir bien suiviConfigurez l'allocation dynamique des ressources pour une gestion avancée du GPU.
-
Créez une base
ResourceClaimTemplatepour l'allocation du GPU avec un fichier nommébasic-gpu-claim-template.yaml:--- apiVersion: v1 kind: Namespace metadata: name: gpu-test1 --- apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: namespace: gpu-test1 name: single-gpu spec: spec: devices: requests: - name: gpu deviceClassName: gpu.nvidia.com -
Appliquez le modèle :
kubectl apply -f basic-gpu-claim-template.yaml -
Vérifiez le statut :
kubectl get resourceclaimtemplates -n gpu-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 consulter les informations relatives au processeur graphique :
kubectl logs gpu-pod -n gpu-test1Voici un exemple de sortie attendue :
GPU 0: NVIDIA L4 (UUID: GPU-da7c24d7-c7e3-ed3b-418c-bcecc32af7c5)
Continuez vers Techniques d'optimisation du GPU avec allocation dynamique des ressources pour découvrir des techniques d'optimisation du GPU plus avancées à l'aide de la DRA.
Techniques d'optimisation du GPU avec allocation dynamique des ressources
Les charges de travail des GPU modernes nécessitent une gestion sophistiquée des ressources pour optimiser l'utilisation et la rentabilité. Le DRA permet plusieurs techniques d'optimisation avancées qui répondent à différents cas d'utilisation et à différentes capacités matérielles :
-
Le découpage dans le temps permet à plusieurs charges de travail de partager les ressources de calcul du GPU au fil du temps, ce qui le rend idéal pour les charges de travail d'inférence associées à une utilisation sporadique du GPU. Pour obtenir un exemple, consultez Optimisez les charges de travail du GPU grâce au découpage en tranches de temps.
-
Le service multiprocessus (MPS) permet l'exécution simultanée de plusieurs processus CUDA sur un seul GPU avec une meilleure isolation que le découpage en tranches temporelles. Pour obtenir un exemple, consultez Optimisez les charges de travail du GPU avec MPS.
-
Le GPU multi-instance (MIG) assure le partitionnement au niveau du matériel, en créant des instances de GPU isolées dotées de ressources de calcul et de mémoire dédiées. Pour obtenir un exemple, consultez Optimisez les charges de travail du GPU avec le GPU multi-instance.
-
L'échange de mémoire entre nœuds (IMEX) permet une communication cohérente en mémoire entre les nœuds pour un entraînement distribué sur les systèmes NVIDIA 00. GB2 Pour obtenir un exemple, consultez Optimisez les charges de travail du GPU avec IMEX à l'aide de GB2 00 instances P6e.
Ces techniques peuvent améliorer considérablement l'utilisation des ressources. Organisations signalent que l'utilisation du GPU augmente de 30 à 40 % avec l'allocation traditionnelle à 80 à 90 % avec des stratégies de partage optimisées. Le choix de la technique dépend des caractéristiques de la charge de travail, des exigences d'isolation et des capacités matérielles.
Optimisez les charges de travail du GPU grâce au découpage en tranches de temps
Le time-slicing permet à plusieurs charges de travail de partager les ressources de calcul du GPU en les planifiant pour qu'elles s'exécutent de manière séquentielle sur le même GPU physique. Il est idéal pour les charges de travail d'inférence associées à une utilisation sporadique du GPU.
Procédez comme suit.
-
Définissez un
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 time-slicing avec un fichier nommé :
timeslicing-pod.yaml--- # Pod 1 - Inference workload apiVersion: v1 kind: Pod metadata: name: inference-pod-1 namespace: timeslicing-gpu labels: app: gpu-inference spec: restartPolicy: Never containers: - name: inference-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "-c"] args: - | import torch import time import os print(f"=== POD 1 STARTING ===") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Current GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB") # Simulate inference workload for i in range(20): x = torch.randn(1000, 1000).cuda() y = torch.mm(x, x.t()) print(f"Pod 1 - Iteration {i+1} completed at {time.strftime('%H:%M:%S')}") time.sleep(60) else: print("No GPU available!") time.sleep(5) resources: claims: - name: shared-gpu-claim resourceClaims: - name: shared-gpu-claim resourceClaimTemplateName: timeslicing-gpu-template nodeSelector: NodeGroupType: "gpu-dra" nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule --- # Pod 2 - Training workload apiVersion: v1 kind: Pod metadata: name: training-pod-2 namespace: timeslicing-gpu labels: app: gpu-training spec: restartPolicy: Never containers: - name: training-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "-c"] args: - | import torch import time import os print(f"=== POD 2 STARTING ===") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Current GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB") # Simulate training workload with heavier compute for i in range(15): x = torch.randn(2000, 2000).cuda() y = torch.mm(x, x.t()) loss = torch.sum(y) print(f"Pod 2 - Training step {i+1}, Loss: {loss.item():.2f} at {time.strftime('%H:%M:%S')}") time.sleep(5) else: print("No GPU available!") time.sleep(60) resources: claims: - name: shared-gpu-claim-2 resourceClaims: - name: shared-gpu-claim-2 resourceClaimTemplateName: timeslicing-gpu-template nodeSelector: NodeGroupType: "gpu-dra" nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule -
Appliquez le modèle et le pod :
kubectl apply -f timeslicing-claim-template.yaml kubectl apply -f timeslicing-pod.yaml -
Surveillez les demandes de ressources :
kubectl get resourceclaims -n timeslicing-gpu -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 : commence à fonctionner immédiatement
Deuxième module (training-pod-2)
-
État :
pending -
Signification : attendre que DRA configure le time-slicing sur le même GPU
-
État du pod : En attente de planification
-
L'État va passer de
pendingallocated,reservedàrunning
Optimisez les charges de travail du GPU avec MPS
Le service multiprocessus (MPS) permet l'exécution simultanée de plusieurs contextes CUDA sur un seul GPU avec une meilleure isolation que le découpage en tranches temporelles.
Procédez comme suit.
-
Définissez un
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 pods MPS :
kubectl apply -f mps-claim-template.yaml kubectl apply -f mps-pod.yaml -
Surveillez les demandes de ressources :
kubectl get resourceclaims -n mps-gpu -wVoici un exemple de sortie :
NAME STATE AGE mps-multi-container-pod-shared-gpu-claim-2p9kx allocated,reserved 86s
Cette configuration illustre un véritable partage de GPU à l'aide du service multiprocessus NVIDIA (MPS) via l'allocation dynamique des ressources (DRA). Contrairement au time-slicing où les charges de travail utilisent à tour de rôle le GPU de manière séquentielle, le MPS permet aux deux conteneurs de s'exécuter simultanément sur le même GPU physique. L'essentiel est que le partage DRA MPS nécessite plusieurs conteneurs au sein d'un même pod, et non plusieurs pods distincts. Une fois déployé, le pilote DRA en alloue un ResourceClaim au Pod et configure automatiquement le MPS pour permettre aux conteneurs d'inférence et d'entraînement de s'exécuter simultanément.
Chaque conteneur dispose de son propre espace mémoire GPU et de ses propres ressources de calcul, le daemon MPS coordonnant l'accès au matériel sous-jacent. Vous pouvez vérifier que cela fonctionne en procédant comme suit :
-
Vérification
nvidia-smi, qui affichera les deux conteneurs sous forme de processus M+C (MPS + Compute) partageant le même périphérique GPU. -
Surveillance des journaux des deux conteneurs, qui afficheront des horodatages entrelacés prouvant une exécution simultanée.
Cette approche maximise l'utilisation du GPU en permettant aux charges de travail complémentaires de partager efficacement le matériel GPU coûteux, plutôt que de le laisser sous-utilisé par un seul processus.
Récipient 1 : inference-container
root@mps-multi-container-pod:/workspace# nvidia-smi
Wed Jul 16 21:09:30 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 570.158.01 Driver Version: 570.158.01 CUDA Version: 12.9 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA L4 On | 00000000:35:00.0 Off | 0 |
| N/A 48C P0 28W / 72W | 597MiB / 23034MiB | 0% E. Process |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| 0 N/A N/A 1 M+C python 246MiB |
+-----------------------------------------------------------------------------------------+
Conteneur 2 : training-container
root@mps-multi-container-pod:/workspace# nvidia-smi
Wed Jul 16 21:16:00 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 570.158.01 Driver Version: 570.158.01 CUDA Version: 12.9 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA L4 On | 00000000:35:00.0 Off | 0 |
| N/A 51C P0 28W / 72W | 597MiB / 23034MiB | 0% E. Process |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| 0 N/A N/A 1 M+C python 314MiB |
+-----------------------------------------------------------------------------------------+
Optimisez les charges de travail du GPU avec le GPU multi-instance
Le GPU multi-instance (MIG) assure le partitionnement au niveau du matériel, en créant des instances de GPU isolées dotées de ressources de calcul et de mémoire dédiées.
L'utilisation du partitionnement MIG dynamique avec différents profils nécessite l'opérateur GPU NVIDIAWITH0—REBOOT=true dans la configuration de MIG Manager est essentielle à la réussite des déploiements MIG.
Vous avez besoin du pilote NVIDIA DRA
Étape 1 : Dé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 graphique Helm déploie les composants suivants et plusieurs profils MIG :
-
Plug-in de périphérique (planification des ressources GPU)
-
DCGM Exporter (métriques et surveillance du GPU)
-
Node Feature Discovery (NFD - étiquetage du matériel)
-
Découverte des fonctionnalités du GPU (GFD - étiquetage spécifique au GPU)
-
MIG Manager (partitionnement GPU multi-instances)
-
Container Toolkit (environnement d'exécution du conteneur GPU)
-
Operator Controller (gestion du cycle de vie)
-
-
Vérifiez les pods de déploiement :
kubectl get pods -n gpu-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és par P4de pour tester les exemples MIG :
apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: dra-eks-cluster region: us-east-1 version: '1.33' managedNodeGroups: # P4DE MIG Node Group with Capacity Block Reservation - name: p4de-mig-nodes amiFamily: AmazonLinux2023 instanceType: p4de.24xlarge # Capacity settings desiredCapacity: 0 minSize: 0 maxSize: 1 # Use specific subnet in us-east-1b for capacity reservation subnets: - us-east-1b # AL2023 NodeConfig for RAID0 local storage only nodeadmConfig: apiVersion: node.eks.aws/v1alpha1 kind: NodeConfig spec: instance: localStorage: strategy: RAID0 # Node labels for MIG configuration labels: nvidia.com/gpu.present: "true" nvidia.com/gpu.product: "A100-SXM4-80GB" nvidia.com/mig.config: "p4de-half-balanced" node-type: "p4de" vpc.amazonaws.com/efa.present: "true" accelerator: "nvidia" # Node taints taints: - key: nvidia.com/gpu value: "true" effect: NoSchedule # EFA support efaEnabled: true # Placement group for high-performance networking placementGroup: groupName: p4de-placement-group strategy: cluster # Capacity Block Reservation (CBR) # Ensure CBR ID matches the subnet AZ with the Nodegroup subnet spot: false capacityReservation: capacityReservationTarget: capacityReservationId: "cr-abcdefghij" # Replace with your capacity reservation 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 du matériel telles que configurées. Voici comment fonctionne le partitionnement :
L'opérateur du GPU a appliqué cette configuration à partir de votre profil MIG intégré :
p4de-half-balanced:
- devices: [0, 1, 2, 3] # First 4 GPUs: MIG enabled
mig-enabled: true
mig-devices:
"1g.10gb": 2 # 2x small instances (10GB each)
"2g.20gb": 1 # 1x medium instance (20GB)
"3g.40gb": 1 # 1x large instance (40GB)
- devices: [4, 5, 6, 7] # Last 4 GPUs: Full GPUs
mig-enabled: false
À partir de vos nvidia-smi -L résultats, voici ce que l'opérateur du GPU a créé :
-
compatible MiG GPUs (0-3) : partitionné du matériel
-
GPU 0 : NVIDIA A100- SXM4 -80 Go
-
Appareil MIG 3g.40 Go 0 — Charges de travail importantes (40 Go de mémoire, 42) SMs
-
Appareil 1 MIG 2 g/20 Go — Charges de travail moyennes (20 Go de mémoire, 28) SMs
-
Appareil MIG 1 g.10 Go 2 — Petites charges de travail (10 Go de mémoire, 14) SMs
-
Appareil MIG 1 g.10 Go 3 — Petites charges de travail (10 Go de mémoire, 14) SMs
-
-
GPU 1 : NVIDIA A100- -80 GO SXM4
-
Dispositif MIG 3g.40gb 0 — Disposition de partition identique
-
Appareil MIG 2g.20gb 1
-
Appareil MIG 1g.10gb 2
-
Appareil MIG 1g.10gb 3
-
-
GPU 2 et GPU 3 : même schéma que le GPU 0 et le GPU 1
-
-
Complet GPUs (4-7) : pas de partitionnement MIG
-
GPU 4 : NVIDIA A100- SXM4 -80 Go — GPU complet de 80 Go
-
GPU 5 : NVIDIA A100- SXM4 -80 Go — GPU complet de 80 Go
-
GPU 6 : NVIDIA A100- SXM4 -80 Go — GPU complet de 80 Go
-
GPU 7 : NVIDIA A100- SXM4 -80 Go — GPU complet de 80 Go
-
Une fois que l'opérateur GPU NVIDIA a créé les partitions MIG, le pilote NVIDIA DRA détecte automatiquement ces instances isolées du matériel et les rend disponibles pour une allocation dynamique des ressources dans Kubernetes. Le pilote DRA découvre chaque instance MIG avec son profil spécifique (1g.10 Go, 2g.20 Go, 3g.40 Go) et les expose en tant que ressources planifiables via la classe de périphérique. mig.nvidia.com
Le pilote DRA surveille en permanence la topologie MIG et tient à jour un inventaire des instances disponibles dans l'ensemble. GPUs Lorsqu'un Pod demande un profil MIG spécifique via unResourceClaimTemplate, le pilote DRA sélectionne intelligemment une instance MIG appropriée à partir de n'importe quel GPU disponible, permettant ainsi une véritable mutualisation au niveau du matériel. Cette allocation dynamique permet à plusieurs charges de travail isolées de s'exécuter simultanément sur le même GPU physique tout en maintenant des limites de ressources strictes et des garanties de performances.
Étape 2 : Tester l'allocation des ressources MIG
Passons maintenant à quelques exemples pour montrer comment DRA alloue dynamiquement des instances MIG à différentes charges de travail. Déployez resourceclaimtemplates et testez les pods pour voir comment le pilote DRA répartit les charges de travail entre les partitions MIG disponibles, permettant ainsi à plusieurs conteneurs de partager les ressources du GPU avec une isolation au niveau du matériel.
-
Créez
mig-claim-template.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 pilote DRA.
-
Consultez les journaux du pilote DRA Pod et vous verrez un résultat similaire à celui-ci :
I0717 21:50:22.925811 1 driver.go:87] NodePrepareResource is called: number of claims: 1 I0717 21:50:22.932499 1 driver.go:129] Returning newly prepared devices for claim '933e9c72-6fd6-49c5-933c-a896407dc6d1': [&Device{RequestNames:[mig-large],PoolName:ip-100-64-173-145.ec2.internal,DeviceName:gpu-0-mig-9-4-4,CDIDeviceIDs:[k8s.gpu.nvidia.com/device=**gpu-0-mig-9-4-4**],}] I0717 21:50:23.186472 1 driver.go:87] NodePrepareResource is called: number of claims: 1 I0717 21:50:23.191226 1 driver.go:129] Returning newly prepared devices for claim '61e5ddd2-8c2e-4c19-93ae-d317fecb44a4': [&Device{RequestNames:[mig-medium],PoolName:ip-100-64-173-145.ec2.internal,DeviceName:gpu-2-mig-14-0-2,CDIDeviceIDs:[k8s.gpu.nvidia.com/device=**gpu-2-mig-14-0-2**],}] I0717 21:50:23.450024 1 driver.go:87] NodePrepareResource is called: number of claims: 1 I0717 21:50:23.455991 1 driver.go:129] Returning newly prepared devices for claim '1eda9b2c-2ea6-401e-96d0-90e9b3c111b5': [&Device{RequestNames:[mig-small],PoolName:ip-100-64-173-145.ec2.internal,DeviceName:gpu-1-mig-19-2-1,CDIDeviceIDs:[k8s.gpu.nvidia.com/device=**gpu-1-mig-19-2-1**],}] -
Vérifiez le
resourceclaimspour connaître 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 sont passés de « 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 de GB2 00 instances P6e
L'IMEX (Internode Memory Exchange) permet une communication cohérente en mémoire entre les nœuds pour un entraînement distribué sur NVIDIA 00. GB2 UltraServers
Procédez comme suit.
-
Définissez un
ComputeDomainpour l'entraînement multi-nœuds avec un fichier nomméimex-compute-domain.yaml:apiVersion: resource.nvidia.com/v1beta1 kind: ComputeDomain metadata: name: distributed-training-domain namespace: default spec: numNodes: 2 channel: resourceClaimTemplate: name: imex-channel-template -
Définissez un Pod en utilisant les canaux IMEX avec un fichier nommé
imex-pod.yaml:apiVersion: v1 kind: Pod metadata: name: imex-distributed-training namespace: default labels: app: imex-training spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: nvidia.com/gpu.clique operator: Exists containers: - name: distributed-training image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["bash", "-c"] args: - | echo "=== IMEX Channel Verification ===" ls -la /dev/nvidia-caps-imex-channels/ echo "" echo "=== GPU Information ===" nvidia-smi echo "" echo "=== NCCL Test (if available) ===" python -c " import torch import torch.distributed as dist import os print(f'CUDA available: {torch.cuda.is_available()}') print(f'CUDA device count: {torch.cuda.device_count()}') if torch.cuda.is_available(): for i in range(torch.cuda.device_count()): print(f'GPU {i}: {torch.cuda.get_device_name(i)}') # Check for IMEX environment variables imex_vars = [k for k in os.environ.keys() if 'IMEX' in k or 'NVLINK' in k] if imex_vars: print('IMEX Environment Variables:') for var in imex_vars: print(f' {var}={os.environ[var]}') print('IMEX channel verification completed') " # Keep container running for inspection sleep 3600 resources: claims: - name: imex-channel-0 - name: imex-channel-1 resourceClaims: - name: imex-channel-0 resourceClaimTemplateName: imex-channel-template - name: imex-channel-1 resourceClaimTemplateName: imex-channel-template tolerations: - key: nvidia.com/gpu operator: Exists effect: NoScheduleNote
Cela nécessite des instances P6e GB2 00.
-
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 daemon IMEX.
kubectl get pods -n nvidia-dra-driver -l resource.nvidia.com/computeDomain -
Vérifiez les canaux IMEX dans le Pod :
kubectl exec imex-distributed-training -- ls -la /dev/nvidia-caps-imex-channels/ -
Consultez les journaux du Pod :
kubectl logs imex-distributed-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