Berechnung und Autoscaling - Amazon EKS

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 anzugeben, die von den mit Karpenter verwendeten Knotentypen und verwalteten Knotengruppen unterstützt werden. Wenn diese nicht definiert werden, kann dies dazu führen, dass Pods auf Instanzen mit unzureichenden GPU-Ressourcen geplant werden, was zu Ausfällen oder Leistungseinbußen führen kann. Wir empfehlen, NodeSelector oder Node Affinity zu verwenden, um anzugeben, auf welchem Knoten ein Pod ausgeführt werden soll, und Rechenressourcen (CPU, Speicher GPUs usw.) im Ressourcenbereich des Pods festzulegen.

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ützung in 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 Karpenter und verwalteten 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 Weitere Informationen zum Erstellen ODCRs, einschließlich CLI-Befehlen, finden Sie unter On-Demand-Kapazitätsreservierung — Erste Schritte.

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 unter Accelerated Computing an. Evaluieren Sie mehrere Instance-Typen und -Größen, um die beste Lösung für Ihre spezifischen Workload-Anforderungen zu finden. Berücksichtigen Sie Faktoren wie Anzahl GPUs, Arbeitsspeicher und Netzwerkleistung. Durch die sorgfältige Auswahl des richtigen GPU-Instance-Typs und der richtigen Größe können Sie eine bessere Ressourcennutzung und Kosteneffizienz in Ihren EKS-Clustern erreichen.

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 wie hier gezeigt verwenden:

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 von power.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 und GPU-Sharing auf Amazon EKS mit NVIDIA Time-Slicing und beschleunigten Instances. EC2

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 HyperPodeingehende 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 Konsolidierungsfunktion von Karpenter optimiert automatisch die Cluster-Kosten, indem sie nicht ausgelastete Knoten beendet oder durch kostengünstigere Alternativen ersetzt. Selbst wenn ein Workload eine GPU vollständig ausnutzt, kann Karpenter Knoten konsolidieren, wenn es einen kostengünstigeren Instance-Typ mit passender Größe identifiziert, der die Anforderungen des Pods erfüllt, was zu Jobunterbrechungen führt.

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 . Mit Budgets können Sie sicherstellen, dass zu einem bestimmten Zeitpunkt nicht mehr als eine bestimmte Anzahl von Knotenknoten in den ausgewählten NodePool Knoten unterbrochen wird. Sie können auch Unterbrechungsbudgets verwenden, um zu verhindern, dass alle Knoten zu einem bestimmten Zeitpunkt (z. B. zu Spitzenzeiten) unterbrochen werden. Weitere Informationen finden Sie in der Dokumentation zu Karpenter Consolidation.

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 abgeschlossener Jobs.

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 und statische Knotengruppen für reservierte Kapazität.

  • 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 NodePool, das das Starten von g 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) stellt einen grundlegenden Fortschritt im Kubernetes-GPU-Ressourcenmanagement dar. DRA geht über die Beschränkungen herkömmlicher Geräte-Plug-ins hinaus und ermöglicht ausgeklügelte GPU-Sharing, Topologieerkennung und knotenübergreifende Ressourcenkoordination. DRA ist in Amazon EKS Version 1.33 verfügbar und adressiert kritische Herausforderungen bei AI/ML Workloads, indem es Folgendes bietet:

  • 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
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

  1. 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
  2. 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:

  1. 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
  2. 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
  3. 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

  1. 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
  2. Fügen Sie das NVIDIA NGC Helm-Repository hinzu:

    helm repo add nvidia https://helm.ngc.nvidia.com/nvidia helm repo update
  3. 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

  1. 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
  2. Ü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.

  1. 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
  2. Wenden Sie die Vorlage an:

    kubectl apply -f basic-gpu-claim-template.yaml
  3. Überprüfen Sie den Status:

    kubectl get resourceclaimtemplates -n gpu-test1

    Das Folgende ist Ausgabebeispiel:

    NAME AGE single-gpu 9m16s
  4. 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"
  5. Wenden Sie den Pod an und überwachen Sie ihn:

    kubectl apply -f basic-gpu-pod.yaml
  6. Ü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
  7. Ü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
  8. 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:

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.

  1. 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
  2. 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
  3. Wenden Sie die Vorlage und den Pod an:

    kubectl apply -f timeslicing-claim-template.yaml kubectl apply -f timeslicing-pod.yaml
  4. 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 wechseln running

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.

  1. 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
  2. Definieren Sie einen Pod mithilfe von MPS mit einer Datei namensmps-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
  3. Wenden Sie die Vorlage an und erstellen Sie mehrere MPS-Pods:

    kubectl apply -f mps-claim-template.yaml kubectl apply -f mps-pod.yaml
  4. Ü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üfungnvidia-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. Der NVIDIA GPU-Operator verwendet MIG Manager, um MIG-Profile zu erstellen, und startet die GPU-Instanzen wie P4D, P4De, P5, P6 und mehr neu, um die Konfigurationsänderungen zu übernehmen. Der GPU-Operator verfügt über die MIG Manager-Komponente, die auf Änderungen der Knotenbezeichnung achtet und automatisch die entsprechende MIG-Konfiguration anwendet, umfassende MIG-Verwaltungsfunktionen. Wenn eine Änderung des MIG-Profils angefordert wird, fährt der Operator alle GPU-Clients ordnungsgemäß herunter, wendet die neue Partitionsgeometrie an und startet die betroffenen Dienste neu. Dieser Prozess erfordert einen Neustart des Knotens für GPU-Instanzen, um saubere GPU-Statusübergänge zu gewährleisten. Aus diesem Grund ist die Aktivierung WITH–0—REBOOT=true in der MIG Manager-Konfiguration für erfolgreiche MIG-Bereitstellungen unerlässlich.

Sie benötigen sowohl den NVIDIA DRA-Treiber als auch den NVIDIA GPU Operator, um mit MIG in Amazon EKS zu arbeiten. Darüber hinaus benötigen Sie weder das NVIDIA Device Plugin noch den DCGM Exporter, da diese Teil des NVIDIA GPU Operators sind. Da auf den EKS NVIDIA die NVIDIA-Treiber vorinstalliert AMIs sind, haben wir die Bereitstellung von Treibern durch den GPU-Operator deaktiviert, um Konflikte zu vermeiden und die optimierten Treiber zu nutzen, die bereits auf den Instanzen vorhanden sind. Der NVIDIA DRA-Treiber kümmert sich um die dynamische Ressourcenzuweisung für MIG-Instanzen, während der GPU-Operator den gesamten GPU-Lebenszyklus verwaltet. Dazu gehören die MIG-Konfiguration, die Funktionalität von Geräte-Plug-ins, die Überwachung durch DCGM und die Erkennung von Knotenfunktionen. Dieser integrierte Ansatz bietet eine Komplettlösung für das GPU-Management in Unternehmen mit Isolierung auf Hardwareebene und Funktionen zur dynamischen Ressourcenzuweisung.

Schritt 1: Stellen Sie NVIDIA GPU Operator bereit
  1. Fügen Sie das NVIDIA GPU Operator-Repository hinzu:

    helm repo add nvidia https://nvidia.github.io/gpu-operator helm repo update
  2. 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
  3. 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)

  4. Ü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
  5. 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.

  6. Melden Sie sich bei der p4de Instanz an.

  7. 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.

  1. 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'
  2. Wenden Sie die drei Vorlagen an:

    kubectl apply -f mig-claim-template.yaml
  3. 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
  4. Erstellen Siemig-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
  5. Wenden Sie diese Spezifikation an, die drei Pods bereitstellen sollte:

    kubctl apply -f mig-pod.yaml

    Diese Pods sollten vom DRA-Treiber geplant werden.

  6. Ü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**],}]
  7. Überprüfen Sieresourceclaims, 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.

  8. 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.

  1. 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
  2. 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.

  3. 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
  4. Überprüfen Sie den ComputeDomain Status.

    kubectl get computedomain distributed-training-domain
  5. Überwachen Sie die Bereitstellung des IMEX-Daemons.

    kubectl get pods -n nvidia-dra-driver -l [resource.nvidia.com/computeDomain](http://resource.nvidia.com/computeDomain)
  6. Überprüfen Sie die IMEX-Kanäle im Pod:

    kubectl exec imex-distributed-training -- ls -la /dev/nvidia-caps-imex-channels/
  7. 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 unter GitHub.