Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.
Elaborazione e scalabilità automatica
Suggerimento
Registrati
Ottimizzazione delle risorse GPU e gestione dei costi
Pianifica i carichi di lavoro in base ai requisiti della GPU utilizzando le etichette Well-Known
Per i AI/ML carichi di lavoro sensibili alle diverse caratteristiche della GPU (ad esempio GPU, memoria GPU), consigliamo di specificare i requisiti della GPU utilizzando etichette di pianificazione note
Esempio
Ad esempio, utilizzando il selettore del nodo del nome della GPU quando si utilizza Karpenter:
apiVersion: v1 kind: Pod metadata: name: gpu-pod-example spec: containers: - name: ml-workload image: <image> resources: limits: nvidia.com/gpu: 1 # Request one NVIDIA GPU nodeSelector: karpenter.k8s.aws/instance-gpu-name: "l40s" # Run on nodes with NVIDIA L40S GPUs
Usa Kubernetes Device Plugin per esporre le GPU
Per esporre le GPU sui nodi, il driver GPU NVIDIA deve essere installato sul sistema operativo del nodo e il runtime del contenitore deve essere configurato per consentire allo scheduler Kubernetes di assegnare pod ai nodi con GPU disponibili. Il processo di configurazione del plug-in per dispositivi NVIDIA Kubernetes dipende dall'AMI accelerata EKS che stai utilizzando:
-
Bottlerocket Accelerated AMI : questa AMI include il driver GPU NVIDIA e il plug-in per dispositivi
NVIDIA Kubernetes è preinstallato e pronto all'uso, il che consente il supporto GPU immediato. Non è richiesta alcuna configurazione aggiuntiva per esporre le GPU allo scheduler Kubernetes. -
AMI accelerata AL2023
: questa AMI include il driver GPU NVIDIA ma il plug-in per dispositivi NVIDIA Kubernetes non è preinstallato. https://github.com/NVIDIA/k8s-device-plugin È necessario installare e configurare il plug-in del dispositivo separatamente, in genere tramite un. DaemonSet Nota che se usi eksctl per creare il tuo cluster e specifichi un tipo di istanza GPU (ad esempio g5.xlarge) nel tuo ClusterConfig,eksctlselezionerà automaticamente l'AMI appropriata e installerà il plug-in per dispositivi NVIDIA Kubernetes. Per saperne di più, consulta il supporto GPU nella documentazione di eksctl. https://eksctl.io/usage/gpu-support/
Se invece decidi di utilizzare le AMI accelerate EKS e l'operatore GPU NVIDIA
Per verificare che il NVIDIA Device Plugin sia attivo e che le GPU siano esposte correttamente, esegui:
kubectl describe node | grep nvidia.com/gpu
Questo comando verifica se la nvidia.com/gpu risorsa è nella capacità e nelle risorse allocabili del nodo. Ad esempio, dovrebbe essere visualizzato un nodo con una GPU. nvidia.com/gpu: 1 Per ulteriori informazioni, consulta la Kubernetes GPU Scheduling Guide.
Usa diversi tipi di istanze EC2
L'utilizzo del maggior numero possibile di tipi di istanze EC2 è un'importante best practice per la scalabilità su Amazon EKS, come descritto nella sezione. Piano dati Kubernetes Questa raccomandazione si applica anche alle istanze con hardware accelerato (ad esempio, GPU). Se crei un cluster che utilizza un solo tipo di istanza e provi a scalare il numero di nodi oltre la capacità della regione, potresti ricevere un errore di capacità insufficiente (ICE), che indica che non è disponibile alcuna istanza. È importante comprendere le caratteristiche uniche dei AI/ML carichi di lavoro prima di diversificarli arbitrariamente. Esamina i tipi di istanze disponibili utilizzando lo strumento
Le istanze di calcolo accelerate sono offerte in diversi modelli di acquisto per adattarsi ai carichi di lavoro a breve, medio termine e allo stato stazionario. Per carichi di lavoro a breve termine, flessibili e tolleranti ai guasti, per i quali vorresti evitare di effettuare una prenotazione, dai un'occhiata alle istanze Spot. I Capacity Block, On-Demand le istanze e i Saving Plans ti consentono di effettuare il provisioning di istanze di calcolo accelerate per la durata del carico di lavoro a medio e lungo termine. Per aumentare le possibilità di accedere con successo alla capacità richiesta nell'opzione di acquisto preferita, si consiglia di utilizzare un elenco diversificato di tipi di istanze e zone di disponibilità. In alternativa, se trovi ICE per un modello di acquisto specifico, riprova a utilizzare un modello diverso.
Esempio L'esempio seguente mostra come abilitare un Karpenter NodePool a fornire istanze G e P superiori alle generazioni 3 (ad esempio, p3). Per ulteriori informazioni, consulta la sezione Best practice per la scalabilità di EKS.
- key: karpenter.k8s.aws/instance-category operator: In values: ["g", "p"] # Diversifies across G-series and P-series - key: karpenter.k8s.aws/instance-generation operator: Gt values: ["3"] # Selects instance generations greater than 3
Per dettagli sull'utilizzo delle istanze Spot per GPU, consulta «Considera l'utilizzo delle istanze Spot di Amazon EC2 per GPU con Karpenter» di seguito.
Prendi in considerazione l'utilizzo delle istanze Spot di Amazon EC2 per GPU con Karpenter
Le istanze Spot di Amazon EC2 ti consentono di sfruttare la capacità EC2 inutilizzata nel cloud AWS e sono disponibili con uno sconto fino al 90% rispetto ai prezzi. On-Demand Le istanze Spot di Amazon EC2 possono essere interrotte con un preavviso di due minuti quando EC2 ha bisogno di ripristinare la capacità. Per ulteriori informazioni, consulta le istanze Spot nella Guida per l'utente di Amazon EC2. Amazon EC2 Spot può essere un'ottima scelta per carichi di lavoro tolleranti ai guasti, stateless e flessibili (in termini di tempo e tipo di istanza). Per ulteriori informazioni su quando utilizzare le istanze Spot, consulta le best practice per le istanze Spot di EC2. https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-best-practices.html Puoi anche utilizzare le istanze Spot per i carichi di AI/ML lavoro, se lo sono. Spot-friendly
Casi d'uso
Spot-friendly I carichi di lavoro possono essere big data, carichi di lavoro containerizzati, server web stateless CI/CD, elaborazione ad alte prestazioni (HPC) e carichi di lavoro di rendering. Le istanze Spot non sono adatte per carichi di lavoro inflessibili, con stato, intolleranti ai guasti o strettamente collegati tra nodi di istanza (ad esempio, carichi di lavoro con processi paralleli che dipendono fortemente l'uno dall'altro per il calcolo e che richiedono una comunicazione costante tra i nodi, come applicazioni di calcolo MPI-based ad alte prestazioni come la fluidodinamica computazionale o i database distribuiti con interdipendenze complesse). Ecco i casi d'uso specifici che consigliamo (in nessun ordine particolare):
-
Real-time inferenza online: utilizza le istanze Spot per una scalabilità ottimizzata in termini di costi per i carichi di lavoro di inferenza in tempo reale, a condizione che i carichi di lavoro siano compatibili con gli spot. In altre parole, il tempo di inferenza è inferiore a due minuti, l'applicazione è tollerante ai guasti alle interruzioni e può essere eseguita su diversi tipi di istanze. Garantisci un'elevata disponibilità attraverso la diversità delle istanze (ad esempio, tra più tipi di istanze e zone di disponibilità) o le prenotazioni, implementando al contempo la tolleranza agli errori a livello di applicazione per gestire le potenziali interruzioni di Spot.
-
Hyper-parameter ottimizzazione: utilizza le istanze Spot per eseguire lavori di ottimizzazione esplorativa in modo opportunistico, poiché le interruzioni possono essere tollerate senza perdite significative, soprattutto per esperimenti di breve durata.
-
Aumento dei dati: utilizza le istanze Spot per eseguire attività di preelaborazione e aumento dei dati che possono riavviarsi dai checkpoint in caso di interruzione, il che le rende ideali per la disponibilità variabile di Spot.
-
Fine-tuning modelli: utilizza le istanze Spot per ottimizzarle con solidi meccanismi di checkpoint per ripristinare l'istanza dall'ultimo stato salvato, riducendo al minimo l'impatto delle interruzioni delle istanze.
-
Inferenza in batch: utilizza le istanze Spot per elaborare grandi quantità di richieste di inferenza offline in modo non in tempo reale, in cui i lavori possono essere sospesi e ripresi, garantendo il massimo allineamento con i risparmi sui costi di Spot e gestendo potenziali interruzioni dovute a tentativi o diversificazione.
-
Sottoinsiemi di formazione opportunistici: utilizzate le istanze Spot per carichi di lavoro di formazione marginali o sperimentali (ad esempio, modelli più piccoli con meno di 10 milioni di parametri), in cui le interruzioni sono accettabili e possono essere applicate ottimizzazioni dell'efficienza come la diversificazione tra tipi di istanze o regioni, sebbene non consigliate per la formazione su scala di produzione a causa di potenziali interruzioni.
Considerazioni
Per utilizzare le istanze Spot per carichi di lavoro accelerati su Amazon EKS, ci sono una serie di considerazioni chiave (in nessun ordine particolare):
-
Usa Karpenter per gestire le istanze Spot con il consolidamento avanzato abilitato. Specificando karpenter. sh/capacity-digita «spot» in Karpenter NodePool, Karpenter eseguirà il provisioning delle istanze Spot per impostazione predefinita senza alcuna configurazione aggiuntiva. Tuttavia, per abilitare il Spot-to-Spot consolidamento avanzato, che sostituisce i nodi Spot sottoutilizzati con alternative Spot più economiche, devi abilitare il SpotToSpotConsolidation feature gate impostando --feature-gates =true negli argomenti del controller Karpenter o
tramite la variabile di ambiente FEATURE_GATES. SpotToSpotConsolidation Karpenter utilizza una strategia di allocazione ottimizzata in termini di prezzo/capacità per il provisioning delle istanze EC2. https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-allocation-strategy.html In base NodePool ai requisiti e ai vincoli dei pod, Karpenter raggruppa i pod non programmabili e invia un set diversificato di tipi di istanze all'API Amazon EC2 Fleet. https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-request-type.html Puoi utilizzare lo strumento EC2 Instance Type Explorer per generare un elenco di tipi di istanze che soddisfano i tuoi requisiti di calcolo specifici. -
Assicurati che i carichi di lavoro siano stateless, tolleranti ai guasti e flessibili. I carichi di lavoro devono essere stateless, tolleranti ai guasti e flessibili in termini di dimensioni. instance/GPU Ciò consente una ripresa senza interruzioni dopo le interruzioni di Spot e la flessibilità delle istanze consente di rimanere su Spot potenzialmente più a lungo. Abilita la gestione delle interruzioni Spot
in Karpenter configurando il valore settings.InterruptionQueue Helm con il nome della coda AWS SQS per rilevare gli eventi di interruzione Spot. Ad esempio, durante l'installazione tramite Helm, usa --set «settings.interruptionQueue=$ {CLUSTER_NAME}». Per vedere un esempio, consulta la guida Getting Started with Karpenter. Quando Karpenter rileva un evento di interruzione Spot, blocca, contamina, drena e termina automaticamente i nodi prima dell'evento di interruzione per massimizzare il periodo di tolleranza alla cessazione dei pod. Allo stesso tempo, Karpenter avvierà immediatamente un nuovo nodo in modo che possa essere pronto il prima possibile. -
Evita di vincolare eccessivamente la selezione del tipo di istanza. Dovreste evitare il più possibile di vincolare i tipi di istanza. Se non si limitano i tipi di istanze, è più probabile che acquisisca capacità Spot su larga scala con una frequenza inferiore di interruzioni delle istanze Spot e a un costo inferiore. Ad esempio, evita di limitarti a tipi specifici (ad esempio, g5.xlarge). Valuta la possibilità di specificare un insieme diversificato di categorie e generazioni di istanze utilizzando chiavi come karpenter.k8s. aws/instance-category e karpenter.k8s. aws/instance-generazione. Karpenter consente una più facile diversificazione della capacità delle istanze on-demand e Spot tra più tipi di istanze e zone di disponibilità (AZ). Inoltre, se il AI/ML carico di lavoro richiede un numero specifico o limitato di acceleratori ma è flessibile tra le regioni, puoi utilizzare Spot Placement Score per identificare dinamicamente la regione ottimale in cui distribuire il carico di lavoro prima del lancio.
-
Amplia NodePool i requisiti per includere un numero maggiore di famiglie di istanze EC2 simili. Ogni pool di istanze Spot è costituito da una capacità di istanze EC2 inutilizzata per un tipo di istanza specifico in una specifica zona di disponibilità (AZ). Quando Karpenter tenta di eseguire il provisioning di un nuovo nodo, seleziona un tipo di istanza che soddisfa i requisiti del nodo. NodePool Se nessun tipo di istanza compatibile ha una capacità Spot in nessuna AZ, il provisioning ha esito negativo. Per evitare questo problema, consenti a NVIDIA di istanze più ampie della serie g (generazione 4 o superiore) di diverse dimensioni e zone di disponibilità (AZ), tenendo conto delle esigenze hardware come la memoria GPU o il Ray Tracing. Poiché le istanze possono essere di diversi tipi, devi assicurarti che il carico di lavoro sia in grado di funzionare su ogni tipo e che le prestazioni ottenute soddisfino le tue esigenze.
-
Sfrutta tutte le zone di disponibilità in una regione. La capacità disponibile varia in base alla zona di disponibilità (AZ), un tipo di istanza specifico potrebbe non essere disponibile in una AZ ma abbondante in un'altra. Ogni combinazione univoca di un tipo di istanza e di una zona di disponibilità costituisce un pool di capacità Spot separato. Richiedendo capacità per tutte le AZ di una regione in NodePool base ai requisiti di Karpenter, stai effettivamente cercando più pool contemporaneamente. Ciò massimizza il numero di pool di capacità Spot e quindi aumenta la probabilità di acquisire capacità Spot. Per ottenere ciò, nella tua NodePool configurazione, ometti topology.kubernetes. io/zone chiave interamente per consentire a Karpenter di selezionare tra tutti gli AZ disponibili nella regione o elencare esplicitamente gli AZ utilizzando l'operatore: In e fornire i valori (ad esempio, us-west-2a).
-
Prendi in considerazione l'utilizzo di Spot Placement Score (SPS) per avere visibilità sulla probabilità di accedere con successo alla capacità richiesta utilizzando le istanze Spot. Spot Placement Score (SPS) è uno strumento che fornisce un punteggio che ti aiuta a valutare la probabilità di successo di una richiesta Spot. Quando usi SPS, devi prima specificare i requisiti di calcolo per le tue istanze Spot, quindi Amazon EC2 restituisce le prime 10 regioni o zone di disponibilità (AZ) in cui è probabile che la tua richiesta Spot abbia successo. Le regioni e le zone di disponibilità vengono valutate su una scala da 1 a 10. Un punteggio pari a 10 indica che la tua richiesta Spot è altamente probabile ma non garantita. Un punteggio di 1 indica che la tua richiesta Spot ha bassissime probabilità di successo. Lo stesso punteggio potrebbe essere restituito per diverse regioni o zone di disponibilità. Per saperne di più, consulta la Guida alla creazione di una dashboard Spot Placement Score Tracker su AWS. Poiché la capacità di Spot varia continuamente, SPS ti aiuterà a identificare la combinazione di tipi di istanze, AZ e regioni più adatta ai tuoi vincoli di carico di lavoro (ad esempio flessibilità, prestazioni, dimensioni, ecc.). Se il AI/ML carico di lavoro richiede un numero specifico o limitato di acceleratori ma è flessibile tra le regioni, puoi utilizzare il punteggio di posizionamento di Spot per identificare dinamicamente la regione ottimale in cui distribuire il carico di lavoro prima del lancio. Per aiutarvi a scoprire automaticamente la probabilità di acquisire capacità Spot, forniamo una guida per la creazione di una dashboard SPS tracker. Questa soluzione monitora i punteggi SPS nel tempo utilizzando una configurazione YAML per configurazioni diversificate (ad esempio, requisiti di istanza comprese le GPU), memorizza le metriche e fornisce dashboard per confrontare le configurazioni. CloudWatch Definisci dashboard per carico di lavoro per valutare le esigenze di vCPU, memoria e GPU, garantendo configurazioni ottimali per i cluster EKS, inclusa la considerazione dell'utilizzo di altre regioni AWS. Per saperne di più, consulta Come funziona il punteggio di posizionamento di Spot.
-
Gestisci con garbo le interruzioni e i test di Spot. Nel caso di un pod con un periodo di terminazione superiore a due minuti, il vecchio nodo verrà interrotto prima che i pod vengano riprogrammati, il che potrebbe influire sulla disponibilità del carico di lavoro. Prendi in considerazione l'avviso di interruzione Spot di due minuti durante la progettazione delle tue applicazioni, implementa il checkpoint nelle applicazioni a lunga esecuzione (ad esempio, il salvataggio dei progressi nello storage persistente come Amazon S3) per riprenderlo dopo le interruzioni, estendi la terminazione GracePeriodSeconds (l'impostazione predefinita è 30 secondi) nelle specifiche Pod per consentire più tempo per l'arresto regolare e gestisci le interruzioni utilizzando gli hook del ciclo di vita PreStop, segnali and/or SIGTERM all'interno della tua applicazione per attività di arresto regolari come la pulizia, il salvataggio dello stato e chiusura della connessione. Per i carichi di lavoro in tempo reale, in cui la scalabilità è importante e i carichi di lavoro impiegano più di due minuti perché l'applicazione sia pronta a servire il traffico, prendi in considerazione l'ottimizzazione dei tempi di avvio dei container e di caricamento del modello ML mediante la revisione Archiviazione delle Scalabilità e prestazioni delle applicazioni best practice. Per testare un nodo sostitutivo, utilizza AWS Fault Injection Service
(FIS) per simulare le interruzioni di Spot.
Oltre a queste best practice principali di Spot, tieni conto di questi fattori nella gestione dei carichi di lavoro delle GPU su Amazon EKS. A differenza dei CPU-based carichi di lavoro, i carichi di lavoro GPU sono particolarmente sensibili ai dettagli hardware come le funzionalità della GPU e la memoria GPU disponibile. I carichi di lavoro delle GPU potrebbero essere limitati dai tipi di istanze che possono utilizzare, con meno opzioni disponibili rispetto alle CPU. Come primo passo, valuta se il carico di lavoro è flessibile a livello di istanza. Se non sai quanti tipi di istanze possono essere utilizzati dal tuo carico di lavoro, testali singolarmente per garantire compatibilità e funzionalità. Identifica quanto puoi essere flessibile per diversificare il più possibile, confermando al contempo che la diversificazione fa sì che il carico di lavoro funzioni e comprendi eventuali impatti sulle prestazioni (ad esempio, sulla produttività o sui tempi di completamento). Come parte della diversificazione dei carichi di lavoro, considera quanto segue:
-
Verifica la compatibilità tra CUDA e framework. I carichi di lavoro della GPU potrebbero essere ottimizzati per hardware e tipi di GPU specifici (ad esempio, V100 in p3 e A100 in p4) o scritti per versioni CUDA specifiche per librerie come TensorFlow, quindi assicurati di verificare la compatibilità dei tuoi carichi di lavoro. Questa compatibilità è fondamentale per prevenire errori di runtime, arresti anomali, guasti nell'accelerazione della GPU (ad esempio, versioni CUDA non corrispondenti con framework simili PyTorch o che TensorFlow possono impedire l'esecuzione) o la capacità di sfruttare funzionalità hardware come la FP16/INT8 precisione.
-
Memoria GPU. Assicurati di valutare i requisiti di memoria dei tuoi modelli e profilarne l'utilizzo durante il runtime utilizzando strumenti come DCGM Exporter
e imposta la memoria GPU minima richiesta per il tipo di istanza in etichette note come karpenter.k8s. aws/instance-gpu-memory. La VRAM della GPU varia a seconda del tipo di istanza (ad esempio, NVIDIA T4 ha 16 GB, A10G ha 24 GB, V100 ha 16-32 GB) e i modelli ML (ad esempio, modelli con linguaggi di grandi dimensioni) possono superare la memoria disponibile, causando errori di esaurimento della memoria (OOM) o arresti anomali. Per le istanze Spot in EKS, ciò può limitare la diversificazione. Ad esempio, non puoi includere tipi di VRAM inferiori se il tuo modello non è adatto, il che potrebbe limitare l'accesso ai pool di capacità e aumentare il rischio di interruzioni. Tieni presente che per l'inferenza a singolo nodo e GPU (ad esempio, più pod programmati sullo stesso nodo per utilizzarne le risorse della GPU), ciò potrebbe limitare la diversificazione, poiché puoi includere solo tipi di istanza con VRAM sufficiente nella configurazione Spot. -
Floating-point precisione e prestazioni. Non tutte le architetture GPU Nvidia hanno la stessa precisione in virgola mobile (ad esempio). FP16/INT8 Valuta le prestazioni dei tipi di base (CUDA/Tensor/RT) e la precisione in virgola mobile richieste per i tuoi carichi di lavoro. L'esecuzione su una GPU meno costosa e meno performante non significa che sia migliore, quindi valuta la possibilità di valutare le prestazioni in termini di lavoro completato entro un determinato lasso di tempo per comprendere l'impatto della diversificazione.
Scenario: diversificazione per carichi di lavoro di inferenza in tempo reale
Per un carico di lavoro di inferenza online in tempo reale sulle istanze Spot, puoi configurare un Karpenter NodePool per diversificarlo tra famiglie e generazioni di istanze GPU compatibili. Questo approccio garantisce un'elevata disponibilità attingendo da più pool Spot, mantenendo al contempo le prestazioni grazie ai vincoli sulle capacità, sulla memoria e sull'architettura della GPU. Supporta l'utilizzo di alternative quando la capacità delle istanze è limitata, riducendo al minimo le interruzioni e ottimizzando la latenza di inferenza. Questo esempio NodePool afferma di utilizzare istanze delle serie g e p superiori a 3, che hanno più di 20 GB di memoria GPU.
Esempio
apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: gpu-inference-spot spec: template: metadata: labels: role: gpu-spot-worker spec: requirements: - key: karpenter.sh/capacity-type operator: In values: ["spot"] # Use Spot Instances - key: karpenter.k8s.aws/instance-category operator: In values: ["g", "p"] # Diversifies across G-series and P-series - key: karpenter.k8s.aws/instance-generation operator: Gt values: ["3"] # Selects instance generations greater than 3 - key: kubernetes.io/arch operator: In values: ["amd64"] # Specifies AMD64 architecture, compatible with NVIDIA GPUs - key: karpenter.k8s.aws/instance-gpu-memory operator: Gt values: ["20480"] # Ensures more than 20GB (20480 MiB) total GPU memory taints: - key: nvidia.com/gpu effect: NoSchedule nodeClassRef: name: gpu-inference-ec2 group: karpenter.k8s.aws kind: EC2NodeClass expireAfter: 720h limits: cpu: 100 memory: 100Gi disruption: consolidationPolicy: WhenEmptyOrUnderutilized consolidateAfter: 5m # Enables consolidation of underutilized nodes after 5 minutes
Implementa il checkpointing per lavori di formazione di lunga durata
Il checkpointing è una tecnica di tolleranza ai guasti che prevede il salvataggio periodico dello stato di un processo, consentendone la ripresa dall'ultimo punto salvato in caso di interruzioni. Nell'apprendimento automatico, è comunemente associato alla formazione, in cui lavori di lunga durata possono far risparmiare peso ai modelli e consentire di riprendere l'addestramento dopo guasti, ad esempio problemi hardware o interruzioni dell'istanza Spot.
I checkpoint vengono utilizzati per salvare lo stato dei modelli di machine learning (ML) durante l'addestramento. I checkpoint sono istantanee del modello e possono essere configurati tramite le funzioni di callback dei framework ML. È possibile utilizzare i checkpoint salvati per riavviare un job di addestramento dall’ultimo checkpoint salvato. Utilizzando i checkpoint, salvate le istantanee del modello in fase di addestramento a causa di un'interruzione imprevista del processo o dell'istanza di formazione. Ciò consente di riprendere l'addestramento del modello in futuro da un checkpoint. Oltre a implementare un sistema di resilienza dei nodi, consigliamo di implementare il checkpoint per mitigare l'impatto delle interruzioni, comprese quelle causate da guasti hardware o interruzioni dell'istanza Spot di Amazon EC2.
Senza il checkpoint, le interruzioni possono comportare perdite di tempo di calcolo e perdita di progressi, il che è costoso per lavori di formazione di lunga durata. Il checkpointing consente ai job di salvare periodicamente il loro stato (ad esempio, i pesi dei modelli e gli stati degli ottimizzatori) e di riprendere dall'ultimo checkpoint (ultimo batch elaborato) dopo un'interruzione. Per implementare il checkpointing, progetta l'applicazione in modo da elaborare i dati in grandi batch e salvare i risultati intermedi in uno storage persistente, ad esempio un bucket Amazon S3 tramite il driver CSI Mountpoint for Amazon S3 mentre il processo di formazione procede.
Casi d'uso
Il checkpointing è particolarmente utile in scenari specifici per bilanciare la tolleranza ai guasti con il sovraccarico delle prestazioni. Prendi in considerazione l'utilizzo del checkpoint nei seguenti casi:
-
La durata del lavoro supera alcune ore: per lavori di formazione di lunga durata (ad esempio, >1-2 ore per modelli di piccole dimensioni o days/weeks per modelli di base di grandi dimensioni con miliardi di parametri), in cui la perdita di progresso dovuta alle interruzioni è costosa. I lavori più brevi potrebbero non giustificare le spese generali. I/O
-
Per istanze Spot o guasti hardware: in ambienti soggetti a interruzioni, come EC2 Spot (preavviso di 2 minuti) o guasti hardware (ad esempio, errori di memoria della GPU), il checkpointing consente una rapida ripresa, rendendo Spot una soluzione ideale per risparmiare sui costi nei carichi di lavoro tolleranti ai guasti.
-
Formazione distribuita su larga scala: per configurazioni con hundreds/thousands acceleratori (ad esempio, >100 GPU), in cui il tempo medio tra i guasti diminuisce linearmente con la scalabilità. Utilizza il model/data parallelismo per gestire l'accesso simultaneo ai checkpoint ed evitare riavvii completi.
-
Large-scale modelli con un elevato fabbisogno di risorse: nella formazione LLM su scala petabyte, in cui i guasti sono inevitabili a causa delle dimensioni del cluster, gli approcci su più livelli (rapidi locali ogni 5-30 minuti per i transitori, duraturi ogni ora per i guasti gravi) ottimizzano i tempi di ripristino rispetto all'efficienza.
Utilizza ML Capacity Blocks per la garanzia della capacità delle istanze P e Trainium
I Capacity Block for ML consentono di riservare istanze GPU molto richieste, in particolare istanze P (ad es. p6-b200, p5, p5e, p5en, p4d, p4de) e Trainium (ad esempio, trn1, trn2), da avviare quasi immediatamente o in una data futura per supportare i carichi di lavoro di machine learning (ML) di breve durata. Queste prenotazioni sono ideali per garantire la capacità di eseguire attività ad alta intensità di calcolo come l'addestramento dei modelli e la messa a punto. I prezzi di EC2 Capacity Blocks sono costituiti da una commissione di prenotazione e da una commissione per il sistema operativo. Per saperne di più sui prezzi, consulta i prezzi di EC2 Capacity Blocks for ML.
Per riservare le GPU per i AI/ML carichi di lavoro su Amazon EKS e garantire una capacità prevedibile, consigliamo di utilizzare i Capacity Block ML per il breve termine o gli ODCR (Capacity Reservation) per una garanzia di On-Demand capacità generica.
-
Gli ODCR consentono di riservare la capacità delle istanze EC2 (ad esempio, istanze GPU come g5 o p5) in una specifica zona di disponibilità per un determinato periodo, garantendo la disponibilità, anche in caso di forte domanda. Gli ODCR non sono vincolati a lungo termine, ma la On-Demand tariffa viene calcolata in base alla capacità riservata, utilizzata o inattiva. In EKS, gli ODCR sono supportati da tipi di nodi come https://karpenter.sh/
Karpenter e gruppi di nodi gestiti. https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html Per dare priorità agli ODCR in Karpenter, configura il campo per utilizzare il campo. NodeClass capacityReservationSelectorTermsConsulta la NodePools documentazione diKarpenter. -
I Capacity Block sono un meccanismo di prenotazione specializzato per istanze GPU (ad esempio, p5, p4d) o Trainium (trn1, trn2), progettato per carichi di lavoro ML a breve termine come l'addestramento di modelli, la messa a punto o la sperimentazione. Si riserva la capacità per un periodo definito (in genere da 24 ore a 182 giorni) a partire da una data futura, pagando solo il tempo riservato. Sono prepagati, richiedono una pianificazione preliminare per le esigenze di capacità e non supportano la scalabilità automatica, ma sono collocati in EC2 per reti a bassa latenza. UltraClusters Fanno pagare solo per il periodo riservato. Per saperne di più, consulta la sezione Trova e acquista Capacity Blocks oppure inizia a configurare gruppi di nodi gestiti con Capacity Blocks utilizzando le istruzioni in Creare un gruppo di nodi gestiti con Capacity Blocks for ML.
Riserva la capacità tramite la Console di gestione AWS e configura i nodi per utilizzare blocchi di capacità ML. Pianifica le prenotazioni in base alla pianificazione dei carichi di lavoro e verifica in un cluster di staging. Per ulteriori informazioni, consulta la documentazione sui blocchi di capacità.
Prendi in considerazione On-Demand Amazon EC2 Spot o On-Demand Capacity Reservations (ODCR) per istanze G Amazon EC2
Per le istanze G Amazon EC2, considera le diverse opzioni di acquisto tra le istanze Spot di Amazon EC2 e le On-Demand prenotazioni di capacità. On-Demand Gli ODCR consentono di riservare la capacità delle istanze EC2 in una specifica zona di disponibilità per una determinata durata, garantendo la disponibilità anche in caso di forte domanda. A differenza dei ML Capacity Block, disponibili solo per le istanze P e Trainium, gli ODCR possono essere utilizzati per una gamma più ampia di tipi di istanze, comprese le istanze G, rendendoli adatti a carichi di lavoro che richiedono diverse funzionalità della GPU, come inferenza o grafica. Quando si utilizzano le istanze Spot di Amazon EC2, la possibilità di diversificare tra diversi tipi di istanze, dimensioni e zone di disponibilità è fondamentale per poter rimanere su Spot più a lungo.
Gli ODCR non prevedono alcun impegno a lungo termine, ma paghi la On-Demand tariffa per la capacità riservata, utilizzata o inattiva. Gli ODCR possono essere creati per un uso immediato o programmati per una data futura, offrendo flessibilità nella pianificazione della capacità. In Amazon EKS, gli ODCR sono supportati da tipi di nodi come https://karpenter.sh/capacityReservationSelectorTerms Consulta la NodePools documentazione di
Prendi in considerazione altri tipi e dimensioni di istanze accelerate
La selezione dell'istanza e della dimensione accelerate appropriate è essenziale per ottimizzare le prestazioni e i costi dei carichi di lavoro ML su Amazon EKS. Ad esempio, diverse famiglie di istanze GPU hanno prestazioni e capacità diverse, come la memoria GPU. Per aiutarti a scegliere l'opzione più conveniente, consulta le istanze GPU disponibili nella pagina Tipi di istanze EC2 in Accelerated Computing.
Se utilizzi un'istanza GPU in un nodo EKS, per impostazione predefinita questo avrà il nvidia-device-plugin-daemonset pod nel namespace. kube-system Per capire rapidamente se stai utilizzando appieno le GPU nella tua istanza, puoi usare nvidia-smi come mostrato qui:
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
-
Se
utilization.memoryè vicino al 100%, allora i tuoi codici sono probabilmente limitati alla memoria. Ciò significa che la GPU (memoria) è completamente utilizzata, ma potrebbe suggerire un'ulteriore ottimizzazione delle prestazioni. -
Se
utilization.gpuè vicino al 100%, ciò non significa necessariamente che la GPU sia completamente utilizzata. Una metrica migliore da considerare è il rapporto tra.power.drawpower.limitSe questo rapporto è pari o superiore al 100%, significa che i tuoi codici stanno utilizzando appieno la capacità di calcolo della GPU. -
Il
-l 5contrassegno indica di emettere le metriche ogni 5 secondi. Nel caso di un singolo tipo di istanza GPU, il flag di query sull'indice non è necessario.
Per saperne di più, consulta le istanze GPU nella documentazione AWS.
Ottimizza l'allocazione delle risorse GPU con l'allocazione MIG e l'allocazione Time-Slicing frazionaria della GPU
I limiti statici delle risorse in Kubernetes (ad esempio, numero di CPU, memoria, GPU) possono portare a un provisioning eccessivo o a un sottoutilizzo, in particolare per carichi di lavoro dinamici come l'inferenza. AI/ML La scelta della GPU giusta è importante. Per carichi di lavoro a basso volume o con picchi di lavoro, il time-slicing consente a più carichi di lavoro di condividere una singola GPU condividendone le risorse di elaborazione, migliorando potenzialmente l'efficienza e riducendo gli sprechi. La condivisione della GPU può essere ottenuta attraverso diverse opzioni:
-
Sfrutta i selettori dei nodi e l'affinità dei nodi per influenzare la pianificazione: assicurati che i nodi di cui è stato eseguito il provisioning e i pod siano pianificati sulle GPU appropriate per il carico di lavoro (ad es.)
karpenter.k8s.aws/instance-gpu-name: "a100" -
Time-Slicing: pianifica i carichi di lavoro in modo da condividere le risorse di calcolo di una GPU nel tempo, consentendo l'esecuzione simultanea senza partizionamento fisico. È ideale per carichi di lavoro con esigenze di elaborazione variabili, ma può mancare l'isolamento della memoria.
-
Multi-Instance GPU (MIG): MIG consente di partizionare una singola GPU NVIDIA in più istanze isolate ed è supportato dalle GPU NVIDIA Ampere (ad esempio, GPU A100), NVIDIA Hopper (ad esempio, GPU H100) e NVIDIA Blackwell (ad esempio, GPU Blackwell). Ogni istanza MIG riceve risorse di calcolo e memoria dedicate, che consentono la condivisione delle risorse in ambienti multi-tenant o carichi di lavoro che richiedono garanzie di risorse, il che consente di ottimizzare l'utilizzo delle risorse GPU, inclusi scenari come la gestione di più modelli con dimensioni di batch diverse tramite time-slicing.
-
Allocazione frazionata della GPU: utilizza la pianificazione basata su software per allocare parti dell'elaborazione o della memoria di una GPU ai carichi di lavoro, offrendo flessibilità per i carichi di lavoro dinamici. NVIDIA KAI Scheduler
, parte della piattaforma, lo consente consentendo ai pod di richiedere risorse GPU frazionarie. Run:ai
Per abilitare queste funzionalità in EKS, puoi implementare il NVIDIA Device Plugin, che espone le GPU come risorse programmabili e supporta il time-slicing e il MIG. Per saperne di più, consulta le Time-Slicing GPU in Kubernetes
Esempio
Ad esempio, per abilitare il time-slicing con NVIDIA Device Plugin:
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
Esempio
Ad esempio, per utilizzare KAI Scheduler per l'allocazione frazionaria della GPU, implementalo insieme a NVIDIA GPU Operator e specifica le risorse GPU frazionarie nelle specifiche del pod:
apiVersion: v1 kind: Pod metadata: name: fractional-gpu-pod-example annotations: gpu-fraction: "0.5" # Annotation for 50% GPU labels: runai/queue: "default" # Required queue assignment spec: containers: - name: ml-workload image: nvcr.io/nvidia/pytorch:25.04-py3 resources: limits: nvidia.com/gpu: 1 nodeSelector: nvidia.com/gpu: "true" schedulerName: kai-scheduler
Resilienza dei nodi e gestione dei lavori di formazione
Implementa i controlli sullo stato dei nodi con il ripristino automatico
Per i lavori di formazione distribuiti su Amazon EKS che richiedono frequenti comunicazioni tra i nodi, ad esempio l'addestramento di modelli multi-GPU su più nodi, problemi hardware come guasti alla GPU o all'EFA possono causare interruzioni dei lavori di formazione. Queste interruzioni possono portare alla perdita dei progressi della formazione e all'aumento dei costi, in particolare per carichi di lavoro di lunga durata che si basano su hardware stabile. AI/ML
Per contribuire ad aumentare la resilienza contro i guasti hardware, come i guasti della GPU nei cluster EKS che eseguono carichi di lavoro GPU, consigliamo di sfruttare l'EKS Node Monitoring Agent con Auto Repair o Amazon. SageMaker HyperPod Mentre l'EKS Node Monitoring Agent with Auto Repair fornisce funzionalità come il monitoraggio dello stato dei nodi e la riparazione automatica utilizzando meccanismi Kubernetes standard, SageMaker HyperPod offre una resilienza mirata e funzionalità aggiuntive progettate specificamente per la formazione ML su larga scala, come controlli approfonditi dello stato e ripresa automatica del lavoro.
-
L'EKS Node Monitoring Agent con Node Auto Repair monitora continuamente lo stato dei nodi leggendo i log e applicando NodeConditions, comprese le condizioni standard e le condizioni specifiche dell'hardware accelerato, per
Readyidentificare problemi come guasti alla GPU o alla rete. Quando un nodo è ritenuto non integro, Node Auto Repair lo blocca e lo sostituisce con un nuovo nodo. La riprogrammazione dei pod e il riavvio dei job si basano sui meccanismi standard di Kubernetes e sulla politica di riavvio del job. -
L'agente per i controlli SageMaker HyperPod
approfonditi e il monitoraggio dello stato di salute monitora continuamente lo stato di salute della GPU e delle istanze. Trainium-based È personalizzato per i AI/ML carichi di lavoro e utilizza etichette (ad esempio, node-health-status) per gestire lo stato dei nodi. Quando un nodo è considerato non integro, HyperPod attiva la sostituzione automatica dell'hardware difettoso, come le GPU. Rileva i guasti relativi alla rete di EFA tramite i controlli di integrità di base predefiniti e supporta la ripresa automatica per i lavori di formazione interrotti, consentendo la ripresa automatica dei lavori di formazione interrotti, consentendo ai lavori di continuare dall'ultimo checkpoint, riducendo al minimo le interruzioni per le attività di machine learning su larga scala.
Sia per EKS Node Monitoring Agent with Auto Repair che per SageMaker HyperPod i cluster che utilizzano EFA, per monitorare EFA-specific metriche quali errori RDMA (Remote Direct Memory Access) e perdite di pacchetti, assicurati che il driver AWS EFA sia installato. Inoltre, consigliamo di implementare l'CloudWatch Observability Add-on o di utilizzare strumenti come DCGM Exporter con Prometheus e Grafana per monitorare EFA, GPU e, per, per, metriche specifiche relative alle sue funzionalità. SageMaker HyperPod
Disabilita Karpenter Consolidation per carichi di lavoro sensibili alle interruzioni
Per carichi di lavoro sensibili alle interruzioni, come l'elaborazione, le attività di AI/ML previsione su larga scala o la formazione, consigliamo di ottimizzare le politiche di consolidamento di Karpenter per evitare interruzioni durante l'esecuzione del lavoro.
La politica di WhenEmptyOrUnderutilized consolidamento può chiudere i nodi prematuramente, con conseguenti tempi di esecuzione più lunghi. Ad esempio, le interruzioni possono ritardare la ripresa del lavoro a causa della riprogrammazione dei pod e del ricaricamento dei dati, il che potrebbe essere costoso per lavori di inferenza batch di lunga durata. Per ovviare a questo problema, puoi impostare WhenEmpty e configurare una consolidateAfter durata, ad esempio 1 ora, consolidationPolicy per conservare i nodi durante i picchi del carico di lavoro. Ad esempio:
disruption: consolidationPolicy: WhenEmpty consolidateAfter: 60m
Questo approccio migliora la latenza di avvio dei pod per carichi di lavoro di inferenza batch impegnativi e altri lavori sensibili alle interruzioni, come l'elaborazione dei dati di inferenza online in tempo reale o l'addestramento di modelli, in cui il costo dell'interruzione supera i risparmi sui costi di elaborazione. NodePool
Usa ttl SecondsAfterFinished per automatizzare i lavori Kubernetes Clean-Up
Consigliamo di impostare ttlSecondsAfterFinished i job Kubernetes in Amazon EKS per eliminare automaticamente gli oggetti di lavoro completati. Gli oggetti di lavoro permanenti consumano risorse del cluster, come la memoria del server API, e complicano il monitoraggio grazie a dashboard ingombranti (ad esempio, Grafana, Amazon). CloudWatch Ad esempio, l'impostazione di un TTL di 1 ora garantisce che i job vengano rimossi subito dopo il completamento, mantenendo il cluster in ordine. Per maggiori dettagli, consulta Automatic Cleanup for Finished Job.
Configurare Low-Priority Job Prelection per Higher-Priority Jobs/workloads
Per i AI/ML carichi di lavoro a priorità mista su Amazon EKS, puoi configurare la prelazione a bassa priorità per garantire che le attività con priorità più alta (ad esempio, l'inferenza in tempo reale) ricevano tempestivamente le risorse. Senza prelazione, i carichi di lavoro a bassa priorità come i processi batch (ad esempio, inferenza batch, elaborazione dati), i servizi non batch (ad esempio, attività in background, cron job) o i lavori (ad esempio, servizi web) possono ritardare i pod critici occupando i nodi. CPU/memory-intensive La prelazione consente a Kubernetes di eliminare i pod a bassa priorità quando i pod ad alta priorità richiedono risorse, garantendo un'allocazione efficiente delle risorse sui nodi con GPU, CPU o memoria. Consigliamo di utilizzare Kubernetes per assegnare priorità e controllare il comportamento di sfratto. PriorityClass PodDisruptionBudget
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: low-priority value: 100 --- spec: priorityClassName: low-priority
Per ulteriori informazioni, consulta la documentazione Kubernetes Priority and Preemption.
Scalabilità e prestazioni delle applicazioni
Personalizza la capacità di calcolo per i carichi di lavoro ML con Karpenter o Static Nodes
Per garantire una capacità di calcolo efficiente in termini di costi e reattiva per i flussi di lavoro di machine learning (ML) su Amazon EKS, ti consigliamo di personalizzare la strategia di provisioning dei nodi in base alle caratteristiche del carico di lavoro e agli impegni di costo. Di seguito sono riportati due approcci da considerare: scalabilità just-in-time con Karpenter e gruppi di nodi statici per la capacità riservata. https://karpenter.sh/docs/
-
Just-in-time scaler per piani dati come Karpenter: per flussi di lavoro ML dinamici con esigenze di calcolo variabili (ad esempio, GPU-based inferenza seguita da CPU-based plottaggio), consigliamo di utilizzare scaler per piani dati just-in-time come Karpenter.
-
Usa gruppi di nodi statici per carichi di lavoro prevedibili: per carichi di lavoro ML prevedibili e stazionari o quando si utilizzano istanze riservate, i gruppi di nodi gestiti da EKS possono aiutare a garantire che la capacità riservata sia completamente fornita e utilizzata, massimizzando i risparmi. Questo approccio è ideale per tipi specifici di istanze salvati tramite RI o ODCR.
Esempio
Questo è un esempio di Karpenter diversificato NodePool g Amazon EC2 in cui la generazione di istanze è superiore a tre.
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
Esempio
Esempio di utilizzo di gruppi di nodi statici per un carico di lavoro di formazione:
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
Utilizza i limiti e le tolleranze per evitare che i carichi di lavoro non accelerati vengano pianificati su istanze accelerate
La pianificazione dei carichi di lavoro non accelerati sulle risorse GPU non è efficiente dal punto di vista del calcolo, consigliamo di utilizzare i taint e la tolleranza per garantire che i pod di carichi di lavoro non accelerati non siano pianificati su nodi inappropriati. Per ulteriori informazioni, consulta la documentazione di Kubernetes.
Scalabilità in base alle prestazioni del modello
Per i carichi di lavoro di inferenza, consigliamo di utilizzare Kubernetes Event-Driven Autoscaling (KEDA) per scalare in base alle metriche delle prestazioni del modello come le richieste di inferenza o il throughput dei token, con periodi di recupero appropriati. Le politiche di scalabilità statica possono sovrafornire o sottofornire le risorse, con un impatto sui costi e sulla latenza. Per saperne di più, consulta la documentazione KEDA. https://keda.sh/
Allocazione dinamica delle risorse per una gestione avanzata delle GPU
L'allocazione dinamica delle risorse (DRA)
-
Fine-grained Allocazione delle GPU
-
Meccanismi di condivisione avanzati, come Multi-Process service (MPS) e Multi-Instance GPU (MIG)
-
Supporto per architetture hardware di nuova generazione, tra cui NVIDIA GB200 UltraServers
L'allocazione tradizionale delle GPU considera le GPU come risorse intere opache, con conseguente significativo sottoutilizzo (spesso del 30-40% nei cluster di produzione). Ciò si verifica perché i carichi di lavoro ricevono l'accesso esclusivo a intere GPU anche quando richiedono solo risorse frazionarie. DRA trasforma questo modello introducendo un'allocazione strutturata e dichiarativa che fornisce allo scheduler Kubernetes una visibilità completa sulle caratteristiche hardware e sui requisiti del carico di lavoro. Ciò consente decisioni di posizionamento intelligenti e una condivisione efficiente delle risorse.
Vantaggi dell'utilizzo di DRA anziché del plug-in per dispositivi NVIDIA
Il plug-in per dispositivi NVIDIA (a partire dalla versione0.12.0) supporta meccanismi di condivisione della GPU tra cui time-slicing, MPS e MIG. Tuttavia, esistono limitazioni architetturali che DRA risolve.
Limitazioni dei plugin per dispositivi NVIDIA
-
Configurazione statica: le configurazioni di condivisione della GPU (repliche time-slicing e impostazioni MPS) richiedono una preconfigurazione a livello di cluster.
ConfigMapsCiò rende difficile fornire strategie di condivisione diverse per carichi di lavoro diversi. -
Selezione granulare limitata: mentre il plug-in del dispositivo espone le caratteristiche della GPU tramite etichette dei nodi, i carichi di lavoro non possono richiedere dinamicamente configurazioni GPU specifiche (dimensioni della memoria e capacità di calcolo) come parte della decisione di pianificazione.
-
Nessun coordinamento delle risorse tra i nodi: non è possibile gestire risorse GPU distribuite su più nodi o esprimere requisiti topologici complessi come i domini NVLink per sistemi come NVIDIA GB200.
-
Vincoli dello scheduler: lo scheduler Kubernetes tratta le risorse GPU come numeri interi opachi, limitando la sua capacità di prendere decisioni basate sulla topologia o di gestire dipendenze complesse tra le risorse.
-
Complessità della configurazione: l'impostazione di diverse strategie di condivisione richiede un'etichettatura multipla e accurata dei nodi, creando complessità operativa.
ConfigMaps
Soluzioni con DRA
-
Selezione dinamica delle risorse: DRA consente ai carichi di lavoro di specificare requisiti dettagliati (memoria GPU, versioni dei driver e attributi specifici) al momento della richiesta.
resourceclaimsCiò consente un abbinamento più flessibile delle risorse. -
Conoscenza della topologia: attraverso parametri strutturati e selettori di dispositivi, DRA gestisce requisiti complessi come la comunicazione GPU tra nodi e le interconnessioni coerenti con la memoria.
-
Cross-node gestione delle risorse:
computeDomainsabilita il coordinamento delle risorse GPU distribuite su più nodi, fondamentale per sistemi come GB200 con canali IMEX. -
Workload-specific configurazione: ognuna
ResourceClaimspecifica strategie e configurazioni di condivisione diverse, consentendo un controllo granulare per carico di lavoro anziché impostazioni a livello di cluster. -
Integrazione avanzata dello scheduler: DRA fornisce allo scheduler informazioni dettagliate sul dispositivo e consente decisioni di posizionamento più intelligenti in base alla topologia hardware e alle caratteristiche delle risorse.
Importante: DRA non sostituisce completamente il plug-in del dispositivo NVIDIA. Il driver NVIDIA DRA funziona insieme al plug-in del dispositivo per fornire funzionalità avanzate. Il plug-in del dispositivo continua a gestire l'individuazione e la gestione di base delle GPU, mentre DRA aggiunge funzionalità avanzate di allocazione e pianificazione.
Istanze supportate da DRA e relative funzionalità
Il supporto DRA varia in base alla famiglia di istanze Amazon EC2 e all'architettura della GPU, come mostrato nella tabella seguente.
| Famiglia di istanze | Tipo GPU | Time-slicing | Supporto MIG | Supporto MPS | Supporto IMEX | Casi d’uso |
|---|---|---|---|---|---|---|
|
G5 |
NVIDIA A10G |
Sì |
No |
Sì |
No |
Carichi di lavoro di inferenza e grafica |
|
G6 |
NVIDIA L4 |
Sì |
No |
Sì |
No |
Inferenza AI ed elaborazione video |
|
G6e |
NVIDIA L40S |
Sì |
No |
Sì |
No |
Addestramento, inferenza e grafica |
|
P4d/P4de |
NVIDIA A100 |
Sì |
Sì |
Sì |
No |
Large-scale formazione e HPC |
|
P5 |
NVIDIA H100 |
Sì |
Sì |
Sì |
No |
Formazione sui modelli Foundation |
|
P6 |
NVIDIA B200 |
Sì |
Sì |
Sì |
No |
Modelli con miliardi o trilioni di parametri, formazione distribuita e inferenza |
|
P6e |
NVIDIA GB200 |
Sì |
Sì |
Sì |
Sì |
Modelli con miliardi o trilioni di parametri, formazione distribuita e inferenza |
Di seguito sono riportate le descrizioni di ciascuna funzionalità della tabella:
-
Time-slicing: consente a più carichi di lavoro di condividere le risorse di calcolo della GPU nel tempo.
-
Multi-Instance GPU (MIG): Hardware-level partizionamento che crea istanze GPU isolate.
-
Multi-Process service (MPS): consente l'esecuzione simultanea di più processi CUDA su una singola GPU.
-
Internode Memory Exchange (IMEX): Memory-coherent comunicazione tra nodi per GB200. UltraServers
Risorse aggiuntive
Per ulteriori informazioni sui driver Kubernetes DRA e NVIDIA DRA, consulta le seguenti risorse su: GitHub
Configura l'allocazione dinamica delle risorse per la gestione avanzata delle GPU
L'argomento seguente mostra come configurare l'allocazione dinamica delle risorse (DRA) per la gestione avanzata della GPU.
Prerequisiti
Prima di implementare DRA su Amazon EKS, assicurati che il tuo ambiente soddisfi i seguenti requisiti.
Configurazione del cluster
-
Cluster Amazon EKS con versione in esecuzione
1.33o successiva -
Gruppi di nodi gestiti Amazon EKS (il DRA è attualmente supportato solo da gruppi di nodi gestiti con AL2023 e AMI ottimizzate per NVIDIA Bottlerocket, non con Karpenter) https://github.com/kubernetes-sigs/karpenter/issues/1231
-
GPU-enabled Nodi di lavoro NVIDIA con tipi di istanza appropriati
Componenti richiesti
-
Versione del plug-in del dispositivo NVIDIA
0.17.1o successiva -
Versione del driver NVIDIA DRA o successiva
25.3.0
Passaggio 1: creare un cluster con un gruppo di DRA-enabled nodi utilizzando eksctl
-
Crea un file di configurazione del cluster denominato:
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 -
Crea il cluster:
eksctl create cluster -f dra-eks-cluster.yaml
Passaggio 2: implementa il plug-in del dispositivo NVIDIA
Implementa il plug-in del dispositivo NVIDIA per abilitare il rilevamento di base delle GPU:
-
Aggiungi il repository Helm del plug-in per dispositivi NVIDIA:
helm repo add nvidia https://nvidia.github.io/k8s-device-plugin helm repo update -
Crea valori personalizzati per il plug-in del dispositivo:
cat <<EOF > nvidia-device-plugin-values.yaml gfd: enabled: true nfd: enabled: true tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule EOF -
Installa il plug-in del dispositivo NVIDIA:
helm install nvidia-device-plugin nvidia/nvidia-device-plugin \ --namespace nvidia-device-plugin \ --create-namespace \ --version 0.17.1 \ --values nvidia-device-plugin-values.yaml
Fase 3: Implementazione del driver NVIDIA DRA Helm chart
-
Creare un file di
dra-driver-values.yamlvalori per il driver DRA:--- nvidiaDriverRoot: / gpuResourcesEnabledOverride: true resources: gpus: enabled: true computeDomains: enabled: true # Enable for GB200 IMEX support controller: tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule kubeletPlugin: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: "nvidia.com/gpu.present" operator: In values: ["true"] tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule -
Aggiungere il repository NVIDIA NGC Helm:
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia helm repo update -
Installa il driver NVIDIA DRA:
helm install nvidia-dra-driver nvidia/nvidia-dra-driver-gpu \ --version="25.3.0-rc.2" \ --namespace nvidia-dra-driver \ --create-namespace \ --values dra-driver-values.yaml
Fase 4: Verificare l'installazione del DRA
-
Verificare che le risorse dell'API DRA siano disponibili:
kubectl api-resources | grep resource.k8s.io/v1beta1Di seguito è riportato l'output previsto:
deviceclasses resource.k8s.io/v1beta1 false DeviceClass resourceclaims resource.k8s.io/v1beta1 true ResourceClaim resourceclaimtemplates resource.k8s.io/v1beta1 true ResourceClaimTemplate resourceslices resource.k8s.io/v1beta1 false ResourceSlice -
Controlla le classi di dispositivi disponibili:
kubectl get deviceclassesDi seguito è riportato un esempio dell'output previsto:
NAME AGE compute-domain-daemon.nvidia.com 4h39m compute-domain-default-channel.nvidia.com 4h39m gpu.nvidia.com 4h39m mig.nvidia.com 4h39mQuando un'istanza GPU G6 appena creata si unisce al cluster Amazon EKS con DRA abilitato, si verificano le seguenti azioni:
-
Il driver NVIDIA DRA rileva automaticamente la GPU A10G e ne crea due su quel nodo.
resourceslices -
Lo
gpu.nvidia.comslice registra il dispositivo GPU A10G fisico con le relative specifiche (memoria, capacità di elaborazione e altro). -
Poiché A10G non supporta il partizionamento MIG, la
compute-domain.nvidia.comslice crea un singolo dominio di calcolo che rappresenta l'intero contesto di calcolo della GPU. -
Queste
resourceslicesvengono quindi pubblicate sul server API Kubernetes, rendendo le risorse GPU disponibili per la pianificazione.resourceclaimsLo scheduler DRA può ora allocare in modo intelligente questa GPU ai pod che richiedono risorse GPU, fornendo una gestione delle risorse più flessibile rispetto ai tradizionali approcci ai plug-in per dispositivi
resourceclaimtemplates. Ciò avviene automaticamente senza intervento manuale. Il nodo diventa semplicemente disponibile per i carichi di lavoro della GPU una volta che il driver DRA completa il processo di individuazione e registrazione delle risorse.Quando si esegue il comando seguente:
kubectl get resourceslicesDi seguito è riportato un esempio dell'output previsto:
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
-
Continua su Pianifica un semplice carico di lavoro della GPU utilizzando l'allocazione dinamica delle risorse.
Pianifica un semplice carico di lavoro della GPU utilizzando l'allocazione dinamica delle risorse
Per pianificare un carico di lavoro GPU semplice utilizzando l'allocazione dinamica delle risorse (DRA), procedi nel seguente modo. Prima di procedere, assicurati di averlo seguito. Configura l'allocazione dinamica delle risorse per la gestione avanzata delle GPU
-
Crea una base
ResourceClaimTemplateper l'allocazione della GPU con un file chiamato:basic-gpu-claim-template.yaml--- apiVersion: v1 kind: Namespace metadata: name: gpu-test1 --- apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: namespace: gpu-test1 name: single-gpu spec: spec: devices: requests: - name: gpu deviceClassName: gpu.nvidia.com -
Applica il modello:
kubectl apply -f basic-gpu-claim-template.yaml -
Verifica lo stato:
kubectl get resourceclaimtemplates -n gpu-test1Di seguito è riportato un output di esempio:
NAME AGE single-gpu 9m16s -
Crea un Pod che utilizza il
ResourceClaimTemplatecon un file chiamatobasic-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" -
Applica e monitora il Pod:
kubectl apply -f basic-gpu-pod.yaml -
Controlla lo stato del Pod:
kubectl get pod -n gpu-test1Di seguito è riportato un esempio di output previsto:
NAME READY STATUS RESTARTS AGE gpu-pod 1/1 Running 0 13m -
Controlla lo
ResourceClaimstato:kubectl get resourceclaims -n gpu-test1Di seguito è riportato un esempio di output previsto:
NAME STATE AGE gpu-pod-gpu0-l76cg allocated,reserved 9m6s -
Visualizza i log del Pod per visualizzare le informazioni sulla GPU:
kubectl logs gpu-pod -n gpu-test1Di seguito è riportato un esempio di output previsto:
GPU 0: NVIDIA L4 (UUID: GPU-da7c24d7-c7e3-ed3b-418c-bcecc32af7c5)
Continuate Tecniche di ottimizzazione della GPU con allocazione dinamica delle risorse a utilizzare tecniche di ottimizzazione della GPU più avanzate utilizzando DRA.
Tecniche di ottimizzazione della GPU con allocazione dinamica delle risorse
I carichi di lavoro delle GPU moderni richiedono una gestione sofisticata delle risorse per ottenere un utilizzo ottimale e un'efficienza dei costi. Il DRA consente diverse tecniche di ottimizzazione avanzate che soddisfano diversi casi d'uso e funzionalità hardware:
-
Time-slicingconsente a più carichi di lavoro di condividere le risorse di calcolo della GPU nel tempo, rendendolo ideale per carichi di lavoro di inferenza con utilizzo sporadico della GPU. Per vedere un esempio, consulta Ottimizza i carichi di lavoro della GPU con il time-slicing.
-
Multi-Process service (MPS) consente l'esecuzione simultanea di più processi CUDA su una singola GPU con un isolamento migliore rispetto al time-slicing. Per vedere un esempio, consulta Ottimizza i carichi di lavoro della GPU con MPS.
-
Multi-Instance La GPU (MIG) fornisce il partizionamento a livello hardware, creando istanze GPU isolate con risorse di calcolo e memoria dedicate. Per vedere un esempio, consulta Ottimizza i carichi di lavoro della GPU con la GPU Multi-Instance.
-
Internode Memory Exchange (IMEX) consente una comunicazione coerente con la memoria tra i nodi per la formazione distribuita sui sistemi NVIDIA GB200. Per vedere un esempio, consulta Ottimizza i carichi di lavoro della GPU con IMEX utilizzando istanze P6e GB200.
Queste tecniche possono migliorare in modo significativo l'utilizzo delle risorse. Le organizzazioni segnalano un aumento dell'utilizzo delle GPU dal 30-40% con l'allocazione tradizionale all'80-90% con strategie di condivisione ottimizzate. La scelta della tecnica dipende dalle caratteristiche del carico di lavoro, dai requisiti di isolamento e dalle capacità hardware.
Ottimizza i carichi di lavoro della GPU con il time-slicing
Time-slicing consente a più carichi di lavoro di condividere le risorse di calcolo della GPU pianificandone l'esecuzione in sequenza sulla stessa GPU fisica. È ideale per carichi di lavoro di inferenza con utilizzo sporadico della GPU.
Effettuare le seguenti operazioni.
-
Definisci un formato
ResourceClaimTemplateper la suddivisione temporale con un file denominato: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 -
Definisci un Pod usando il time-slicing con un file chiamato:
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 -
Applica il modello e il Pod:
kubectl apply -f timeslicing-claim-template.yaml kubectl apply -f timeslicing-pod.yaml -
Monitora le richieste di risorse:
kubectl get resourceclaims -n timeslicing-gpu -wDi seguito è riportato un output di esempio:
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
Primo Pod (inference-pod-1)
-
Stato:
allocated,reserved -
Significato: DRA ha trovato una GPU disponibile e l'ha riservata per questo Pod
-
Stato del pod: inizia a funzionare immediatamente
Secondo pod (training-pod-2)
-
Stato:
pending -
Significato: in attesa che DRA configuri il time-slicing sulla stessa GPU
-
Stato del pod: in attesa di essere programmato
-
Lo stato passerà da
pendingallocated,reservedarunning
Ottimizza i carichi di lavoro della GPU con MPS
Multi-Process Service (MPS) consente l'esecuzione simultanea di più contesti CUDA su una singola GPU con un isolamento migliore rispetto al time-slicing.
Effettuare le seguenti operazioni.
-
Definite un
ResourceClaimTemplateper MPS con un file denominatomps-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 -
Definisci un Pod usando MPS con un file chiamato:
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 -
Applica il modello e crea più pod MPS:
kubectl apply -f mps-claim-template.yaml kubectl apply -f mps-pod.yaml -
Monitora i reclami relativi alle risorse:
kubectl get resourceclaims -n mps-gpu -wDi seguito è riportato un output di esempio:
NAME STATE AGE mps-multi-container-pod-shared-gpu-claim-2p9kx allocated,reserved 86s
Questa configurazione dimostra una vera condivisione della GPU utilizzando NVIDIA Multi-Process Service (MPS) tramite Dynamic Resource Allocation (DRA). A differenza del time-slicing, in cui i carichi di lavoro si alternano utilizzando la GPU in sequenza, MPS consente a entrambi i contenitori di funzionare contemporaneamente sulla stessa GPU fisica. L'idea chiave è che la condivisione di DRA MPS richiede più contenitori all'interno di un singolo Pod, non più Pod separati. Una volta implementato, il driver DRA ne ResourceClaim assegna uno al Pod e configura automaticamente MPS per consentire l'esecuzione simultanea dei contenitori di inferenza e di formazione.
Ogni container dispone di spazio di memoria GPU e risorse di calcolo isolati, con il demone MPS che coordina l'accesso all'hardware sottostante. È possibile verificare che funzioni effettuando le seguenti operazioni:
-
Verifica
nvidia-smi, che mostrerà entrambi i contenitori come processi M+C (MPS + Compute) che condividono lo stesso dispositivo GPU. -
Monitoraggio dei log di entrambi i contenitori, che mostreranno timestamp interlacciati che dimostrano l'esecuzione simultanea.
Questo approccio massimizza l'utilizzo della GPU consentendo ai carichi di lavoro complementari di condividere in modo efficiente il costoso hardware della GPU, anziché lasciarlo sottoutilizzato da un singolo processo.
Contenitore 1: contenitore di inferenza
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 |
+-----------------------------------------------------------------------------------------+
Contenitore 2: contenitore di formazione
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 |
+-----------------------------------------------------------------------------------------+
Ottimizza i carichi di lavoro della GPU con la GPU Multi-Instance
Multi-instance La GPU (MIG) fornisce il partizionamento a livello hardware, creando istanze GPU isolate con risorse di calcolo e memoria dedicate.
L'utilizzo del partizionamento MIG dinamico con vari profili richiede l'operatore GPU NVIDIA. https://github.com/NVIDIA/gpu-operatorWITH0—REBOOT=true nella configurazione di MIG Manager è essenziale per il successo delle implementazioni MIG.
Per lavorare con MIG in Amazon EKS sono necessari sia NVIDIA DRA Driver
Fase 1: Implementazione di NVIDIA GPU Operator
-
Aggiungi il repository NVIDIA GPU Operator:
helm repo add nvidia https://nvidia.github.io/gpu-operator helm repo update -
Crea un file:
gpu-operator-values.yamldriver: 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 -
Installa GPU Operator utilizzando il
gpu-operator-values.yamlfile:helm install gpu-operator nvidia/gpu-operator \ --namespace gpu-operator \ --create-namespace \ --version v25.3.1 \ --values gpu-operator-values.yamlQuesto diagramma Helm utilizza i seguenti componenti e diversi profili MIG:
-
Device Plugin (pianificazione delle risorse GPU)
-
DCGM Exporter (metriche e monitoraggio della GPU)
-
Node Feature Discovery (NFD - etichettatura hardware)
-
GPU Feature Discovery (GFD - etichettatura) GPU-specific
-
MIG Manager (partizionamento della GPU) Multi-instance
-
Container Toolkit (runtime del contenitore GPU)
-
Operator Controller (gestione del ciclo di vita)
-
-
Verifica i pod di distribuzione:
kubectl get pods -n gpu-operatorDi seguito è riportato un output di esempio:
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 -
Crea un cluster Amazon EKS con un gruppo di nodi gestiti da P4de per testare gli esempi MIG:
apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: dra-eks-cluster region: us-east-1 version: '1.33' managedNodeGroups: # P4DE MIG Node Group with Capacity Block Reservation - name: p4de-mig-nodes amiFamily: AmazonLinux2023 instanceType: p4de.24xlarge # Capacity settings desiredCapacity: 0 minSize: 0 maxSize: 1 # Use specific subnet in us-east-1b for capacity reservation subnets: - us-east-1b # AL2023 NodeConfig for RAID0 local storage only nodeadmConfig: apiVersion: node.eks.aws/v1alpha1 kind: NodeConfig spec: instance: localStorage: strategy: RAID0 # Node labels for MIG configuration labels: nvidia.com/gpu.present: "true" nvidia.com/gpu.product: "A100-SXM4-80GB" nvidia.com/mig.config: "p4de-half-balanced" node-type: "p4de" vpc.amazonaws.com/efa.present: "true" accelerator: "nvidia" # Node taints taints: - key: nvidia.com/gpu value: "true" effect: NoSchedule # EFA support efaEnabled: true # Placement group for high-performance networking placementGroup: groupName: p4de-placement-group strategy: cluster # Capacity Block Reservation (CBR) # Ensure CBR ID matches the subnet AZ with the Nodegroup subnet spot: false capacityReservation: capacityReservationTarget: capacityReservationId: "cr-abcdefghij" # Replace with your capacity reservation IDNVIDIA GPU Operator utilizza l'etichetta aggiunta ai nodi
nvidia.com/mig.config: "p4de-half-balanced"e partiziona la GPU con il profilo specificato. -
Accedi all'istanza.
p4de -
Esegui il comando seguente:
nvidia-smi -LDovresti vedere il seguente output di esempio:
[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 ha applicato con successo il profilo p4de-half-balanced MIG all'istanza P4DE, creando partizioni GPU a livello hardware così come configurate. Ecco come funziona il partizionamento:
L'operatore GPU ha applicato questa configurazione dal tuo profilo MIG incorporato:
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
Dal tuo nvidia-smi -L output, ecco cosa ha creato l'operatore GPU:
-
MIG-enabled GPU (0-3): hardware partizionato
-
GPU 0: NVIDIA A100-SXM4-80GB
-
Dispositivo 0 MIG 3g.40 GB: carichi di lavoro di grandi dimensioni (40 GB di memoria, 42 SM)
-
Dispositivo 1 MIG 2g.20 gb: carichi di lavoro medi (20 GB di memoria, 28 SM)
-
Dispositivo 2 MIG 1g.10gb: piccoli carichi di lavoro (10 GB di memoria, 14 SM)
-
Dispositivo 3 MIG 1g.10gb: piccoli carichi di lavoro (10 GB di memoria, 14 SM)
-
-
GPU 1: NVIDIA A100-SXM4-80GB
-
Dispositivo MIG 3g.40gb 0 — Layout di partizione identico
-
Dispositivo MIG 2g.20gb 1
-
Dispositivo MIG 1g.10gb 2
-
Dispositivo MIG 1g.10gb 3
-
-
GPU 2 e GPU 3: stesso modello di GPU 0 e GPU 1
-
-
GPU complete (4-7): nessun partizionamento MIG
-
GPU 4: NVIDIA — GPU completa da 80 GB A100-SXM4-80GB
-
GPU 5: NVIDIA — GPU completa da 80 GB A100-SXM4-80GB
-
GPU 6: NVIDIA — GPU completa da 80 GB A100-SXM4-80GB
-
GPU 7: NVIDIA — GPU completa da 80 GB A100-SXM4-80GB
-
Una volta che l'operatore GPU NVIDIA crea le partizioni MIG, il driver NVIDIA DRA rileva automaticamente queste istanze isolate dall'hardware e le rende disponibili per l'allocazione dinamica delle risorse in Kubernetes. Il driver DRA rileva ogni istanza MIG con il suo profilo specifico (1g.10gb, 2g.20gb, 3g.40gb) e le espone come risorse programmabili tramite la classe del dispositivo. mig.nvidia.com
Il driver DRA monitora continuamente la topologia MIG e mantiene un inventario delle istanze disponibili su tutte le GPU. Quando un Pod richiede un profilo MIG specifico tramite aResourceClaimTemplate, il driver DRA seleziona in modo intelligente un'istanza MIG appropriata da qualsiasi GPU disponibile, consentendo una vera multi-tenancy a livello di hardware. Questa allocazione dinamica consente l'esecuzione simultanea di più carichi di lavoro isolati sulla stessa GPU fisica mantenendo rigorosi limiti di risorse e garanzie prestazionali.
Fase 2: Verifica l'allocazione delle risorse MIG
Eseguiamo ora alcuni esempi per dimostrare come DRA alloca dinamicamente le istanze MIG a diversi carichi di lavoro. Implementa i pod resourceclaimtemplates e testali per vedere come il driver DRA colloca i carichi di lavoro tra le partizioni MIG disponibili, consentendo a più contenitori di condividere le risorse GPU con isolamento a livello hardware.
-
Crea
resourceclaimtemplatesper contenere il MIG:mig-claim-template.yamlapiVersion: 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' -
Applica i tre modelli:
kubectl apply -f mig-claim-template.yaml -
Esegui il comando seguente:
kubectl get resourceclaimtemplates -n mig-gpuDi seguito è riportato un output di esempio:
NAME AGE mig-large-template 71m mig-medium-template 71m mig-small-template 71m -
Crea
mig-pod.yamlper pianificare più lavori per sfruttare questoresourceclaimtemplates:--- # 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 -
Applica questa specifica, che dovrebbe utilizzare tre Pod:
kubctl apply -f mig-pod.yamlQuesti Pod devono essere programmati dal driver DRA.
-
Controllate i log del driver DRA Pod e vedrete un risultato simile a questo:
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**],}] -
Verificate
resourceclaimsper vedere lo stato del Pod:kubectl get resourceclaims -n mig-gpu -wDi seguito è riportato un output di esempio:
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 0sCome puoi vedere, tutti i Pod sono stati spostati da in sospeso a
allocated,reservedtramite il driver DRA. -
Esegui
nvidia-smidal nodo. Noterai che tre processori Python sono in esecuzione: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 |** +-----------------------------------------------------------------------------------------+
Ottimizza i carichi di lavoro della GPU con IMEX utilizzando istanze P6e GB200
IMEX (Internode Memory Exchange) consente una comunicazione coerente con la memoria tra i nodi per il training distribuito su NVIDIA GB200. UltraServers
Effettuare le seguenti operazioni.
-
Definisci un training
ComputeDomainper più nodi con un file denominatoimex-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 -
Definisci un Pod usando i canali IMEX con un file chiamato:
imex-pod.yamlapiVersion: 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: NoScheduleNota
Ciò richiede istanze P6e GB200.
-
Implementa IMEX applicando i modelli and:
ComputeDomainkubectl apply -f imex-claim-template.yaml kubectl apply -f imex-compute-domain.yaml kubectl apply -f imex-pod.yaml -
Controlla lo stato.
ComputeDomainkubectl get computedomain distributed-training-domain -
Monitora la distribuzione del demone IMEX.
kubectl get pods -n nvidia-dra-driver -l resource.nvidia.com/computeDomain -
Controlla i canali IMEX nel Pod:
kubectl exec imex-distributed-training -- ls -la /dev/nvidia-caps-imex-channels/ -
Visualizza i log del Pod:
kubectl logs imex-distributed-trainingDi seguito è riportato un esempio dell'output previsto:
=== 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
Per ulteriori informazioni, vedere l'esempio di NVIDIA