Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.
Berechnung und Autoscaling
Optimierung der GPU-Ressourcen und Kostenmanagement
Planen Sie Workloads mit GPU-Anforderungen mithilfe von bekannten Labels
Für AI/ML Workloads, die empfindlich auf unterschiedliche GPU-Merkmale reagieren (z. B. GPU, GPU-Speicher), empfehlen wir, die GPU-Anforderungen anhand bekannter Scheduling-Labels
Beispiel
Verwenden Sie beispielsweise den GPU-Namen-Node-Selektor, wenn Sie Karpenter verwenden:
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
Verwenden Sie das Kubernetes Device Plugin für die Bereitstellung GPUs
Für die Bereitstellung GPUs auf Knoten muss der NVIDIA-GPU-Treiber auf dem Betriebssystem des Knotens installiert und die Container-Laufzeit so konfiguriert sein, dass der Kubernetes-Scheduler Pods Knoten zuweisen kann, auf denen sie verfügbar sind. GPUs Der Einrichtungsprozess für das NVIDIA Kubernetes Device Plugin hängt vom verwendeten EKS Accelerated AMI ab:
-
Bottlerocket Accelerated AMI: Dieses AMI beinhaltet den NVIDIA-GPU-Treiber und das NVIDIA Kubernetes Device Plugin
ist vorinstalliert und sofort einsatzbereit, sodass GPU-Unterstützung sofort verfügbar ist. Für die Bereitstellung im Kubernetes-Scheduler ist keine zusätzliche Konfiguration erforderlich. GPUs -
AL2023 Beschleunigtes AMI
: Dieses AMI enthält den NVIDIA-GPU-Treiber, aber das NVIDIA Kubernetes Device Plugin ist nicht vorinstalliert. Sie müssen das Geräte-Plugin separat installieren und konfigurieren, in der Regel über ein. DaemonSet Beachten Sie, dass, wenn Sie eksctl verwenden, um Ihren Cluster zu erstellen und einen GPU-Instanztyp (z. B. g5.xlarge
) in Ihrem angeben ClusterConfig,eksctl
automatisch das beschleunigte AMI ausgewählt und das NVIDIA Kubernetes Device Plugin auf jeder Instanz in der Knotengruppe installiert wird. Weitere Informationen finden Sie unter GPU-Unterstützungin der eksctl-Dokumentation.
Führen Sie folgenden Befehl aus, um zu überprüfen, ob das NVIDIA-Geräte-Plug-In aktiv ist und GPUs korrekt angezeigt wird:
kubectl describe node | grep nvidia.com/gpu
Dieser Befehl überprüft, ob die nvidia.com/gpu
Ressource die Kapazität des Knotens und die zuweisbaren Ressourcen erfüllt. Zum Beispiel sollte ein Knoten mit einer GPU angezeigt werden. nvidia.com/gpu: 1
Weitere Informationen finden Sie im Kubernetes GPU Scheduling Guide
Verwenden Sie ML Capacity Blocks für die Kapazitätssicherung von P- und Trainium-Instanzen
Mit Kapazitätsblöcken für ML können Sie sehr gefragte GPU-Instances, insbesondere P-Instances (z. B. p6-b200, p5, p5e, p5en, p4d, p4de) und Trainium-Instances (z. B. trn1, trn2), reservieren, um entweder fast sofort oder zu einem future Zeitpunkt zu starten, um Ihre kurzfristigen Machine Learning-Workloads (ML) zu unterstützen. Diese Reservierungen sind ideal, um die Kapazität für rechenintensive Aufgaben wie Modelltraining und Feinabstimmung sicherzustellen. EC2 Die Preise für Capacity Blocks setzen sich aus einer Reservierungsgebühr und einer Betriebssystemgebühr zusammen. Weitere Informationen zur Preisgestaltung finden Sie unter Preise für EC2 Kapazitätsblöcke für ML
Um AI/ML Workloads auf Amazon EKS GPUs für eine vorhersehbare Kapazitätssicherung zu reservieren, empfehlen wir die Nutzung von ML-Kapazitätsblöcken für kurzfristige oder On-Demand-Kapazitätsreservierungen (ODCRs) zur allgemeinen Kapazitätssicherung.
-
ODCRs ermöglichen es Ihnen, EC2 Instance-Kapazität (z. B. GPU-Instances wie g5 oder p5) in einer bestimmten Availability Zone für einen bestimmten Zeitraum zu reservieren und so die Verfügbarkeit auch bei hoher Nachfrage sicherzustellen. ODCRs Sie haben kein langfristiges Abonnement, aber Sie zahlen den On-Demand-Tarif für die reservierte Kapazität, unabhängig davon, ob sie genutzt oder nicht genutzt wird. In EKS ODCRs werden Knotentypen wie Karpenter
und verwaltete Knotengruppen unterstützt. Um ODCRs in Karpenter Prioritäten zu setzen, konfigurieren Sie das Feld so, dass es verwendet wird NodeClass . capacityReservationSelectorTerms
Weitere Informationen finden Sie in der Karpenter Dokumentation. NodePools -
Kapazitätsblöcke sind ein spezieller Reservierungsmechanismus für GPU- (z. B. p5, p4d) oder Trainium-Instances (trn1, trn2), der für kurzfristige ML-Workloads wie Modelltraining, Feinabstimmung oder Experimente konzipiert wurde. Sie reservieren Kapazität für einen bestimmten Zeitraum (in der Regel 24 Stunden bis 182 Tage), der an einem future Datum beginnt, und zahlen nur für die reservierte Zeit. Sie sind im Voraus bezahlt, erfordern eine vorherige Planung des Kapazitätsbedarfs und unterstützen keine automatische Skalierung. Sie sind jedoch für Netzwerke mit niedriger Latenz vorgesehen. EC2 UltraClusters Sie berechnen nur für den reservierten Zeitraum. Weitere Informationen finden Sie unter Suchen und Kaufen von Kapazitätsblöcken oder richten Sie zunächst verwaltete Knotengruppen mit Kapazitätsblöcken ein. Folgen Sie dabei den Anweisungen unter Erstellen einer verwalteten Knotengruppe mit Kapazitätsblöcken für ML.
Reservieren Sie Kapazität über die AWS-Managementkonsole und konfigurieren Sie Ihre Knoten für die Verwendung von ML-Kapazitätsblöcken. Planen Sie Reservierungen auf der Grundlage von Workload-Zeitplänen und testen Sie sie in einem Staging-Cluster. Weitere Informationen finden Sie in der Dokumentation zu Kapazitätsblöcken.
Erwägen Sie On-Demand-, Amazon EC2 Spot- oder On-Demand-Kapazitätsreservierungen (ODCRs) für G EC2 Amazon-Instances
Beachten Sie bei G EC2 Amazon-Instances die verschiedenen Kaufoptionen On-Demand, Amazon EC2 Spot-Instances und On-Demand-Kapazitätsreservierungen. ODCRsermöglichen es Ihnen, EC2 Instance-Kapazität in einer bestimmten Availability Zone für einen bestimmten Zeitraum zu reservieren und so die Verfügbarkeit auch bei hoher Nachfrage sicherzustellen. Im Gegensatz zu ML Capacity Blocks, die nur für P- und Trainium-Instances verfügbar sind, ODCRs können sie für ein breiteres Spektrum von Instance-Typen, einschließlich G-Instances, verwendet werden. Dadurch eignen sie sich für Workloads, die unterschiedliche GPU-Fähigkeiten wie Inferenz oder Grafik erfordern. Bei der Verwendung von Amazon EC2 Spot-Instances ist die Möglichkeit, zwischen verschiedenen Instance-Typen, Größen und Verfügbarkeitszonen zu variieren, entscheidend, um länger vor Ort bleiben zu können.
ODCRs Sie haben keine langfristige Bindung, aber Sie zahlen den On-Demand-Tarif für die reservierte Kapazität, unabhängig davon, ob sie genutzt oder nicht genutzt wird. ODCRs kann für die sofortige Nutzung erstellt oder für einen future Zeitpunkt geplant werden, was Flexibilität bei der Kapazitätsplanung bietet. In Amazon EKS ODCRs werden sie von Knotentypen wie KarpentercapacityReservationSelectorTerms
Weitere Informationen finden Sie in der Karpenter Dokumentation. NodePools
Ziehen Sie andere beschleunigte Instance-Typen und -Größen in Betracht
Die Auswahl der geeigneten beschleunigten Instance und Größe ist entscheidend für die Optimierung von Leistung und Kosten Ihrer ML-Workloads auf Amazon EKS. Beispielsweise verfügen verschiedene GPU-Instance-Familien über unterschiedliche Leistungen und Funktionen, z. B. GPU-Speicher. Um Ihnen bei der Auswahl der Option mit dem besten Preis-Leistungs-Verhältnis zu helfen, sehen Sie sich die verfügbaren GPU-Instances auf der Seite EC2 Instance-Typen
Wenn Sie eine GPU-Instanz in einem EKS-Knoten verwenden, befindet sich der nvidia-device-plugin-daemonset
Pod standardmäßig im kube-system
Namespace. Um einen schnellen Eindruck davon zu bekommen, ob Sie die GPU (s) in Ihrer Instanz vollständig nutzen, können Sie 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
-
Wenn der
utilization.memory
Wert nahe bei 100% liegt, sind Ihr (e) Code (s) wahrscheinlich speichergebunden. Dies bedeutet, dass die GPU (Speicher) voll ausgelastet ist, könnte aber darauf hindeuten, dass weitere Leistungsoptimierungen untersucht werden sollten. -
Wenn der nahe bei 100%
utilization.gpu
liegt, bedeutet dies nicht unbedingt, dass die GPU voll ausgelastet ist. Eine bessere Metrik, die man sich ansehen sollte, ist das Verhältnis vonpower.draw
zupower.limit
. Wenn dieses Verhältnis 100% oder mehr beträgt, nutzen Ihre Codes die Rechenkapazität der GPU vollständig aus. -
Die
-l 5
Flagge besagt, dass die Metriken alle 5 Sekunden ausgegeben werden sollen. Im Fall eines einzelnen GPU-Instanztyps wird das Indexabfrageflag nicht benötigt.
Weitere Informationen finden Sie unter GPU-Instances in der AWS-Dokumentation.
Optimieren Sie die GPU-Ressourcenzuweisung mit Time-Slicing, MIG und fraktionierter GPU-Zuweisung
Statische Ressourcenbeschränkungen in Kubernetes (z. B. CPU-, Arbeitsspeicher-, GPU-Anzahl) können zu einer Über- oder Unterauslastung führen, insbesondere bei dynamischen Workloads wie Inferenz. AI/ML Die Auswahl der richtigen GPU ist wichtig. Bei Workloads mit geringem Volumen oder hoher Auslastung ermöglicht Time-Slicing, dass sich mehrere Workloads eine einzelne GPU teilen, indem sie ihre Rechenressourcen gemeinsam nutzen, was potenziell die Effizienz verbessert und Verschwendung reduziert. Die gemeinsame Nutzung der GPU kann über verschiedene Optionen erreicht werden:
-
Nutzen Sie die Knotenauswahl und die Knotenaffinität, um die Planung zu beeinflussen: Stellen Sie sicher, dass die bereitgestellten Knoten und Pods auf den GPUs für die Arbeitslast geeigneten Knoten und Pods eingeplant werden (z. B.
karpenter.k8s.aws/instance-gpu-name: "a100"
-
Time-Slicing: Plant Workloads so, dass sie die Rechenressourcen einer GPU im Laufe der Zeit gemeinsam nutzen, was eine gleichzeitige Ausführung ohne physische Partitionierung ermöglicht. Dies ist ideal für Workloads mit variablem Rechenbedarf, aber möglicherweise fehlt es an Speicherisolierung.
-
Multi-Instance-GPU (MIG): MIG ermöglicht die Partitionierung einer einzelnen NVIDIA-GPU in mehrere isolierte Instanzen und wird von NVIDIA Ampere (z. B. A100-GPU), NVIDIA Hopper (z. B. H100-GPU) und NVIDIA Blackwell (z. B. Blackwell) unterstützt. GPUs GPUs Jede MIG-Instanz erhält dedizierte Rechen- und Speicherressourcen und ermöglicht so die gemeinsame Nutzung von Ressourcen in Umgebungen mit mehreren Mandanten oder Workloads, für die Ressourcengarantien erforderlich sind. Dadurch können Sie die GPU-Ressourcennutzung optimieren, einschließlich Szenarien wie der Bereitstellung mehrerer Modelle mit unterschiedlichen Batchgrößen durch Timeslicing.
-
Teilweise GPU-Zuweisung: Nutzt softwarebasiertes Scheduling, um Teile der Rechenleistung oder des Speichers einer GPU Workloads zuzuweisen, was Flexibilität für dynamische Workloads bietet. Der NVIDIA KAI Scheduler
, Teil der Run:AI-Plattform, ermöglicht dies, indem er es Pods ermöglicht, fraktionierte GPU-Ressourcen anzufordern.
Um diese Funktionen in EKS zu aktivieren, können Sie das NVIDIA Device Plugin einsetzen, das GPUs als planbare Ressourcen verfügbar ist und Time-Slicing und MIG unterstützt. Weitere Informationen finden Sie unter Time-Slicing GPUs in Kubernetes
Beispiel
Um beispielsweise Time-Slicing mit dem NVIDIA Device Plugin zu aktivieren, gehen Sie wie folgt vor:
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
Beispiel
Um beispielsweise den KAI Scheduler für die fraktionierte GPU-Zuweisung zu verwenden, stellen Sie ihn zusammen mit dem NVIDIA-GPU-Operator bereit und geben Sie fraktionierte GPU-Ressourcen in der Pod-Spezifikation an:
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
Knotenausfallsicherheit und Verwaltung von Schulungsaufträgen
Implementieren Sie Node Health Checks mit automatisierter Wiederherstellung
Bei verteilten Trainingsaufgaben auf Amazon EKS, die eine häufige Kommunikation zwischen den Knoten erfordern, wie z. B. das Training mehrerer GPU-Modelle über mehrere Knoten hinweg, können Hardwareprobleme wie GPU- oder EFA-Ausfälle zu Unterbrechungen der Trainingsaufgaben führen. Diese Störungen können zum Verlust von Trainingsfortschritten und zu höheren Kosten führen, insbesondere bei lang andauernden AI/ML Workloads, die auf stabiler Hardware basieren.
Um die Widerstandsfähigkeit gegen Hardwarefehler zu erhöhen, wie z. B. GPU-Ausfälle in EKS-Clustern, auf denen GPU-Workloads ausgeführt werden, empfehlen wir, entweder den EKS Node Monitoring Agent mit Auto Repair oder Amazon zu nutzen. SageMaker HyperPod Der EKS Node Monitoring Agent with Auto Repair bietet Funktionen wie die Überwachung des Knotenzustands und die automatische Reparatur mithilfe von Kubernetes-Standardmechanismen, SageMaker HyperPod bietet gezielte Resilienz und zusätzliche Funktionen, die speziell für groß angelegte ML-Trainings entwickelt wurden, wie z. B. eingehende Gesundheitschecks und automatische Wiederaufnahme von Jobs.
-
Der EKS Node Monitoring Agent mit Node Auto Repair überwacht kontinuierlich den Zustand der Knoten NodeConditions, liest Protokolle und wendet Standardbedingungen wie
Ready
und spezifische Bedingungen für beschleunigte Hardware an, um Probleme wie GPU- oder Netzwerkausfälle zu identifizieren. Wenn ein Knoten als fehlerhaft eingestuft wird, sperrt Node Auto Repair ihn ab und ersetzt ihn durch einen neuen Knoten. Die Neuplanung von Pods und der Neustart von Jobs basieren auf den Standardmechanismen von Kubernetes und der Neustartrichtlinie des Jobs. -
Der Agent für SageMaker HyperPod
eingehende Integritätsprüfungen und die Zustandsüberwachung überwacht kontinuierlich den Integritätsstatus von GPU- und Trainium-basierten Instances. Er ist auf AI/ML Workloads zugeschnitten und verwendet Labels (z. B.) zur Verwaltung des Knotenzustands. node-health-status Wenn ein Knoten als fehlerhaft eingestuft wird, wird der automatische Austausch der fehlerhaften Hardware HyperPod ausgelöst, z. B. GPUs Es erkennt standardmäßig netzwerkbedingte Ausfälle für EFA durch seine grundlegenden Integritätsprüfungen und unterstützt die automatische Wiederaufnahme unterbrochener Trainingsjobs, sodass Jobs ab dem letzten Checkpoint fortgesetzt werden können, wodurch Unterbrechungen bei umfangreichen ML-Aufgaben minimiert werden.
Stellen Sie sowohl für EKS Node Monitoring Agent mit Auto Repair als auch für SageMaker HyperPod Cluster, die EFA verwenden, zur Überwachung EFA-spezifischer Metriken wie Remote Direct Memory Access (RDMA) -Fehler und Paketabbrüche sicher, dass der AWS EFA-Treiber installiert ist. Darüber hinaus empfehlen wir, das CloudWatch Observability Add-on einzusetzen oder Tools wie DCGM Exporter mit Prometheus und Grafana zu verwenden, um EFA, GPU und damit spezifische Metriken im Zusammenhang mit seinen Funktionen zu überwachen. SageMaker HyperPod
Deaktivieren Sie Karpenter Consolidation für unterbrechungssensitive Workloads
Für Workloads, die empfindlich auf Unterbrechungen reagieren, wie etwa bei der Verarbeitung, umfangreichen AI/ML Prognoseaufgaben oder Schulungen, empfehlen wir, die Konsolidierungsrichtlinien von Karpenter zu optimieren, um Unterbrechungen bei der Auftragsausführung zu vermeiden
Die WhenEmptyOrUnderutilized
Konsolidierungsrichtlinie kann Knoten vorzeitig beenden, was zu längeren Ausführungszeiten führt. Beispielsweise können Unterbrechungen die Wiederaufnahme von Jobs verzögern, da Pods neu geplant und Daten neu geladen werden, was bei Batch-Inferenzjobs mit langer Laufzeit kostspielig sein kann. Um dies zu vermeiden, können Sie den Wert consolidationPolicy
auf festlegen WhenEmpty
und eine consolidateAfter
Dauer, z. B. 1 Stunde, konfigurieren, damit Knoten auch bei Arbeitslastspitzen erhalten bleiben. Zum Beispiel:
disruption: consolidationPolicy: WhenEmpty consolidateAfter: 60m
Dieser Ansatz verbessert die Latenz beim Pod-Start bei hohen Batch-Inferenz-Workloads und anderen unterbrechungssensitiven Aufgaben, wie z. B. Online-Inferenzdatenverarbeitung in Echtzeit oder Modelltraining, bei denen die Kosten einer Unterbrechung die Einsparungen bei den Rechenkosten überwiegen. Karpenter Disruption Budgets ist eine weitere Funktion zur Verwaltung von Störungen bei KarpenterNodePool .
Verwenden Sie ttlSecondsAfter Finished, um Kubernetes-Jobs automatisch zu bereinigen
Wir empfehlen, ttlSecondsAfterFinished
für Kubernetes-Jobs in Amazon EKS so einzustellen, dass abgeschlossene Auftragsobjekte automatisch gelöscht werden. Verbleibende Auftragsobjekte verbrauchen Clusterressourcen wie API-Serverspeicher und erschweren die Überwachung durch überladene Dashboards (z. B. Grafana, Amazon). CloudWatch Wenn Sie beispielsweise eine TTL von 1 Stunde festlegen, wird sichergestellt, dass Jobs kurz nach Abschluss entfernt werden, sodass Ihr Cluster tidy bleibt. Weitere Informationen finden Sie unter Automatische Bereinigung
Job-Präemption mit niedriger Priorität für Aufträge/Workloads mit höherer Priorität konfigurieren
Für AI/ML Workloads mit gemischter Priorität auf Amazon EKS können Sie das Preemption von Jobs mit niedriger Priorität konfigurieren, um sicherzustellen, dass Aufgaben mit höherer Priorität (z. B. Echtzeit-Inferenz) umgehend Ressourcen erhalten. Ohne Präemption können Workloads mit niedriger Priorität wie Batch-Prozesse (z. B. Batch-Inferenz, Datenverarbeitung), Nicht-Batch-Dienste (z. B. Hintergrundaufgaben, Cron-Jobs) oder CPU-/speicherintensive Jobs (z. B. Webdienste) kritische Pods verzögern, indem sie Knoten belegen. Mit Preemption kann Kubernetes Pods mit niedriger Priorität entfernen, wenn Pods mit hoher Priorität Ressourcen benötigen, wodurch eine effiziente Ressourcenzuweisung auf Knoten mit, oder Speicher gewährleistet wird. GPUs CPUs Wir empfehlen die Verwendung von PriorityClass
Kubernetes, um Prioritäten zuzuweisen und das Räumungsverhalten zu kontrollieren. PodDisruptionBudget
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: low-priority value: 100 --- spec: priorityClassName: low-priority
Weitere Informationen finden Sie in der Dokumentation zu Kubernetes Priority and Preemption
Skalierung und Leistung von Anwendungen
Passen Sie die Rechenkapazität für ML-Workloads mit Karpenter oder Static Nodes an
Um kosteneffiziente und reaktionsschnelle Rechenkapazitäten für maschinelles Lernen (ML) -Workflows auf Amazon EKS sicherzustellen, empfehlen wir, Ihre Node-Bereitstellungsstrategie an die Merkmale und Kostenverpflichtungen Ihres Workloads anzupassen. Im Folgenden sind zwei Ansätze aufgeführt, die Sie in Betracht ziehen sollten: just-in-time Skalierung mit Karpenter
-
Just-in-time Datenebenen-Skalierer wie Karpenter: Für dynamische ML-Workflows mit variablen Rechenanforderungen (z. B. GPU-basierte Inferenz gefolgt von CPU-basierter Darstellung) empfehlen wir die Verwendung von Datenebenen-Skalierern wie Karpenter. just-in-time
-
Verwenden Sie statische Knotengruppen für vorhersehbare Workloads: Bei vorhersagbaren, stationären ML-Workloads oder bei der Verwendung von Reserved Instances können von EKS verwaltete Knotengruppen sicherstellen, dass reservierte Kapazität vollständig bereitgestellt und genutzt wird, wodurch die Einsparungen maximiert werden. Dieser Ansatz ist ideal für bestimmte Instance-Typen, die über oder festgeschrieben werden. RIs ODCRs
Beispiel
Dies ist ein Beispiel für ein vielseitiges Karpenter NodePoolg
EC2 Amazon-Instances ermöglicht, bei denen die Instance-Generierung mehr als drei beträgt.
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
Beispiel
Beispiel für die Verwendung statischer Knotengruppen für einen Trainings-Workload:
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
Verwenden Sie Taints und Toleranzen, um zu verhindern, dass nicht beschleunigte Workloads auf beschleunigten Instances geplant werden
Die Planung nicht beschleunigter Workloads auf GPU-Ressourcen ist nicht recheneffizient. Wir empfehlen, Taints und Toleration zu verwenden, um sicherzustellen, dass Pods für nicht beschleunigte Workloads nicht auf ungeeigneten Knoten geplant werden. Weitere Informationen finden Sie in der Kubernetes-Dokumentation.
Skalieren Sie basierend auf der Modellleistung
Für Inferenz-Workloads empfehlen wir die Verwendung von Kubernetes Event-Driven Autoscaling (KEDA) zur Skalierung auf der Grundlage von Modellleistungskennzahlen wie Inferenzanfragen oder Token-Durchsatz mit entsprechenden Abklingzeiten. Statische Skalierungsrichtlinien können zu viel oder zu wenig Ressourcen bereitstellen, was sich auf Kosten und Latenz auswirkt. Weitere Informationen finden Sie in der KEDA-Dokumentation
Dynamische Ressourcenzuweisung für erweitertes GPU-Management
Die dynamische Ressourcenzuweisung (DRA)
-
Feinkörnige GPU-Zuweisung
-
Fortschrittliche Sharing-Mechanismen wie Multi-Process Service (MPS) und Multi-Instance-GPU (MIG)
-
Support für Hardwarearchitekturen der nächsten Generation, einschließlich NVIDIA 00 GB2 UltraClusters
Herkömmliche GPU-Zuweisung behandelt Ressourcen GPUs als undurchsichtige Integer-Ressourcen, was zu einer erheblichen Unterauslastung führt (häufig 30-40% in Produktionsclustern). Dies liegt daran, dass Workloads exklusiven Zugriff auf Gesamtressourcen erhalten, GPUs auch wenn sie nur Bruchteile der Ressourcen benötigen. DRA transformiert dieses Modell, indem es eine strukturierte, deklarative Zuweisung einführt, die dem Kubernetes-Scheduler einen vollständigen Überblick über Hardwaremerkmale und Workload-Anforderungen bietet. Dies ermöglicht intelligente Platzierungsentscheidungen und eine effiziente gemeinsame Nutzung von Ressourcen.
Vorteile der Verwendung von DRA anstelle des NVIDIA-Geräte-Plugins
Das NVIDIA-Geräte-Plugin (ab Version0.12.0
) unterstützt GPU-Sharing-Mechanismen wie Time-Slicing, MPS und MIG. Es gibt jedoch architektonische Einschränkungen, die DRA behebt.
Einschränkungen des NVIDIA-Geräte-Plugins
-
Statische Konfiguration: Konfigurationen zur gemeinsamen Nutzung von GPUs (Time-Slicing-Replikate und MPS-Einstellungen) erfordern eine clusterweite Vorkonfiguration.
ConfigMaps
Dies macht es schwierig, unterschiedliche Sharing-Strategien für unterschiedliche Workloads bereitzustellen. -
Eingeschränkte detaillierte Auswahl: Das Geräte-Plug-In macht zwar GPU-Merkmale anhand von Knotenbezeichnungen verfügbar, Workloads können jedoch nicht dynamisch bestimmte GPU-Konfigurationen (Speichergröße und Rechenkapazität) als Teil der Planungsentscheidung anfordern.
-
Keine knotenübergreifende Ressourcenkoordination: Es ist nicht möglich, verteilte GPU-Ressourcen über mehrere Knoten zu verwalten oder komplexe Topologieanforderungen wie NVLink Domänen für Systeme wie NVIDIA 00 zu formulieren. GB2
-
Scheduler-Einschränkungen: Der Kubernetes-Scheduler behandelt GPU-Ressourcen als undurchsichtige Ganzzahlen, was seine Fähigkeit einschränkt, topologiebewusste Entscheidungen zu treffen oder komplexe Ressourcenabhängigkeiten zu handhaben.
-
Komplexität der Konfiguration: Die Einrichtung verschiedener Strategien zur gemeinsamen Nutzung erfordert mehrere
ConfigMaps
und sorgfältige Knotenkennzeichnungen, was zu betrieblicher Komplexität führt.
Lösungen mit DRA
-
Dynamische Ressourcenauswahl: Mit DRA können Workloads detaillierte Anforderungen (GPU-Speicher, Treiberversionen und spezifische Attribute) zum Zeitpunkt der Anfrage angeben.
resourceclaims
Dies ermöglicht einen flexibleren Ressourcenabgleich. -
Topologiebewusstsein: Durch strukturierte Parameter und Geräteauswahlen bewältigt DRA komplexe Anforderungen wie knotenübergreifende GPU-Kommunikation und speicherkohärente Verbindungen.
-
Knotenübergreifendes Ressourcenmanagement:
computeDomains
ermöglicht die Koordination verteilter GPU-Ressourcen auf mehrere Knoten, was für Systeme wie 00 mit IMEX-Kanälen von entscheidender Bedeutung ist. GB2 -
Workload-spezifische Konfiguration: Jede Konfiguration
ResourceClaim
spezifiziert unterschiedliche Strategien und Konfigurationen für die gemeinsame Nutzung und ermöglicht so eine feinkörnige Steuerung pro Workload anstelle von clusterweiten Einstellungen. -
Verbesserte Scheduler-Integration: DRA stellt dem Scheduler detaillierte Geräteinformationen zur Verfügung und ermöglicht intelligentere Platzierungsentscheidungen auf der Grundlage der Hardwaretopologie und der Ressourceneigenschaften.
Wichtig: DRA ersetzt das NVIDIA-Geräte-Plugin nicht vollständig. Der NVIDIA DRA-Treiber arbeitet zusammen mit dem Geräte-Plug-In, um erweiterte Funktionen bereitzustellen. Das Geräte-Plugin übernimmt weiterhin die grundlegende Erkennung und Verwaltung von GPUs, während DRA erweiterte Zuweisungs- und Planungsfunktionen hinzufügt.
Von DRA unterstützte Instanzen und ihre Funktionen
Die DRA-Unterstützung variiert je nach EC2 Amazon-Instance-Familie und GPU-Architektur, wie in der folgenden Tabelle dargestellt.
Instance-Familie | GPU-Typ | Zeiteinteilung | MIG-Unterstützung | MPS-Unterstützung | IMEX-Unterstützung | Anwendungsfälle |
---|---|---|---|---|---|---|
G5 |
NVIDIA A10G |
Ja |
Nein |
Ja |
Nein |
Inferenz- und Grafik-Workloads |
G6 |
NVIDIA L4 |
Ja |
Nein |
Ja |
Nein |
KI-Inferenz und Videoverarbeitung |
G6e |
NVIDIA L40S |
Ja |
Nein |
Ja |
Nein |
Training, Inferenz und Grafik |
P4d/P4de |
NVIDIA A100 |
Ja |
Ja |
Ja |
Nein |
Umfangreiches Training und HPC |
P5 |
NVIDIA H100 |
Ja |
Ja |
Ja |
Nein |
Modelltraining für die Stiftung |
P6 |
NVIDIA B200 |
Ja |
Ja |
Ja |
Nein |
Modelle mit Milliarden oder Billionen Parametern, verteiltes Training und Inferenz |
P6e |
NVIDIA 00 GB2 |
Ja |
Ja |
Ja |
Ja |
Modelle mit Milliarden oder Billionen Parametern, verteiltes Training und Inferenz |
Im Folgenden werden die einzelnen Funktionen in der Tabelle beschrieben:
-
Time-Slicing: Ermöglicht es mehreren Workloads, GPU-Rechenressourcen im Laufe der Zeit gemeinsam zu nutzen.
-
Multi-Instance-GPU (MIG): Partitionierung auf Hardwareebene, die isolierte GPU-Instanzen erstellt.
-
Multi-Process-Service (MPS): Ermöglicht die gleichzeitige Ausführung mehrerer CUDA-Prozesse auf einer einzigen GPU.
-
Internode Memory Exchange (IMEX): Speicherkohärente Kommunikation zwischen Knoten für 00. GB2 UltraClusters
Weitere Ressourcen
Weitere Informationen zu Kubernetes DRA- und NVIDIA DRA-Treibern finden Sie in den folgenden Ressourcen unter: GitHub
Richten Sie eine dynamische Ressourcenzuweisung für erweitertes GPU-Management ein
Das folgende Thema zeigt Ihnen, wie Sie die dynamische Ressourcenzuweisung (DRA) für erweitertes GPU-Management einrichten.
Voraussetzungen
Stellen Sie vor der Implementierung von DRA auf Amazon EKS sicher, dass Ihre Umgebung die folgenden Anforderungen erfüllt.
Cluster-Konfiguration
-
Amazon EKS-Cluster mit laufender Version
1.33
oder höher -
GPU-fähige NVIDIA-Worker-Knoten mit entsprechenden Instance-Typen
Erforderliche Komponenten
-
NVIDIA-Geräte-Plug-in-Version
0.17.1
oder höher -
NVIDIA DRA-Treiberversion
25.3.0
oder höher
Schritt 1: Erstellen Sie mithilfe von eksctl einen Cluster mit einer DRA-fähigen Knotengruppe
-
Erstellen Sie eine Cluster-Konfigurationsdatei mit dem Namen:
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
-
Erstellen Sie den Cluster:
eksctl create cluster -f dra-eks-cluster.yaml
Schritt 2: Stellen Sie das NVIDIA-Geräte-Plugin bereit
Stellen Sie das NVIDIA-Geräte-Plugin bereit, um die grundlegende GPU-Erkennung zu ermöglichen:
-
Fügen Sie das Helm-Repository für das NVIDIA-Geräte-Plugin hinzu:
helm repo add nvidia https://nvidia.github.io/k8s-device-plugin helm repo update
-
Erstellen Sie benutzerdefinierte Werte für das Geräte-Plugin:
cat <<EOF > nvidia-device-plugin-values.yaml gfd: enabled: true nfd: enabled: true tolerations: - key: [nvidia.com/gpu](http://nvidia.com/gpu) operator: Exists effect: NoSchedule EOF
-
Installieren Sie das NVIDIA-Geräte-Plug-In:
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
Schritt 3: Stellen Sie das Helm-Diagramm für den NVIDIA-DRA-Treiber bereit
-
Erstellen Sie eine
dra-driver-values.yaml
Wertedatei für den DRA-Treiber:--- 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
-
Fügen Sie das NVIDIA NGC Helm-Repository hinzu:
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia helm repo update
-
Installieren Sie den NVIDIA DRA-Treiber:
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
Schritt 4: Überprüfen Sie die DRA-Installation
-
Stellen Sie sicher, dass die DRA API-Ressourcen verfügbar sind:
kubectl api-resources | grep [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1)
Das Folgende ist die erwartete Ausgabe:
deviceclasses [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1) false DeviceClass resourceclaims [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1) true ResourceClaim resourceclaimtemplates [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1) true ResourceClaimTemplate resourceslices [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1) false ResourceSlice
-
Überprüfen Sie die verfügbaren Geräteklassen:
kubectl get deviceclasses
Im Folgenden finden Sie ein Beispiel für die erwartete Ausgabe:
NAME AGE compute-domain-daemon.nvidia.com 4h39m compute-domain-default-channel.nvidia.com 4h39m gpu.nvidia.com 4h39m mig.nvidia.com 4h39m
Wenn eine neu erstellte G6-GPU-Instance Ihrem Amazon EKS-Cluster mit aktiviertem DRA beitritt, werden die folgenden Aktionen ausgeführt:
-
Der NVIDIA DRA-Treiber erkennt automatisch die A10G-GPU und erstellt zwei
resourceslices
auf diesem Knoten. -
Der
gpu.nvidia.com
Slice registriert das physische A10G-GPU-Gerät mit seinen Spezifikationen (Speicher, Rechenkapazität und mehr). -
Da A10G die MIG-Partitionierung nicht unterstützt, erstellt der
compute-domain.nvidia.com
Slice eine einzelne Rechendomäne, die den gesamten Rechenkontext der GPU darstellt. -
Diese
resourceslices
werden dann auf dem Kubernetes-API-Server veröffentlicht, sodass die GPU-Ressourcen für die Planung zur Verfügung stehen.resourceclaims
Der DRA-Scheduler kann diese GPU nun intelligent Pods zuweisen, über die GPU-Ressourcen angefordert werden, was im Vergleich zu herkömmlichen
resourceclaimtemplates
Geräte-Plug-in-Ansätzen eine flexiblere Ressourcenverwaltung ermöglicht. Dies geschieht automatisch ohne manuelles Eingreifen. Der Knoten wird einfach für GPU-Workloads verfügbar, sobald der DRA-Treiber die Ressourcenerkennung und Registrierung abgeschlossen hat.Wenn Sie den folgenden Befehl ausführen:
kubectl get resourceslices
Im Folgenden finden Sie ein Beispiel für die erwartete Ausgabe:
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
-
Fahren Sie fort mit Planen Sie einen einfachen GPU-Workload mithilfe der dynamischen Ressourcenzuweisung.
Planen Sie einen einfachen GPU-Workload mithilfe der dynamischen Ressourcenzuweisung
Gehen Sie wie folgt vor, um einen einfachen GPU-Workload mithilfe der dynamischen Ressourcenzuweisung (DRA) zu planen. Bevor Sie fortfahren, stellen Sie sicher, dass Sie die folgenden Anweisungen befolgt habenRichten Sie eine dynamische Ressourcenzuweisung für erweitertes GPU-Management ein.
-
Erstellen Sie eine Grundlage
ResourceClaimTemplate
für die GPU-Zuweisung mit einer Datei mit dem Namenbasic-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
-
Wenden Sie die Vorlage an:
kubectl apply -f basic-gpu-claim-template.yaml
-
Überprüfen Sie den Status:
kubectl get resourceclaimtemplates -n gpu-test1
Das Folgende ist Ausgabebeispiel:
NAME AGE single-gpu 9m16s
-
Erstellen Sie einen Pod, der den verwendet,
ResourceClaimTemplate
mit einer Datei namensbasic-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"
-
Wenden Sie den Pod an und überwachen Sie ihn:
kubectl apply -f basic-gpu-pod.yaml
-
Überprüfen Sie den Pod-Status:
kubectl get pod -n gpu-test1
Im Folgenden finden Sie ein Beispiel für eine erwartete Ausgabe:
NAME READY STATUS RESTARTS AGE gpu-pod 1/1 Running 0 13m
-
Überprüfen Sie den
ResourceClaim
Status:kubectl get resourceclaims -n gpu-test1
Das Folgende ist ein Beispiel für eine erwartete Ausgabe:
NAME STATE AGE gpu-pod-gpu0-l76cg allocated,reserved 9m6s
-
Sehen Sie sich die Pod-Logs an, um GPU-Informationen zu sehen:
kubectl logs gpu-pod -n gpu-test1
Im Folgenden finden Sie ein Beispiel für eine erwartete Ausgabe:
GPU 0: NVIDIA L4 (UUID: GPU-da7c24d7-c7e3-ed3b-418c-bcecc32af7c5)
Weitere fortgeschrittene Techniken Techniken zur GPU-Optimierung mit dynamischer Ressourcenzuweisung zur GPU-Optimierung mithilfe von DRA finden Sie weiter.
Techniken zur GPU-Optimierung mit dynamischer Ressourcenzuweisung
Moderne GPU-Workloads erfordern ein ausgeklügeltes Ressourcenmanagement, um eine optimale Nutzung und Kosteneffizienz zu erreichen. DRA ermöglicht mehrere fortschrittliche Optimierungstechniken, die auf unterschiedliche Anwendungsfälle und Hardwarefunktionen zugeschnitten sind:
-
Time-Slicing ermöglicht es mehreren Workloads, GPU-Rechenressourcen im Laufe der Zeit gemeinsam zu nutzen, was es ideal für Inferenz-Workloads mit sporadischer GPU-Nutzung macht. Ein Beispiel finden Sie unter Optimieren Sie GPU-Workloads mit Time-Slicing.
-
Der Multi-Process Service (MPS) ermöglicht die gleichzeitige Ausführung mehrerer CUDA-Prozesse auf einer einzigen GPU mit besserer Isolierung als Time-Slicing. Ein Beispiel finden Sie unter Optimieren Sie GPU-Workloads mit MPS.
-
Die Multi-Instance-GPU (MIG) ermöglicht Partitionierung auf Hardwareebene und erstellt isolierte GPU-Instanzen mit dedizierten Rechen- und Speicherressourcen. Ein Beispiel finden Sie unter Optimieren Sie GPU-Workloads mit Multi-Instance-GPU.
-
Internode Memory Exchange (IMEX) ermöglicht eine speicherkohärente Kommunikation zwischen Knoten für verteiltes Training auf NVIDIA 00-Systemen. GB2 Ein Beispiel finden Sie unter Optimieren Sie GPU-Workloads mit IMEX mithilfe von GB2 00 P6e-Instanzen.
Diese Techniken können die Ressourcennutzung erheblich verbessern. Organizations berichten, dass die GPU-Auslastung von 30 bis 40% bei herkömmlicher Zuweisung auf 80 bis 90% bei optimierten Sharing-Strategien steigt. Die Wahl der Technik hängt von den Eigenschaften der Arbeitslast, den Isolationsanforderungen und den Hardwarefunktionen ab.
Optimieren Sie GPU-Workloads mit Time-Slicing
Time-Slicing ermöglicht es mehreren Workloads, GPU-Rechenressourcen gemeinsam zu nutzen, indem sie so geplant werden, dass sie sequentiell auf derselben physischen GPU ausgeführt werden. Es ist ideal für Inferenz-Workloads mit sporadischer GPU-Nutzung.
Führen Sie die folgenden Schritte aus.
-
Definieren Sie a
ResourceClaimTemplate
für Timeslicing mit einer Datei mit dem Namen: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
-
Definieren Sie einen Pod mithilfe von Timeslicing mit einer Datei namens:
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
-
Wenden Sie die Vorlage und den Pod an:
kubectl apply -f timeslicing-claim-template.yaml kubectl apply -f timeslicing-pod.yaml
-
Ressourcenansprüche überwachen:
kubectl get resourceclaims -n timeslicing-gpu -w
Das Folgende ist Ausgabebeispiel:
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
Erster Pod (inference-pod-1
)
-
Bundesland:
allocated,reserved
-
Das heißt: DRA hat eine verfügbare GPU gefunden und sie für diesen Pod reserviert
-
Pod-Status: Startet sofort
Zweiter Pod (training-pod-2
)
-
Bundesland:
pending
-
Das heißt: Ich warte darauf, dass DRA Time-Slicing auf derselben GPU konfiguriert
-
Pod-Status: Wartet darauf, geplant zu werden
-
Der Status wird von bis
pending
allocated,reserved
zu wechselnrunning
Optimieren Sie GPU-Workloads mit MPS
Multi-Process Service (MPS) ermöglicht die gleichzeitige Ausführung mehrerer CUDA-Kontexte auf einer einzigen GPU mit besserer Isolierung als Time-Slicing.
Führen Sie die folgenden Schritte aus.
-
Definieren Sie a
ResourceClaimTemplate
für MPS mit einer Datei namensmps-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
-
Definieren Sie einen Pod mithilfe von MPS mit einer Datei namens
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
-
Wenden Sie die Vorlage an und erstellen Sie mehrere MPS-Pods:
kubectl apply -f mps-claim-template.yaml kubectl apply -f mps-pod.yaml
-
Überwachen Sie die Ressourcenansprüche:
kubectl get resourceclaims -n mps-gpu -w
Das Folgende ist Ausgabebeispiel:
NAME STATE AGE mps-multi-container-pod-shared-gpu-claim-2p9kx allocated,reserved 86s
Diese Konfiguration demonstriert echte GPU-Sharing mithilfe von NVIDIA Multi-Process Service (MPS) durch dynamische Ressourcenzuweisung (DRA). Im Gegensatz zum Time-Slicing, bei dem Workloads die GPU nacheinander verwenden, ermöglicht MPS, dass beide Container gleichzeitig auf derselben physischen GPU ausgeführt werden. Die wichtigste Erkenntnis ist, dass die gemeinsame Nutzung von DRA MPS mehrere Container innerhalb eines einzigen Pods erfordert, nicht mehrere separate Pods. Bei der Bereitstellung weist der DRA-Treiber dem Pod einen ResourceClaim
zu und konfiguriert MPS automatisch so, dass sowohl der Inferenz- als auch der Trainingscontainer gleichzeitig ausgeführt werden können.
Jeder Container erhält seinen eigenen isolierten GPU-Speicherplatz und eigene Rechenressourcen, wobei der MPS-Daemon den Zugriff auf die zugrunde liegende Hardware koordiniert. Sie können überprüfen, ob dies funktioniert, indem Sie wie folgt vorgehen:
-
Überprüfung
nvidia-smi
, wodurch beide Container als M+C (MPS + Compute
) -Prozesse angezeigt werden, die sich dasselbe GPU-Gerät teilen. -
Überwachung der Logs aus beiden Containern, wobei verschachtelte Zeitstempel angezeigt werden, die die gleichzeitige Ausführung belegen.
Dieser Ansatz maximiert die GPU-Auslastung, indem ergänzende Workloads die teure GPU-Hardware effizient gemeinsam nutzen können, anstatt sie durch einen einzelnen Prozess ungenutzt zu lassen.
Behälter 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 |
+-----------------------------------------------------------------------------------------+
Behälter 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 |
+-----------------------------------------------------------------------------------------+
Optimieren Sie GPU-Workloads mit Multi-Instance-GPU
Die Multi-Instance-GPU (MIG) ermöglicht Partitionierung auf Hardwareebene und erstellt isolierte GPU-Instanzen mit dedizierten Rechen- und Speicherressourcen.
Für die Verwendung der dynamischen MIG-Partitionierung mit verschiedenen Profilen ist der NVIDIA-GPU-Operator erforderlich.WITH0—REBOOT=true
in der MIG Manager-Konfiguration für erfolgreiche MIG-Bereitstellungen unerlässlich.
Sie benötigen sowohl den NVIDIA DRA-Treiber
Schritt 1: Stellen Sie NVIDIA GPU Operator bereit
-
Fügen Sie das NVIDIA GPU Operator-Repository hinzu:
helm repo add nvidia https://nvidia.github.io/gpu-operator helm repo update
-
Erstellen Sie eine
gpu-operator-values.yaml
Datei: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
-
Installieren Sie GPU Operator mithilfe der
gpu-operator-values.yaml
folgenden Datei:helm install gpu-operator nvidia/gpu-operator \ --namespace gpu-operator \ --create-namespace \ --version v25.3.1 \ --values gpu-operator-values.yaml
Dieses Helm-Diagramm stellt die folgenden Komponenten und mehrere MIG-Profile bereit:
-
Geräte-Plugin (GPU-Ressourcenplanung)
-
DCGM Exporter (GPU-Metriken und Überwachung)
-
Erkennung von Knotenmerkmalen (NFD — Hardwarekennzeichnung)
-
GPU Feature Discovery (GFD — GPU-spezifische Kennzeichnung)
-
MIG Manager (GPU-Partitionierung mit mehreren Instanzen)
-
Container-Toolkit (GPU-Container-Laufzeit)
-
Operator Controller (Lebenszyklusmanagement)
-
-
Überprüfen Sie die Bereitstellungs-Pods:
kubectl get pods -n gpu-operator
Das Folgende ist Ausgabebeispiel:
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
-
Erstellen Sie einen Amazon EKS-Cluster mit einer von P4de verwalteten Knotengruppe, um die MIG-Beispiele zu testen:
apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: dra-eks-cluster region: us-east-1 version: '1.33' managedNodeGroups: # P4DE MIG Node Group with Capacity Block Reservation - name: p4de-mig-nodes amiFamily: AmazonLinux2023 instanceType: p4de.24xlarge # Capacity settings desiredCapacity: 0 minSize: 0 maxSize: 1 # Use specific subnet in us-east-1b for capacity reservation subnets: - us-east-1b # AL2023 NodeConfig for RAID0 local storage only nodeadmConfig: apiVersion: node.eks.aws/v1alpha1 kind: NodeConfig spec: instance: localStorage: strategy: RAID0 # Node labels for MIG configuration labels: nvidia.com/gpu.present: "true" nvidia.com/gpu.product: "A100-SXM4-80GB" nvidia.com/mig.config: "p4de-half-balanced" node-type: "p4de" vpc.amazonaws.com/efa.present: "true" accelerator: "nvidia" # Node taints taints: - key: nvidia.com/gpu value: "true" effect: NoSchedule # EFA support efaEnabled: true # Placement group for high-performance networking placementGroup: groupName: p4de-placement-group strategy: cluster # Capacity Block Reservation (CBR) # Ensure CBR ID matches the subnet AZ with the Nodegroup subnet spot: false capacityReservation: capacityReservationTarget: capacityReservationId: "cr-abcdefghij" # Replace with your capacity reservation ID
NVIDIA GPU Operator verwendet das Label, das den Knoten hinzugefügt wurde,
nvidia.com/mig.config: "p4de-half-balanced"
und partitioniert die GPU mit dem angegebenen Profil. -
Melden Sie sich bei der
p4de
Instanz an. -
Führen Sie den folgenden Befehl aus:
nvidia-smi -L
Sie sollten die folgende Beispielausgabe sehen:
[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 hat das p4de-half-balanced
MIG-Profil erfolgreich auf Ihre P4DE-Instanz angewendet und dabei wie konfiguriert GPU-Partitionen auf Hardwareebene erstellt. So funktioniert die Partitionierung:
Der GPU-Operator hat diese Konfiguration aus Ihrem eingebetteten MIG-Profil übernommen:
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
Aus Ihrer nvidia-smi -L
Ausgabe hat der GPU-Operator Folgendes erstellt:
-
MIG-fähig GPUs (0-3): Hardware partitioniert
-
GPU 0: NVIDIA A100- -80 GB SXM4
-
MIG 3G.40 GB Gerät 0 — Große Arbeitslasten (40 GB Speicher, 42) SMs
-
MIG 2G.20 GB Gerät 1 — Mittlere Arbeitslasten (20 GB Speicher, 28) SMs
-
MIG 1g.10gb Gerät 2 — Kleine Workloads (10 GB Speicher, 14) SMs
-
MIG 1G.10GB Gerät 3 — Kleine Workloads (10 GB Speicher, 14) SMs
-
-
GPU 1: NVIDIA A100-80 GB SXM4
-
MIG 3G.40gb Gerät 0 — Identisches Partitionslayout
-
MIG 2g.20gb Gerät 1
-
MIG 1g.10gb Gerät 2
-
MIG 1g.10gb Gerät 3
-
-
GPU 2 und GPU 3 — Gleiches Muster wie GPU 0 und GPU 1
-
-
Vollständig GPUs (4-7): Keine MIG-Partitionierung
-
GPU 4: NVIDIA A100-80 GB — Vollständige SXM4 80-GB-GPU
-
GPU 5: NVIDIA A100- SXM4 -80 GB — Vollständige 80-GB-GPU
-
GPU 6: NVIDIA A100- SXM4 -80 GB — Vollständige 80-GB-GPU
-
GPU 7: NVIDIA A100- SXM4 -80 GB — Vollständige 80-GB-GPU
-
Sobald der NVIDIA-GPU-Operator die MIG-Partitionen erstellt hat, erkennt der NVIDIA DRA-Treiber diese hardwareisolierten Instanzen automatisch und stellt sie für die dynamische Ressourcenzuweisung in Kubernetes zur Verfügung. Der DRA-Treiber erkennt jede MIG-Instanz mit ihrem spezifischen Profil (1G.10 GB, 2G.20 GB, 3G.40 GB) und stellt sie über die Geräteklasse als planbare Ressourcen zur Verfügung. mig.nvidia.com
Der DRA-Treiber überwacht kontinuierlich die MIG-Topologie und führt eine Bestandsaufnahme aller verfügbaren Instanzen. GPUs Wenn ein Pod über ein ein bestimmtes MIG-Profil anfordertResourceClaimTemplate
, wählt der DRA-Treiber auf intelligente Weise eine geeignete MIG-Instanz aus jeder verfügbaren GPU aus und ermöglicht so eine echte Mehrmandantenfähigkeit auf Hardwareebene. Durch diese dynamische Zuweisung können mehrere isolierte Workloads gleichzeitig auf derselben physischen GPU ausgeführt werden, wobei strenge Ressourcengrenzen und Leistungsgarantien eingehalten werden.
Schritt 2: Testen Sie die MIG-Ressourcenzuweisung
Lassen Sie uns nun anhand einiger Beispiele demonstrieren, wie DRA MIG-Instanzen dynamisch verschiedenen Workloads zuweist. Stellen Sie die Pods bereit resourceclaimtemplates
und testen Sie sie, um zu sehen, wie der DRA-Treiber Workloads auf die verfügbaren MIG-Partitionen verteilt, sodass mehrere Container GPU-Ressourcen gemeinsam nutzen können, wobei die Isolierung auf Hardwareebene erfolgt.
-
Erstellen, um
mig-claim-template.yaml
die MIG einzuschließen:resourceclaimtemplates
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'
-
Wenden Sie die drei Vorlagen an:
kubectl apply -f mig-claim-template.yaml
-
Führen Sie den folgenden Befehl aus:
kubectl get resourceclaimtemplates -n mig-gpu
Das Folgende ist Ausgabebeispiel:
NAME AGE mig-large-template 71m mig-medium-template 71m mig-small-template 71m
-
Erstellen Sie
mig-pod.yaml
, um mehrere Jobs zu planen und diese Vorteile zu nutzenresourceclaimtemplates
:--- # 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
-
Wenden Sie diese Spezifikation an, die drei Pods bereitstellen sollte:
kubctl apply -f mig-pod.yaml
Diese Pods sollten vom DRA-Treiber geplant werden.
-
Überprüfen Sie die Pod-Logs des DRA-Treibers und Sie erhalten eine Ausgabe, die der folgenden ähnelt:
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**],}]
-
Überprüfen Sie
resourceclaims
, um den Pod-Status zu sehen:kubectl get resourceclaims -n mig-gpu -w
Das Folgende ist Ausgabebeispiel:
NAME STATE AGE mig-large-training-pod-mig-large-claim-6dpn8 pending 0s mig-large-training-pod-mig-large-claim-6dpn8 pending 0s mig-large-training-pod-mig-large-claim-6dpn8 allocated,reserved 0s mig-medium-training-pod-mig-medium-claim-bk596 pending 0s mig-medium-training-pod-mig-medium-claim-bk596 pending 0s mig-medium-training-pod-mig-medium-claim-bk596 allocated,reserved 0s mig-small-inference-pod-mig-small-claim-d2t58 pending 0s mig-small-inference-pod-mig-small-claim-d2t58 pending 0s mig-small-inference-pod-mig-small-claim-d2t58 allocated,reserved 0s
Wie Sie sehen,
allocated,reserved
wurden alle Pods vom DRA-Treiber von „Ausstehend“ zu „Ausstehend“ verschoben. -
Führen Sie
nvidia-smi
vom Knoten aus aus. Sie werden feststellen, dass drei Python-Prozessoren laufen: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 |** +-----------------------------------------------------------------------------------------+
Optimieren Sie GPU-Workloads mit IMEX mithilfe von GB2 00 P6e-Instanzen
IMEX (Internode Memory Exchange) ermöglicht eine speicherkohärente Kommunikation zwischen Knoten für verteiltes Training auf NVIDIA 00. GB2 UltraClusters
Führen Sie die folgenden Schritte aus.
-
Definieren Sie ein
ComputeDomain
für ein Training mit mehreren Knoten mit einer Datei namensimex-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
-
Definieren Sie einen Pod mithilfe von IMEX-Kanälen mit einer Datei namens:
imex-pod.yaml
apiVersion: v1 kind: Pod metadata: name: imex-distributed-training namespace: default labels: app: imex-training spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: nvidia.com/gpu.clique operator: Exists containers: - name: distributed-training image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["bash", "-c"] args: - | echo "=== IMEX Channel Verification ===" ls -la /dev/nvidia-caps-imex-channels/ echo "" echo "=== GPU Information ===" nvidia-smi echo "" echo "=== NCCL Test (if available) ===" python -c " import torch import torch.distributed as dist import os print(f'CUDA available: {torch.cuda.is_available()}') print(f'CUDA device count: {torch.cuda.device_count()}') if torch.cuda.is_available(): for i in range(torch.cuda.device_count()): print(f'GPU {i}: {torch.cuda.get_device_name(i)}') # Check for IMEX environment variables imex_vars = [k for k in os.environ.keys() if 'IMEX' in k or 'NVLINK' in k] if imex_vars: print('IMEX Environment Variables:') for var in imex_vars: print(f' {var}={os.environ[var]}') print('IMEX channel verification completed') " # Keep container running for inspection sleep 3600 resources: claims: - name: imex-channel-0 - name: imex-channel-1 resourceClaims: - name: imex-channel-0 resourceClaimTemplateName: imex-channel-template - name: imex-channel-1 resourceClaimTemplateName: imex-channel-template tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule
Anmerkung
Dies erfordert P6e GB2 00-Instanzen.
-
Stellen Sie IMEX bereit, indem Sie die
ComputeDomain
beiden Vorlagen anwenden:kubectl apply -f imex-claim-template.yaml kubectl apply -f imex-compute-domain.yaml kubectl apply -f imex-pod.yaml
-
Überprüfen Sie den
ComputeDomain
Status.kubectl get computedomain distributed-training-domain
-
Überwachen Sie die Bereitstellung des IMEX-Daemons.
kubectl get pods -n nvidia-dra-driver -l [resource.nvidia.com/computeDomain](http://resource.nvidia.com/computeDomain)
-
Überprüfen Sie die IMEX-Kanäle im Pod:
kubectl exec imex-distributed-training -- ls -la /dev/nvidia-caps-imex-channels/
-
Sehen Sie sich die Pod-Logs an:
kubectl logs imex-distributed-training
Im Folgenden finden Sie ein Beispiel für die erwartete Ausgabe:
=== 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
Weitere Informationen finden Sie im NVIDIA-Beispiel