

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

# Calcolo e scalabilità automatica
<a name="aiml-compute"></a>

**Suggerimento**  
 [Esplora le](https://aws-experience.com/emea/smb/events/series/get-hands-on-with-amazon-eks?trk=4a9b4147-2490-4c63-bc9f-f8a84b122c8c&sc_channel=el) best practice tramite i workshop Amazon EKS.

## Ottimizzazione delle risorse GPU e gestione dei costi
<a name="_gpu_resource_optimization_and_cost_management"></a>

### Pianifica i carichi di lavoro con i requisiti della GPU utilizzando le etichette Well-Known
<a name="_schedule_workloads_with_gpu_requirements_using_well_known_labels"></a>

[https://karpenter.sh/v1.0/concepts/scheduling/#labels](https://karpenter.sh/v1.0/concepts/scheduling/#labels) La mancata definizione di questi parametri può comportare la pianificazione dei pod su istanze con risorse GPU inadeguate, con conseguenti guasti o un peggioramento delle prestazioni. Ti consigliamo di utilizzare [NodeSelector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) o [Node affinity per specificare su quale nodo](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity) deve essere eseguito un pod e di impostare le risorse di calcolo (CPU, memoria, GPU ecc.) nella sezione [delle risorse](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) del pod.

 **Esempio** 

Ad esempio, utilizzando il selettore di nodi di nomi 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
<a name="_use_kubernetes_device_plugin_for_exposing_gpus"></a>

Per esporre le GPU sui nodi, è necessario installare il driver GPU NVIDIA sul sistema operativo del nodo e configurare il runtime del contenitore per consentire allo scheduler Kubernetes di assegnare pod ai nodi con GPU disponibili. Il processo di configurazione per il plugin per dispositivi NVIDIA Kubernetes dipende dall'AMI EKS Accelerated che stai utilizzando:
+  AMI **[Bottlerocket Accelerated: questa AMI](https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami-bottlerocket.html)** include il **driver** GPU NVIDIA e [il NVIDIA Kubernetes Device](https://github.com/NVIDIA/k8s-device-plugin) Plugin è preinstallato e pronto all'uso, abilitando il supporto GPU immediatamente. Non è richiesta alcuna configurazione aggiuntiva per esporre le GPU allo scheduler Kubernetes.
+  **AMI **[accelerata AL2023: questa AMI](https://aws.amazon.com/blogs/containers/amazon-eks-optimized-amazon-linux-2023-accelerated-amis-now-available/)** include il driver GPU NVIDIA, ma il plugin per dispositivi [NVIDIA Kubernetes non](https://github.com/NVIDIA/k8s-device-plugin) è preinstallato.** È 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, `eksctl` selezionerà automaticamente l'AMI appropriata e installerà il NVIDIA Kubernetes Device Plugin. [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](https://github.com/NVIDIA/gpu-operator) per gestire componenti come il plug-in per dispositivi NVIDIA Kubernetes, prendi nota di disabilitare la gestione del driver GPU NVIDIA e del toolkit NVIDIA Container come indicato nei driver GPU NVIDIA e nella documentazione di NVIDIA Container Toolkit NVIDIA. Pre-Installed ](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/getting-started.html#pre-installed-nvidia-gpu-drivers-and-nvidia-container-toolkit)

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 rientra nella capacità del nodo e nelle risorse allocabili. Ad esempio, dovrebbe essere visualizzato un nodo con una GPU. `nvidia.com/gpu: 1` Per ulteriori informazioni, consulta la [Kubernetes GPU Scheduling](https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/) Guide.

### Utilizza molti tipi di istanze EC2 diversi
<a name="_use_many_different_ec2_instance_types"></a>

L'utilizzo del maggior numero possibile di tipi di istanze EC2 diversi è una best practice importante per la scalabilità su Amazon EKS, come indicato nella sezione. [Piano dati Kubernetes](scale-data-plane.md) 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 sono disponibili istanze. È importante comprendere le caratteristiche uniche dei AI/ML carichi di lavoro prima di diversificare arbitrariamente. Esamina i tipi di istanze disponibili utilizzando lo strumento [EC2 Instance Type Explorer](https://aws.amazon.com/ec2/instance-explorer/) per generare un elenco di tipi di istanze che soddisfano i tuoi requisiti di elaborazione specifici ed evita di limitare arbitrariamente il tipo di istanze che possono essere utilizzate nel tuo cluster.

Le istanze di elaborazione accelerata sono offerte in diversi modelli di acquisto per soddisfare carichi di lavoro a breve, medio termine e stazionari. Per carichi di lavoro a breve termine, flessibili e tolleranti ai guasti, in cui vorresti evitare di effettuare una prenotazione, dai un'occhiata alle istanze Spot. I blocchi di capacità, On-Demand le istanze e i piani di risparmio consentono di fornire istanze di elaborazione accelerate per carichi di lavoro a medio e lungo termine. Per aumentare le possibilità di accedere correttamente 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 consentire a un Karpenter di effettuare il provisioning NodePool di istanze G e P superiori alla terza generazione (ad esempio, p3). Per ulteriori informazioni, consulta la sezione [Le migliori pratiche di scalabilità EKS](scalability.md).

```
- 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 i dettagli sull'uso delle istanze Spot per le GPU, consulta «Prendi in considerazione l'utilizzo di istanze Spot Amazon EC2 per GPU con Karpenter» di seguito.

### Prendi in considerazione l'utilizzo di istanze Spot Amazon EC2 per GPU con Karpenter
<a name="_consider_using_amazon_ec2_spot_instances_for_gpus_with_karpenter"></a>

Le istanze Spot di Amazon EC2 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 necessita del ripristino della capacità. Per ulteriori informazioni, consulta le [istanze Spot](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-spot-instances.html) nella Guida per l'utente di Amazon EC2. Amazon EC2 Spot può essere un'ottima scelta per carichi di lavoro con tolleranza ai guasti, stateless e flessibili (tempo e tipo di istanza). [Per ulteriori informazioni su quando utilizzare le istanze Spot, consulta le best practice per le istanze Spot 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, High Performance Computing (HPC) e carichi di lavoro di rendering. Le istanze Spot non sono adatte per carichi di lavoro rigidi, stateful, intolleranti ai guasti o strettamente accoppiati tra i nodi di istanza (ad esempio, carichi di lavoro con processi paralleli che dipendono fortemente l'uno dall'altro per il calcolo, che richiedono una comunicazione costante tra i nodi, come applicazioni di calcolo ad alte prestazioni come la fluidodinamica computazionale o i database distribuiti con interdipendenze complesse). MPI-based Ecco i casi d'uso specifici che consigliamo (senza un 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 adatti allo 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 l'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 potenziali interruzioni Spot.
+  **Hyper-parameter ottimizzazione**: utilizza le istanze Spot per eseguire lavori di ottimizzazione esplorativa in modo opportuno, 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 essere riavviate 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 la messa a punto con solidi meccanismi di checkpoint per riprendere dall'ultimo stato salvato, riducendo al minimo l'impatto delle interruzioni delle istanze.
+  **Inferenza in batch**: utilizza le istanze Spot per elaborare grandi batch di richieste di inferenza offline in modo non in tempo reale, dove i lavori possono essere messi in pausa e ripresi, offrendo il miglior allineamento con i risparmi sui costi di Spot e gestendo potenziali interruzioni attraverso nuovi tentativi o diversificazione.
+  **Sottoinsiemi di formazione opportunistici**: utilizza le istanze Spot per carichi di lavoro di formazione marginali o sperimentali (ad esempio, modelli più piccoli con meno di 10 milioni di parametri), dove le interruzioni sono accettabili e possono essere applicate ottimizzazioni dell'efficienza come la diversificazione tra tipi di istanze o regioni, sebbene non sia consigliabile 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 come «spot» nel tuo Karpenter NodePool, Karpenter fornirà le istanze Spot di default senza alcuna configurazione aggiuntiva. Tuttavia, per abilitare il Spot-to-Spot consolidamento avanzato, che sostituisce i nodi Spot sottoutilizzati con alternative Spot più economiche, è necessario abilitare il SpotToSpotConsolidation [feature gate](https://karpenter.sh/docs/reference/settings/) impostando --feature-gates =true negli argomenti del controller Karpenter o tramite la variabile di ambiente FEATURE\_GATES. SpotToSpotConsolidation Karpenter utilizza la strategia di allocazione ottimizzata in base al rapporto prezzo/capacità per effettuare il [provisioning](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-allocation-strategy.html) delle istanze EC2. [In base NodePool ai requisiti e ai vincoli dei pod, Karpenter racchiude 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](https://aws.amazon.com/ec2/instance-explorer/) che soddisfano i tuoi requisiti di elaborazione specifici.
+  **Assicurati che i carichi di lavoro siano stateless,** flessibili e tolleranti agli errori. 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 potenzialmente su Spot più a lungo. Abilita [la gestione delle interruzioni Spot](https://karpenter.sh/docs/concepts/disruption/#interruption) in Karpenter configurando il valore settings.InterruptionQueue Helm con il nome della coda AWS SQS per catturare gli eventi di interruzione Spot. Ad esempio, durante l'installazione tramite Helm, usa --set «settings.interruptionQueue=$ {CLUSTER\_NAME}». Per vedere un esempio[, consulta la](https://karpenter.sh/docs/getting-started/getting-started-with-karpenter/) guida Getting Started with Karpenter. Quando Karpenter rileva un evento di interruzione Spot, cordone, contamina, drena e chiude automaticamente i nodi prima dell'evento di interruzione per massimizzare il periodo di tolleranza di terminazione dei pod. Allo stesso tempo, Karpenter avvierà immediatamente un nuovo nodo in modo che possa essere pronto il prima possibile.
+  **Evitate di limitare eccessivamente la selezione del tipo di istanza.** Dovreste evitare il più possibile di vincolare i tipi di istanza. Non limitando i tipi di istanze, vi è una maggiore possibilità di acquisire capacità Spot su larga scala con una frequenza inferiore di interruzioni delle istanze Spot a un costo inferiore. Ad esempio, evita di limitarti a tipi specifici (ad esempio g5.xlarge). Prendi in considerazione 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 su 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 zona di disponibilità (AZ) specifica. Quando Karpenter tenta di fornire un nuovo nodo, seleziona un tipo di istanza che soddisfa i requisiti del nodo. NodePool Se nessun tipo di istanza compatibile dispone della capacità Spot in qualsiasi zona, il provisioning fallisce. Per evitare questo problema, consenti istanze della serie g più ampie (generazione 4 o superiore) di NVIDIA 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 tuo 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 zona ma abbondante in un'altra. Ogni combinazione unica di un tipo di istanza e una zona di disponibilità costituisce un pool di capacità Spot separato. Richiedendo la capacità in tutte le AZ di una regione che soddisfi i NodePool requisiti di Karpenter, è possibile cercare in modo efficace 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, oppure 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)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/work-with-spot-placement-score.html) è uno strumento che fornisce un punteggio per aiutarti a valutare la probabilità di successo di una richiesta Spot. Quando usi SPS, devi prima specificare i requisiti di elaborazione 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 è molto probabile, ma non è garantito che la richiesta Spot abbia successo. 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 ulteriori informazioni, consulta [la Guida alla creazione di una dashboard Spot Placement Score Tracker su AWS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/work-with-spot-placement-score.html). Poiché la capacità di Spot oscilla continuamente, SPS ti aiuterà a identificare la combinazione di tipi di istanze, AZ e regioni più adatta ai vincoli del 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 aiutarti a scoprire automaticamente la probabilità di acquisire capacità Spot, forniamo una guida per la creazione di una dashboard di monitoraggio SPS. Questa soluzione monitora i punteggi SPS nel tempo utilizzando una configurazione YAML per configurazioni diversificate (ad esempio, i requisiti delle istanze, comprese le GPU), archivia 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 possibilità di utilizzare altre regioni AWS. [Per ulteriori informazioni, consulta Come funziona il punteggio di posizionamento di Spot.](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/how-sps-works.html)
+  **Gestisci con garbo le interruzioni e i test di Spot**. Per un pod con un periodo di terminazione superiore a due minuti, il vecchio nodo verrà interrotto prima della riprogrammazione dei pod, 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, salvando i progressi su uno storage persistente come Amazon S3) per riprendere dopo le interruzioni, estendi la terminazione GracePeriodSeconds (l'impostazione predefinita è 30 secondi) nelle specifiche Pod per consentire più tempo per uno spegnimento regolare e gestisci le interruzioni utilizzando i segnali SIGTERM del ciclo di vita PreStop all'interno della tua applicazione per attività di spegnimento senza intoppi come la pulizia, il salvataggio dello stato e la chiusura della connessione and/or . Per i carichi di lavoro in tempo reale, in cui il tempo di scalabilità è importante e i carichi di lavoro impiegano più di due minuti prima che l'applicazione sia pronta a servire il traffico, prendi in considerazione l'ottimizzazione dei tempi di avvio dei container e di caricamento dei modelli ML mediante revisioni [Archiviazione](aiml-storage.md) e [Scalabilità e prestazioni delle applicazioni](aiml-performance.md) best practice. Per testare un nodo sostitutivo, usa [AWS Fault Injection Service](https://aws.amazon.com/fis/) (FIS) per simulare le interruzioni 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 delle 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 tuo carico di lavoro è flessibile a seconda delle istanze. 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 mantiene il carico di lavoro funzionante e comprendi eventuali impatti sulle prestazioni (ad esempio, sulla produttività o sui tempi di completamento). Nell'ambito della diversificazione dei carichi di lavoro, considera quanto segue:
+  **Esamina la compatibilità tra CUDA** e framework. I carichi di lavoro della GPU potrebbero essere ottimizzati per hardware o tipi di GPU specifici (ad esempio, V100 in p3 rispetto a A100 in p4) o scritti per versioni CUDA specifiche per librerie come, ad esempio TensorFlow, assicurati di verificare la compatibilità per i 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 impedirne 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 di profilare l'utilizzo della memoria del modello durante l'esecuzione utilizzando strumenti come [DCGM Exporter](https://docs.nvidia.com/datacenter/dcgm/latest/gpu-telemetry/dcgm-exporter.html) 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 in base al 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 o arresti anomali di memoria esaurita (OOM). Per le istanze Spot in EKS, ciò può limitare la diversificazione. Ad esempio, non è possibile includere tipi di VRAM inferiori se il modello non è adatto, il che potrebbe limitare l'accesso ai pool di capacità e aumentare il rischio di interruzione. Tieni presente che per l'inferenza a singola GPU e a nodo singolo (ad esempio, più pod pianificati sullo stesso nodo per utilizzare le relative risorse GPU), ciò potrebbe limitare la diversificazione, poiché nella configurazione Spot puoi includere solo tipi di istanze con VRAM sufficiente.
+  **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 core (CUDA/Tensor/RT) e la precisione a virgola mobile necessarie 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 periodo di tempo specifico 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 in modo che si diversifichi tra famiglie e generazioni di istanze NodePool GPU compatibili. Questo approccio garantisce un'elevata disponibilità attingendo a più pool Spot, mantenendo al contempo le prestazioni attraverso vincoli sulle funzionalità, sulla memoria e sull'architettura della GPU. Supporta l'utilizzo di alternative quando la capacità dell'istanza è limitata, riducendo al minimo le interruzioni e ottimizzando la latenza di inferenza. Questo esempio NodePool indica che utilizza istanze delle serie g e p maggiori di 3, con 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
<a name="_implement_checkpointing_for_long_running_training_jobs"></a>

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 i lavori di lunga durata possono far risparmiare peso al modello e gli stati dell'ottimizzatore per riprendere l'addestramento dopo guasti, come problemi hardware o interruzioni delle istanze 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, si salvano le istantanee del modello durante l'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, incluse quelle causate da guasti hardware o interruzioni delle istanze Spot di Amazon EC2.

Senza checkpoint, le interruzioni possono comportare uno spreco di tempo di elaborazione e una perdita di progressi, il che è costoso per i lavori di formazione di lunga durata. Il checkpointing consente ai lavori di salvare periodicamente il loro stato (ad esempio, pesi del modello e stati dell'ottimizzatore) e di riprendere dall'ultimo checkpoint (ultimo batch elaborato) dopo un'interruzione. Per implementare il checkpointing, progetta la tua applicazione in modo che elabori i dati in grandi batch e salvi i risultati intermedi su uno storage persistente, ad esempio un bucket Amazon S3 tramite il driver Mountpoint for [Amazon S3](https://docs.aws.amazon.com/eks/latest/userguide/s3-csi.html) CSI mentre il processo di formazione procede.

 **Casi d'uso** 

Il checkpointing è particolarmente utile in scenari specifici per bilanciare la tolleranza agli errori 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, più di 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 progressi a causa delle 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 checkpoint consente una ripresa rapida, rendendo Spot fattibile per ridurre i costi in carichi di lavoro con tolleranza ai guasti.
+  **Formazione distribuita su larga scala**: per le configurazioni con hundreds/thousands acceleratori (ad esempio, >100 GPU), in cui il tempo medio tra i guasti diminuisce linearmente con la scala. model/data Utilizzatelo per il 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 a più livelli (rapido, locale ogni 5-30 minuti per i transitori, duraturo ogni ora per i guasti più gravi) ottimizzano i tempi di ripristino rispetto all'efficienza.

### Utilizza ML Capacity Blocks per garantire la capacità delle istanze P e Trainium
<a name="_use_ml_capacity_blocks_for_capacity_assurance_of_p_and_trainium_instances"></a>

 [I Capacity Blocks for ML](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-blocks.html) ti consentono di prenotare istanze GPU molto richieste, in particolare istanze P (ad esempio, p6-b200, p5, p5e, p5en, p4d, p4de) e istanze Trainium (ad es. trn1, trn2), da avviare quasi immediatamente o in date future per supportare i carichi di lavoro di machine learning (ML) di breve durata. Queste prenotazioni sono ideali per garantire la capacità necessaria per attività ad alta intensità di calcolo come la formazione 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 ulteriori informazioni sui prezzi, consulta i prezzi di [EC2 Capacity Blocks for ML.](https://aws.amazon.com/ec2/capacityblocks/pricing/)

Per riservare le GPU per i AI/ML carichi di lavoro su Amazon EKS per una garanzia di capacità prevedibile, consigliamo di utilizzare i blocchi di capacità ML per i carichi di lavoro a breve termine o le [prenotazioni di capacità (ODCR) per la garanzia On-Demand della capacità](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-reservations.html) generica.
+ Gli ODCR consentono di riservare la capacità delle istanze EC2 (ad esempio, istanze GPU come g5 o p5) in una zona di disponibilità specifica per un determinato periodo, garantendo la disponibilità anche in caso di forte domanda. Gli ODCR non hanno alcun impegno a lungo termine, ma pagano la On-Demand tariffa per la capacità riservata, utilizzata o inattiva. [In EKS, gli ODCR sono supportati da tipi di nodi come [Karpenter](https://karpenter.sh/) 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 l'utilizzo del campo. NodeClass `capacityReservationSelectorTerms` [Consulta la NodePools documentazione](https://karpenter.sh/docs/concepts/nodeclasses/#speccapacityreservationselectorterms) di Karpenter.
+ I Capacity Blocks 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 la formazione di modelli, la messa a punto o la sperimentazione. Riservi la capacità per un periodo definito (in genere da 24 ore a 182 giorni) a partire da una data futura, pagando solo per il tempo prenotato. Sono prepagati, richiedono una pianificazione preliminare per le esigenze di capacità e non supportano la scalabilità automatica, ma sono collocati in EC2 per una rete a bassa latenza. UltraClusters Fanno pagare solo per il periodo prenotato. Per saperne di più, consulta [Trova e acquista blocchi di capacità](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/capacity-blocks-purchase.html) oppure inizia a configurare gruppi di nodi gestiti con Capacity Blocks seguendo le istruzioni riportate in [Creare un gruppo di nodi gestiti con blocchi di capacità per ML](https://docs.aws.amazon.com/eks/latest/userguide/capacity-blocks-mng.html).

Riserva la capacità tramite la Console di gestione AWS e configura i tuoi nodi per utilizzare blocchi di capacità ML. Pianifica le prenotazioni in base alla pianificazione dei carichi di lavoro ed esegui i test in un cluster di staging. Per ulteriori informazioni, consulta la [documentazione relativa ai blocchi di capacità](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-blocks.html).

### Prendi in considerazione On-Demand Amazon EC2 Spot o On-Demand Capacity Reservations (ODCR) per istanze G Amazon EC2
<a name="_consider_on_demand_amazon_ec2_spot_or_on_demand_capacity_reservations_odcrs_for_g_amazon_ec2_instances"></a>

Per le istanze G Amazon EC2, considera le diverse opzioni di acquisto tra le istanze Spot di Amazon On-Demand EC2 e le prenotazioni di capacità. On-Demand [Gli ODCR](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-reservations.html) consentono di riservare la capacità delle istanze EC2 in una zona di disponibilità specifica per un determinato periodo, garantendo la disponibilità anche in caso di forte domanda. A differenza degli 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 funzionalità GPU diverse, come l'inferenza o la 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 hanno alcun impegno a lungo termine, ma pagano la On-Demand tariffa per la capacità riservata, utilizzata o inattiva. Gli ODCR possono essere creati per un uso immediato o programmati per date future, garantendo flessibilità nella pianificazione della capacità. [In Amazon EKS, gli ODCR sono supportati da tipi di nodi come [Karpenter](https://karpenter.sh/) 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 l'utilizzo del campo. NodeClass `capacityReservationSelectorTerms` [Consulta la NodePools documentazione](https://karpenter.sh/docs/concepts/nodepools/) di Karpenter. Per ulteriori informazioni sulla creazione di ODCR, inclusi i comandi CLI, consulta la Guida introduttiva alla prenotazione della [On-Demand capacità](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-reservations-getting-started.html).

### Prendi in considerazione altri tipi e dimensioni di istanze accelerate
<a name="_consider_other_accelerated_instance_types_and_sizes"></a>

La selezione dell'istanza accelerata e della dimensione appropriate è essenziale per ottimizzare prestazioni e costi nei carichi di lavoro ML su Amazon EKS. Ad esempio, diverse famiglie di istanze GPU hanno prestazioni e funzionalità diverse, come la memoria GPU. **Per aiutarti a scegliere l'opzione con il miglior rapporto prezzo/prestazioni, consulta le istanze GPU disponibili nella pagina Tipi di istanze [EC2](https://aws.amazon.com/ec2/instance-types/) in Accelerated Computing.** Valuta diversi tipi e dimensioni di istanze per trovare la soluzione migliore per i tuoi requisiti di carico di lavoro specifici. Prendi in considerazione fattori come il numero di GPU, la memoria e le prestazioni di rete. Selezionando attentamente il tipo e la dimensione dell'istanza GPU corretti, è possibile ottenere un migliore utilizzo delle risorse e un'efficienza dei costi nei cluster EKS.

Se si utilizza un'istanza GPU in un nodo EKS, per impostazione predefinita il `nvidia-device-plugin-daemonset` pod verrà inserito nel `kube-system` namespace. [Per capire rapidamente se state utilizzando appieno le GPU della vostra istanza, potete usare nvidia-smi come mostrato di seguito:](https://docs.nvidia.com/deploy/nvidia-smi/index.html)

```
kubectl exec nvidia-device-plugin-daemonset-xxxxx \
  -n kube-system -- nvidia-smi \
  --query-gpu=index,power.draw,power.limit,temperature.gpu,utilization.gpu,utilization.memory,memory.free,memory.used \
  --format=csv -l 5
```
+ Se `utilization.memory` è vicino al 100%, è probabile che i tuoi codici siano vincolati alla memoria. Ciò significa che la GPU (memoria) è completamente utilizzata, ma potrebbe suggerire che sia necessario studiare 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 a. `power.draw` `power.limit` Se questo rapporto è pari o superiore al 100%, i tuoi codici stanno utilizzando appieno la capacità di calcolo della GPU.
+ Il `-l 5` flag indica di emettere le metriche ogni 5 secondi. Nel caso di un singolo tipo di istanza GPU, il flag di interrogazione dell'indice non è necessario.

Per ulteriori informazioni, consulta le [istanze GPU](https://docs.aws.amazon.com/dlami/latest/devguide/gpu.html) nella documentazione di AWS.

### Ottimizza l'allocazione delle risorse GPU con Time-Slicing, MIG e l'allocazione frazionata della GPU
<a name="_optimize_gpu_resource_allocation_with_time_slicing_mig_and_fractional_gpu_allocation"></a>

I limiti statici delle risorse in Kubernetes (ad esempio, CPU, memoria, numero di GPU) possono portare a un approvvigionamento eccessivo o al 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 traffico, 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 tramite diverse opzioni:
+  **Sfrutta i selettori dei nodi e l'affinità dei nodi per influenzare la pianificazione**: assicurati che i nodi forniti e i pod siano pianificati sulle GPU appropriate per il carico di lavoro (ad esempio,) `karpenter.k8s.aws/instance-gpu-name: "a100"`
+  **Time-Slicing**: Pianifica i carichi di lavoro per 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 è supportata con le 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 batch di diverse dimensioni tramite time-slicing.
+  **Allocazione frazionata della GPU: utilizza la pianificazione basata su software per allocare** parti del calcolo o della memoria di una GPU ai carichi di lavoro, offrendo flessibilità per carichi di lavoro dinamici. [NVIDIA KAI Scheduler, parte della piattaforma, consente tutto ciò permettendo ai](https://github.com/NVIDIA/KAI-Scheduler) 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 time-slicing e MIG. Per saperne di più, consulta le [Time-Slicing GPU in Kubernetes](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/gpu-sharing.html) e la [condivisione delle GPU su Amazon EKS con istanze NVIDIA](https://aws.amazon.com/blogs/containers/gpu-sharing-on-amazon-eks-with-nvidia-time-slicing-and-accelerated-ec2-instances/) time-slicing e accelerate EC2.

 **Esempio** 

Ad esempio, per abilitare il time-slicing con il 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 frazionata 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
<a name="_node_resiliency_and_training_job_management"></a>

### Implementa Node Health Checks con il ripristino automatico
<a name="_implement_node_health_checks_with_automated_recovery"></a>

Per i lavori di formazione distribuiti su Amazon EKS che richiedono comunicazioni frequenti tra nodi, come l'addestramento su modelli multi-GPU su più nodi, problemi hardware come guasti della GPU o dell'EFA possono causare interruzioni dei lavori di formazione. Queste interruzioni possono portare alla perdita di progressi nella 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 utilizzare EKS Node **Monitoring Agent con Auto Repair o Amazon**. SageMaker HyperPod** Mentre EKS Node Monitoring Agent with Auto Repair offre funzionalità come il monitoraggio dello stato dei nodi e la riparazione automatica utilizzando meccanismi Kubernetes standard, SageMaker HyperPod offre resilienza mirata e funzionalità aggiuntive progettate specificamente per la formazione ML su larga scala, come controlli approfonditi dello stato e ripresa automatica dei lavori.
+ L'[EKS Node Monitoring Agent](https://docs.aws.amazon.com/eks/latest/userguide/node-health.html) con Node Auto Repair monitora continuamente lo stato dei nodi leggendo i log `Ready` e applicando NodeConditions, incluse condizioni standard come quelle specifiche dell'hardware accelerato per identificare problemi come guasti della GPU o della rete. Quando un nodo è considerato non integro, Node Auto Repair lo isola e lo sostituisce con un nuovo nodo. La riprogrammazione dei pod e il riavvio dei lavori si basano sui meccanismi standard di Kubernetes e sulla politica di riavvio del processo.
+ L'agente di controllo dello stato di integrità [SageMaker HyperPod](https://catalog.workshops.aws/sagemaker-hyperpod-eks/en-US)approfondito e di 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, ad esempio le GPU. Per impostazione predefinita, rileva i guasti relativi alla rete per l'EFA attraverso i suoi controlli sanitari di base e supporta la ripresa automatica dei lavori di formazione interrotti, consentendo di continuare i lavori dall'ultimo checkpoint e 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 come errori RDMA (Remote Direct Memory Access) e cadute di pacchetti, assicurati che il driver [AWS](https://docs.aws.amazon.com/eks/latest/userguide/node-efa.html) EFA sia installato. Inoltre, consigliamo di implementare [CloudWatch Observability Add-on](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-EKS-addon.html) o utilizzare strumenti come DCGM Exporter con Prometheus e Grafana per monitorare EFA, GPU e, per esempio, metriche specifiche relative alle sue funzionalità. SageMaker HyperPod

### Disabilita Karpenter Consolidation per carichi di lavoro sensibili alle interruzioni
<a name="_disable_karpenter_consolidation_for_interruption_sensitive_workloads"></a>

[Per i 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.](https://karpenter.sh/v1.0/concepts/disruption/#consolidation) La funzionalità di consolidamento di Karpenter ottimizza automaticamente i costi del cluster chiudendo i nodi sottoutilizzati o sostituendoli con alternative più economiche. Tuttavia, anche quando un carico di lavoro utilizza completamente una GPU, Karpenter può consolidare i nodi se identifica un tipo di istanza di dimensioni adeguate a un prezzo inferiore che soddisfi i requisiti del pod, con conseguenti interruzioni 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 dei job a causa della riprogrammazione dei pod e del ricaricamento dei dati, il che potrebbe essere costoso per i lavori di inferenza in batch di lunga durata. Per mitigare questo problema, puoi impostare `WhenEmpty` e configurare una `consolidateAfter` durata, ad esempio 1 ora, `consolidationPolicy` per conservare i nodi durante i picchi di carico di lavoro. Esempio:

```
disruption:
  consolidationPolicy: WhenEmpty
  consolidateAfter: 60m
```

Questo approccio migliora la latenza di avvio dei pod per carichi di lavoro di inferenza in batch complessi e altri lavori sensibili alle interruzioni, come l'elaborazione di dati di inferenza online in tempo reale o l'addestramento dei modelli, in cui il costo dell'interruzione supera i risparmi sui costi di elaborazione. [NodePool Karpenter](https://karpenter.sh/docs/concepts/disruption/#nodepool-disruption-budgets) Disruption Budgets è un'altra funzionalità per la gestione delle interruzioni di Karpenter. Con i budget, puoi assicurarti che non più di un certo numero di nodi vengano interrotti nei nodi prescelti in un determinato momento. NodePool Puoi anche utilizzare i budget per le interruzioni per evitare che tutti i nodi vengano interrotti in un determinato momento (ad esempio nelle ore di punta). Per ulteriori informazioni, consulta la documentazione di [Karpenter](https://karpenter.sh/docs/concepts/disruption/#consolidation) Consolidation.

### Usa ttl SecondsAfterFinished per automatizzare i lavori di Kubernetes Clean-Up
<a name="_use_ttlsecondsafterfinished_to_auto_clean_up_kubernetes_jobs"></a>

Consigliamo di impostare `ttlSecondsAfterFinished` i job Kubernetes in Amazon EKS per eliminare automaticamente gli oggetti di lavoro completati. Gli oggetti di lavoro persistenti consumano risorse del cluster, come la memoria del server API, e complicano il monitoraggio con dashboard ingombranti (ad esempio Grafana, Amazon). CloudWatch Ad esempio, l'impostazione di un TTL di 1 ora garantisce che i lavori vengano rimossi subito dopo il completamento, mantenendo il cluster in ordine. Per ulteriori dettagli, consulta [Pulizia automatica per lavori finiti.](https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/)

### Configurare Low-Priority Job Preemption per Higher-Priority Jobs/workloads
<a name="_configure_low_priority_job_preemption_for_higher_priority_jobsworkloads"></a>

Per i carichi di AI/ML lavoro a priorità mista su Amazon EKS, puoi configurare la priorità dei lavori a bassa priorità per garantire che le attività con priorità più alta (ad esempio, inferenza in tempo reale) ricevano risorse tempestivamente. Senza prelazione, i carichi di lavoro a bassa priorità come i processi batch (ad esempio, inferenza in batch, elaborazione dei 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 priorità 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 sulla [priorità e la priorità di Kubernetes](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/).

## Scalabilità e prestazioni delle applicazioni
<a name="_application_scaling_and_performance"></a>

### Personalizza la capacità di calcolo per i carichi di lavoro ML con Karpenter o Static Nodes
<a name="_tailor_compute_capacity_for_ml_workloads_with_karpenter_or_static_nodes"></a>

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, 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 scalatori di piani dati come Karpenter**: per flussi di lavoro ML dinamici con richieste di calcolo variabili (ad esempio, GPU-based inferenza seguita da grafici), consigliamo di utilizzare scalatori di piani di dati just-in-time come CPU-based 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](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html) possono contribuire a garantire che la capacità riservata sia completamente fornita e utilizzata, massimizzando i risparmi. Questo approccio è ideale per tipi di istanze specifici eseguiti tramite RI o ODCR.

 **Esempio** 

Questo è un esempio di Karpenter diversificato [NodePool](https://karpenter.sh/docs/concepts/nodepools/)che consente il lancio di istanze `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 fattori e tolleranze per impedire che carichi di lavoro non accelerati vengano pianificati su istanze accelerate
<a name="_use_taints_and_tolerations_to_prevent_non_accelerated_workloads_from_being_scheduled_on_accelerated_instances"></a>

La pianificazione di carichi di lavoro non accelerati su risorse GPU non è efficiente dal punto di vista del calcolo, pertanto consigliamo di utilizzare taints and toleration per garantire che i pod di carichi di lavoro non accelerati non siano pianificati su nodi inappropriati. Per [ulteriori informazioni](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/), consulta la documentazione di Kubernetes.

### Scalabilità basata sulle prestazioni del modello
<a name="_scale_based_on_model_performance"></a>

Per i carichi di lavoro di inferenza, consigliamo di utilizzare Kubernetes Event-Driven Autoscaling (KEDA) per scalare in base a metriche prestazionali del modello, come le richieste di inferenza o il throughput dei token, con periodi di cooldown appropriati. Le politiche di scalabilità statica possono sovrafornire o insufficiente le risorse, con un impatto sui costi e sulla latenza. [Scopri di più nella documentazione KEDA.](https://keda.sh/)

## Allocazione dinamica delle risorse per la gestione avanzata delle GPU
<a name="aiml-dra"></a>

 L'[allocazione dinamica delle risorse (DRA)](https://kubernetes.io/docs/concepts/scheduling-eviction/dynamic-resource-allocation/#enabling-dynamic-resource-allocation) rappresenta un progresso fondamentale nella gestione delle risorse GPU Kubernetes. DRA supera le tradizionali limitazioni dei plug-in dei dispositivi per consentire la condivisione sofisticata delle GPU, il riconoscimento della topologia e il coordinamento delle risorse tra i nodi. Disponibile nella [versione 1.33](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions-standard.html#kubernetes-1-33) di Amazon EKS, DRA affronta le sfide critiche dei AI/ML carichi di lavoro fornendo quanto segue:
+ Fine-grained Allocazione tramite GPU
+ Meccanismi di condivisione avanzati, come Multi-Process service (MPS) e Multi-Instance GPU (MIG)
+ Support 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 sottoutilizzo significativo (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
<a name="_advantages_of_using_dra_instead_of_nvidia_device_plugin"></a>

Il plug-in per dispositivi NVIDIA (a partire dalla versione`0.12.0`) supporta meccanismi di condivisione della GPU tra cui time-slicing, MPS e MIG. Tuttavia, esistono limitazioni architettoniche che DRA affronta.

 **Limitazioni dei plug-in per dispositivi NVIDIA** 
+  **Configurazione statica:** le configurazioni di condivisione della GPU (repliche time-slicing e impostazioni MPS) richiedono la preconfigurazione a livello di cluster. `ConfigMaps` Ciò rende difficile fornire strategie di condivisione diverse per carichi di lavoro diversi.
+  **Selezione granulare limitata:** sebbene il plug-in del dispositivo esponga le caratteristiche della GPU tramite le 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 nodi: non è possibile gestire risorse** GPU distribuite su più nodi o esprimere requisiti di topologia 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 dalle risorse.
+  **Complessità di configurazione: l'impostazione di diverse strategie di condivisione richiede un'etichettatura multipla e attenta 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. `resourceclaims` Ciò consente una corrispondenza più flessibile delle risorse.
+  **Conoscenza della topologia:** tramite 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:** `computeDomains` abilita il coordinamento delle risorse GPU distribuite su più nodi, fondamentale per sistemi come GB200 con canali IMEX.
+  **Workload-specific configurazione:** Ciascuno `ResourceClaim` specifica strategie e configurazioni di condivisione diverse, consentendo un controllo granulare per carico di lavoro anziché impostazioni a livello di cluster.
+  **Integrazione migliorata 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 della GPU, mentre DRA aggiunge funzionalità avanzate di allocazione e pianificazione.

### Istanze supportate da DRA e relative funzionalità
<a name="_instances_supported_by_dra_and_their_features"></a>

Il supporto DRA varia in base alla famiglia di istanze Amazon EC2 e all'architettura GPU, come illustrato 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 | Formazione, inferenza e grafica | 
| P4d/P4de | NVIDIA A100 | Sì  | Sì | Sì | No | Large-scale formazione e HPC | 
| P5 | NVIDIA H100 | Sì  | Sì | Sì | No | Formazione sul modello Foundation | 
| P6 | NVIDIA B200 | Sì  | Sì | Sì | No | Modelli con miliardi o trilioni di parametri, addestramento distribuito e inferenza | 
| P6e | NVIDIA GB200 | Sì  | Sì | Sì | Sì | Modelli con miliardi o trilioni di parametri, addestramento distribuito 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
<a name="_additional_resources"></a>

Per ulteriori informazioni sui driver Kubernetes DRA e NVIDIA DRA, consulta le seguenti risorse su: GitHub
+ [Allocazione](https://github.com/kubernetes/dynamic-resource-allocation) dinamica delle risorse Kubernetes 
+  [Proposta di miglioramento di Kubernetes per DRA](https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/3063-dynamic-resource-allocation) 
+  [Driver NVIDIA DRA per GPU](https://github.com/NVIDIA/k8s-dra-driver-gpu) 
+  [Esempi e guida rapida di NVIDIA DRA](https://github.com/NVIDIA/k8s-dra-driver-gpu/tree/main/demo/specs/quickstart) 

### Configura l'allocazione dinamica delle risorse per la gestione avanzata delle GPU
<a name="aiml-dra-setup"></a>

L'argomento seguente mostra come configurare l'allocazione dinamica delle risorse (DRA) per la gestione avanzata delle GPU.

#### Prerequisiti
<a name="aiml-dra-prereqs"></a>

Prima di implementare DRA su Amazon EKS, assicurati che il tuo ambiente soddisfi i seguenti requisiti.

##### Configurazione del cluster
<a name="aiml-dra-configuration"></a>
+ Cluster Amazon EKS in esecuzione `1.33` o versione successiva
+ [Gruppi di nodi gestiti Amazon EKS (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 istanze appropriati

##### Componenti richiesti
<a name="aiml-dra-components"></a>
+ Versione del plug-in per dispositivi NVIDIA `0.17.1` o successiva
+ Versione del driver NVIDIA DRA o successiva `25.3.0`

#### Fase 1: Creare un cluster con un gruppo di DRA-enabled nodi usando eksctl
<a name="aiml-dra-create-cluster"></a>

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

1. Crea il cluster:

   ```
   eksctl create cluster -f dra-eks-cluster.yaml
   ```

#### Fase 2: Implementazione del plug-in per dispositivi NVIDIA
<a name="aiml-dra-nvidia-plugin"></a>

Implementa il plug-in per dispositivi NVIDIA per abilitare l'individuazione di base della GPU:

1. Aggiungi il repository Helm del plug-in per dispositivi NVIDIA:

   ```
   helm repo add nvidia https://nvidia.github.io/k8s-device-plugin
   helm repo update
   ```

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

1. 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
<a name="aiml-dra-helm-chart"></a>

1. Crea un file di `dra-driver-values.yaml` valori 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
   ```

1. Aggiungi il repository NVIDIA NGC Helm:

   ```
   helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
   helm repo update
   ```

1. 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
<a name="aiml-dra-verify"></a>

1. Verificate che le risorse dell'API DRA siano disponibili:

   ```
   kubectl api-resources | grep resource.k8s.io/v1beta1
   ```

   Di 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
   ```

1. Controlla le classi di dispositivi disponibili:

   ```
   kubectl get deviceclasses
   ```

   Di seguito è riportato un esempio di output previsto:

   ```
   NAME                                        AGE
   compute-domain-daemon.nvidia.com            4h39m
   compute-domain-default-channel.nvidia.com   4h39m
   gpu.nvidia.com                              4h39m
   mig.nvidia.com                              4h39m
   ```

   Quando 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`
   + La `gpu.nvidia.com` slice registra il dispositivo GPU A10G fisico con le sue specifiche (memoria, capacità di elaborazione e altro).
   + Poiché A10G non supporta il partizionamento MIG, la `compute-domain.nvidia.com` slice crea un singolo dominio di calcolo che rappresenta l'intero contesto di calcolo della GPU.
   + Questi `resourceslices` vengono quindi pubblicati sul server API Kubernetes, rendendo le risorse della GPU disponibili per la pianificazione. `resourceclaims`

     Lo scheduler DRA può ora allocare in modo intelligente questa GPU ai Pod che richiedono risorse GPU, fornendo una gestione delle risorse più flessibile rispetto agli approcci tradizionali basati sui plug-in dei dispositivi`resourceclaimtemplates`. Ciò avviene automaticamente senza intervento manuale. Il nodo diventa disponibile semplicemente per i carichi di lavoro della GPU una volta che il driver DRA ha completato il processo di individuazione e registrazione delle risorse.

     Quando si esegue il comando seguente:

     ```
     kubectl get resourceslices
     ```

     Di seguito è riportato un esempio di 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 carico di lavoro GPU semplice utilizzando l'allocazione dinamica delle risorse](#aiml-dra-workload).

### Pianifica un carico di lavoro GPU semplice utilizzando l'allocazione dinamica delle risorse
<a name="aiml-dra-workload"></a>

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](#aiml-dra-setup)

1. Crea una base `ResourceClaimTemplate` per l'allocazione della GPU con un file denominato: `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
   ```

1. Applica il modello:

   ```
   kubectl apply -f basic-gpu-claim-template.yaml
   ```

1. Verifica lo stato:

   ```
   kubectl get resourceclaimtemplates -n gpu-test1
   ```

   Di seguito è riportato un output di esempio:

   ```
   NAME         AGE
   single-gpu   9m16s
   ```

1. Crea un Pod che usi il `ResourceClaimTemplate` con un file chiamato`basic-gpu-pod.yaml`:

   ```
   ---
   apiVersion: v1
   kind: Pod
   metadata:
     namespace: gpu-test1
     name: gpu-pod
     labels:
       app: pod
   spec:
     containers:
     - name: ctr0
       image: ubuntu:22.04
       command: ["bash", "-c"]
       args: ["nvidia-smi -L; trap 'exit 0' TERM; sleep 9999 & wait"]
       resources:
         claims:
         - name: gpu0
     resourceClaims:
     - name: gpu0
       resourceClaimTemplateName: single-gpu
     nodeSelector:
       NodeGroupType: gpu-dra
       nvidia.com/gpu.present: "true"
     tolerations:
     - key: "nvidia.com/gpu"
       operator: "Exists"
       effect: "NoSchedule"
   ```

1. Applica e monitora il Pod:

   ```
   kubectl apply -f basic-gpu-pod.yaml
   ```

1. Controlla lo stato del Pod:

   ```
   kubectl get pod -n gpu-test1
   ```

   Di seguito è riportato un esempio di output previsto:

   ```
   NAME      READY   STATUS    RESTARTS   AGE
   gpu-pod   1/1     Running   0          13m
   ```

1. Controlla lo `ResourceClaim` stato:

   ```
   kubectl get resourceclaims -n gpu-test1
   ```

   Di seguito è riportato un esempio di output previsto:

   ```
   NAME                 STATE                AGE
   gpu-pod-gpu0-l76cg   allocated,reserved   9m6s
   ```

1. Visualizza i log dei Pod per visualizzare le informazioni sulla GPU:

   ```
   kubectl logs gpu-pod -n gpu-test1
   ```

   Di seguito è riportato un esempio di output previsto:

   ```
   GPU 0: NVIDIA L4 (UUID: GPU-da7c24d7-c7e3-ed3b-418c-bcecc32af7c5)
   ```

Continua a leggere [Tecniche di ottimizzazione della GPU con allocazione dinamica delle risorse](#aiml-dra-optimization) per tecniche di ottimizzazione della GPU più avanzate utilizzando DRA.

### Tecniche di ottimizzazione della GPU con allocazione dinamica delle risorse
<a name="aiml-dra-optimization"></a>

I carichi di lavoro GPU moderni richiedono una gestione sofisticata delle risorse per ottenere un utilizzo ottimale e un'efficienza dei costi. DRA consente diverse tecniche di ottimizzazione avanzate che rispondono a diversi casi d'uso e funzionalità hardware:
+  **Time-slicing**consente a più carichi di lavoro di condividere le risorse di calcolo della GPU nel tempo, rendendola 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 time-slicing](#aiml-dra-timeslicing).
+  **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](#aiml-dra-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 GPU Multi-Instance](#aiml-dra-mig).
+  **Internode Memory Exchange (IMEX) consente una comunicazione coerente in termini di 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 le istanze GB200 P6e](#aiml-dra-imex).

Queste tecniche possono migliorare significativamente l'utilizzo delle risorse. Le organizzazioni segnalano che l'utilizzo della GPU aumenta 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 time-slicing
<a name="aiml-dra-timeslicing"></a>

Time-slicing consente a più carichi di lavoro di condividere le risorse di elaborazione 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.

1. Definite un file `ResourceClaimTemplate` per il time-slicing 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
   ```

1. Definite 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
   ```

1. Applica il modello e il Pod:

   ```
   kubectl apply -f timeslicing-claim-template.yaml
   kubectl apply -f timeslicing-pod.yaml
   ```

1. Monitora le richieste di risorse:

   ```
   kubectl get resourceclaims -n timeslicing-gpu -w
   ```

   Di 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à dal `pending` `allocated,reserved` al `running` 

#### Ottimizza i carichi di lavoro della GPU con MPS
<a name="aiml-dra-mps"></a>

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.

1. Definite un file `ResourceClaimTemplate` per MPS con il nome`mps-claim-template.yaml`:

   ```
   ---
   apiVersion: v1
   kind: Namespace
   metadata:
     name: mps-gpu
   
   ---
   apiVersion: resource.k8s.io/v1beta1
   kind: ResourceClaimTemplate
   metadata:
     name: mps-gpu-template
     namespace: mps-gpu
   spec:
     spec:
       devices:
         requests:
         - name: shared-gpu
           deviceClassName: gpu.nvidia.com
         config:
         - requests: ["shared-gpu"]
           opaque:
             driver: gpu.nvidia.com
             parameters:
               apiVersion: resource.nvidia.com/v1beta1
               kind: GpuConfig
               sharing:
                 strategy: MPS
   ```

1. Definite un Pod utilizzando MPS con un file denominato: `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
   ```

1. Applica il modello e crea più MPS Pod:

   ```
   kubectl apply -f mps-claim-template.yaml
   kubectl apply -f mps-pod.yaml
   ```

1. Monitora le richieste di risorse:

   ```
   kubectl get resourceclaims -n mps-gpu -w
   ```

   Di 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 l'allocazione dinamica delle risorse (DRA). A differenza del time-slicing, in cui i carichi di lavoro utilizzano a turno la GPU in sequenza, MPS consente l'esecuzione simultanea di entrambi i container sulla stessa GPU fisica. L'intuizione principale è che la condivisione di DRA MPS richiede più contenitori all'interno di un singolo Pod, non più Pod separati. Una volta distribuito, il driver DRA ne `ResourceClaim` assegna uno al Pod e configura automaticamente MPS per consentire l'esecuzione simultanea dei contenitori di inferenza e di addestramento.

Ogni contenitore dispone del proprio spazio di memoria GPU e delle proprie risorse di calcolo isolate, con il daemon 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: `inference-container`
<a name="_container1_inference_container"></a>

```
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: `training-container`
<a name="_container2_training_container"></a>

```
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 GPU Multi-Instance
<a name="aiml-dra-mig"></a>

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-operator) L'operatore GPU NVIDIA utilizza [MIG Manager per creare profili MIG](https://github.com/NVIDIA/gpu-operator/blob/47fea81ac752a68745300b5ec77f3bd8ee69d059/deployments/gpu-operator/values.yaml#L374) e riavviare le istanze GPU come P4D, P4De, P5, P6 e altre per applicare le modifiche alla configurazione. L'operatore GPU include funzionalità complete di gestione MIG tramite il componente MIG Manager, che controlla le modifiche alle etichette dei nodi e applica automaticamente la configurazione MIG appropriata. Quando viene richiesta una modifica del profilo MIG, l'operatore spegne automaticamente tutti i client GPU, applica la nuova geometria della partizione e riavvia i servizi interessati. Questo processo richiede il riavvio del nodo per le istanze GPU per garantire transizioni di stato della GPU pulite. Ecco perché l'abilitazione `WITH0REBOOT=true` nella configurazione MIG Manager è essenziale per implementazioni MIG di successo.

Sono necessari sia [NVIDIA DRA Driver](https://github.com/NVIDIA/k8s-dra-driver-gpu) che NVIDIA GPU Operator per lavorare con MIG in Amazon EKS. Inoltre, non sono necessari NVIDIA Device Plugin e DCGM Exporter, poiché fanno parte di NVIDIA GPU Operator. Poiché le AMI NVIDIA EKS vengono fornite con i driver NVIDIA preinstallati, abbiamo disabilitato l'implementazione dei driver da parte dell'operatore GPU per evitare conflitti e sfruttare i driver ottimizzati già presenti sulle istanze. Il driver NVIDIA DRA gestisce l'allocazione dinamica delle risorse per le istanze MIG, mentre l'operatore GPU gestisce l'intero ciclo di vita della GPU. Ciò include la configurazione MIG, la funzionalità dei plug-in dei dispositivi, il monitoraggio tramite DCGM e l'individuazione delle funzionalità dei nodi. Questo approccio integrato offre una soluzione completa per la gestione delle GPU aziendali, con isolamento a livello hardware e funzionalità di allocazione dinamica delle risorse.

##### Fase 1: Implementare NVIDIA GPU Operator
<a name="_step_1_deploy_nvidia_gpu_operator"></a>

1. Aggiungi il repository NVIDIA GPU Operator:

   ```
   helm repo add nvidia https://nvidia.github.io/gpu-operator
   helm repo update
   ```

1. Crea un file: `gpu-operator-values.yaml`

   ```
   driver:
     enabled: false
   
   mig:
     strategy: mixed
   
   migManager:
     enabled: true
     env:
       - name: WITH_REBOOT
         value: "true"
     config:
       create: true
       name: custom-mig-parted-configs
       default: "all-disabled"
       data:
         config.yaml: |-
           version: v1
           mig-configs:
             all-disabled:
               - devices: all
                 mig-enabled: false
   
             # P4D profiles (A100 40GB)
             p4d-half-balanced:
               - devices: [0, 1, 2, 3]
                 mig-enabled: true
                 mig-devices:
                   "1g.5gb": 2
                   "2g.10gb": 1
                   "3g.20gb": 1
               - devices: [4, 5, 6, 7]
                 mig-enabled: false
   
             # P4DE profiles (A100 80GB)
             p4de-half-balanced:
               - devices: [0, 1, 2, 3]
                 mig-enabled: true
                 mig-devices:
                   "1g.10gb": 2
                   "2g.20gb": 1
                   "3g.40gb": 1
               - devices: [4, 5, 6, 7]
                 mig-enabled: false
   
   devicePlugin:
     enabled: true
     config:
       name: ""
       create: false
       default: ""
   
   toolkit:
     enabled: true
   
   nfd:
     enabled: true
   
   gfd:
     enabled: true
   
   dcgmExporter:
     enabled: true
     serviceMonitor:
       enabled: true
       interval: 15s
       honorLabels: false
       additionalLabels:
         release: kube-prometheus-stack
   
   nodeStatusExporter:
     enabled: false
   
   operator:
     defaultRuntime: containerd
     runtimeClass: nvidia
     resources:
       limits:
         cpu: 500m
         memory: 350Mi
       requests:
         cpu: 200m
         memory: 100Mi
   
   daemonsets:
     tolerations:
       - key: "nvidia.com/gpu"
         operator: "Exists"
         effect: "NoSchedule"
     nodeSelector:
       accelerator: nvidia
     priorityClassName: system-node-critical
   ```

1. Installa GPU Operator utilizzando il `gpu-operator-values.yaml` file:

   ```
   helm install gpu-operator nvidia/gpu-operator \
     --namespace gpu-operator \
     --create-namespace \
     --version v25.3.1 \
     --values gpu-operator-values.yaml
   ```

   Questo grafico Helm utilizza i seguenti componenti e più 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 GPU) Multi-instance 
   + Container Toolkit (runtime del contenitore GPU)
   + Operator Controller (gestione del ciclo di vita)

1. Verifica i pod di distribuzione:

   ```
   kubectl get pods -n gpu-operator
   ```

   Di 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
   ```

1. Crea un cluster Amazon EKS con un gruppo di nodi gestiti 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 ID
   ```

   NVIDIA GPU Operator utilizza l'etichetta aggiunta ai nodi `nvidia.com/mig.config: "p4de-half-balanced"` e partiziona la GPU con il profilo specificato.

1. Accedi all'istanza. `p4de`

1. Esegui il comando seguente:

   ```
   nvidia-smi -L
   ```

   Dovresti 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 come configurato. Ecco come funziona il partizionamento:

L'operatore GPU ha applicato questa configurazione dal 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
```

In base al 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
    + MIG 3g.40gb Device 0 — Carichi di lavoro di grandi dimensioni (40 GB di memoria, 42 SM)
    + MIG 2g.20gb Device 1 — Carichi di lavoro medi (20 GB di memoria, 28 SM)
    + MIG 1g.10gb Device 2 — Piccoli carichi di lavoro (10 GB di memoria, 14 SM)
    + MIG 1g.10gb Device 3 — Piccoli carichi di lavoro (10 GB di memoria, 14 SM)
  + GPU 1: NVIDIA A100-SXM4-80GB
    + MIG 3g.40gb Device 0 — Layout di partizione identico
    + MIG 2g.20gb Dispositivo 1
    + MIG 1g.10gb Dispositivo 2
    + MIG 1g.10gb Dispositivo 3
  + GPU 2 e GPU 3: stesso schema 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 pianificabili attraverso 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 a`ResourceClaimTemplate`, il driver DRA seleziona in modo intelligente l'istanza MIG appropriata da qualsiasi GPU disponibile, abilitando una vera multi-tenancy a livello hardware. Questa allocazione dinamica consente l'esecuzione simultanea di più carichi di lavoro isolati sulla stessa GPU fisica, mantenendo rigidi limiti di risorse e garanzie prestazionali.

##### Fase 2: Verificare l'allocazione delle risorse MIG
<a name="_step_2_test_mig_resource_allocation"></a>

Eseguiamo ora alcuni esempi per dimostrare come DRA alloca dinamicamente le istanze MIG a diversi carichi di lavoro. Implementate `resourceclaimtemplates` e testate i pod per vedere come il driver DRA colloca i carichi di lavoro tra le partizioni MIG disponibili, consentendo a più container di condividere le risorse GPU con isolamento a livello di hardware.

1. Crea `resourceclaimtemplates` per contenere il MIG: `mig-claim-template.yaml`

   ```
   apiVersion: v1
   kind: Namespace
   metadata:
     name: mig-gpu
   
   ---
   # Template for 3g.40gb MIG instance (Large training)
   apiVersion: resource.k8s.io/v1beta1
   kind: ResourceClaimTemplate
   metadata:
     name: mig-large-template
     namespace: mig-gpu
   spec:
     spec:
       devices:
         requests:
         - name: mig-large
           deviceClassName: mig.nvidia.com
           selectors:
           - cel:
               expression: |
                 device.attributes['gpu.nvidia.com'].profile == '3g.40gb'
   
   ---
   # Template for 2g.20gb MIG instance (Medium training)
   apiVersion: resource.k8s.io/v1beta1
   kind: ResourceClaimTemplate
   metadata:
     name: mig-medium-template
     namespace: mig-gpu
   spec:
     spec:
       devices:
         requests:
         - name: mig-medium
           deviceClassName: mig.nvidia.com
           selectors:
           - cel:
               expression: |
                 device.attributes['gpu.nvidia.com'].profile == '2g.20gb'
   
   ---
   # Template for 1g.10gb MIG instance (Small inference)
   apiVersion: resource.k8s.io/v1beta1
   kind: ResourceClaimTemplate
   metadata:
     name: mig-small-template
     namespace: mig-gpu
   spec:
     spec:
       devices:
         requests:
         - name: mig-small
           deviceClassName: mig.nvidia.com
           selectors:
           - cel:
               expression: |
                 device.attributes['gpu.nvidia.com'].profile == '1g.10gb'
   ```

1. Applica i tre modelli:

   ```
   kubectl apply -f mig-claim-template.yaml
   ```

1. Esegui il comando seguente:

   ```
   kubectl get resourceclaimtemplates -n mig-gpu
   ```

   Di seguito è riportato un output di esempio:

   ```
   NAME                  AGE
   mig-large-template    71m
   mig-medium-template   71m
   mig-small-template    71m
   ```

1. Crea `mig-pod.yaml` per pianificare più lavori per sfruttare questo `resourceclaimtemplates` vantaggio:

   ```
   ---
   # 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
   ```

1. Applica questa specifica, che dovrebbe implementare tre Pod:

   ```
   kubctl apply -f mig-pod.yaml
   ```

   Questi Pod devono essere programmati dal driver DRA.

1. Controllate i registri del Pod del driver DRA 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**],}]
   ```

1. Verifica il `resourceclaims` per vedere lo stato del Pod:

   ```
   kubectl get resourceclaims -n mig-gpu -w
   ```

   Di 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   0s
   ```

   Come puoi vedere, tutti i Pod sono stati spostati dalla posizione in sospeso al `allocated,reserved` driver DRA.

1. Esegui `nvidia-smi` dal nodo. Noterai che sono in esecuzione tre processori Python:

   ```
   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 le istanze GB200 P6e
<a name="aiml-dra-imex"></a>

IMEX (Internode Memory Exchange) consente una comunicazione coerente in termini di memoria tra i nodi per la formazione distribuita su NVIDIA GB200. UltraServers

Effettuare le seguenti operazioni.

1. Definite un programma `ComputeDomain` per l'addestramento multinodo con un file denominato`imex-compute-domain.yaml`:

   ```
   apiVersion: resource.nvidia.com/v1beta1
   kind: ComputeDomain
   metadata:
     name: distributed-training-domain
     namespace: default
   spec:
     numNodes: 2
     channel:
       resourceClaimTemplate:
         name: imex-channel-template
   ```

1. Definisci un Pod utilizzando i canali IMEX con un file denominato: `imex-pod.yaml`

   ```
   apiVersion: v1
   kind: Pod
   metadata:
     name: imex-distributed-training
     namespace: default
     labels:
       app: imex-training
   spec:
     affinity:
       nodeAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
           nodeSelectorTerms:
           - matchExpressions:
             - key: nvidia.com/gpu.clique
               operator: Exists
     containers:
     - name: distributed-training
       image: nvcr.io/nvidia/pytorch:25.04-py3
       command: ["bash", "-c"]
       args:
       - |
         echo "=== IMEX Channel Verification ==="
         ls -la /dev/nvidia-caps-imex-channels/
         echo ""
   
         echo "=== GPU Information ==="
         nvidia-smi
         echo ""
   
         echo "=== NCCL Test (if available) ==="
         python -c "
         import torch
         import torch.distributed as dist
         import os
   
         print(f'CUDA available: {torch.cuda.is_available()}')
         print(f'CUDA device count: {torch.cuda.device_count()}')
   
         if torch.cuda.is_available():
             for i in range(torch.cuda.device_count()):
                 print(f'GPU {i}: {torch.cuda.get_device_name(i)}')
   
         # Check for IMEX environment variables
         imex_vars = [k for k in os.environ.keys() if 'IMEX' in k or 'NVLINK' in k]
         if imex_vars:
             print('IMEX Environment Variables:')
             for var in imex_vars:
                 print(f'  {var}={os.environ[var]}')
   
         print('IMEX channel verification completed')
         "
   
         # Keep container running for inspection
         sleep 3600
       resources:
         claims:
         - name: imex-channel-0
         - name: imex-channel-1
     resourceClaims:
     - name: imex-channel-0
       resourceClaimTemplateName: imex-channel-template
     - name: imex-channel-1
       resourceClaimTemplateName: imex-channel-template
     tolerations:
     - key: nvidia.com/gpu
       operator: Exists
       effect: NoSchedule
   ```
**Nota**  
Ciò richiede istanze P6e GB200.

1. Implementa IMEX applicando i modelli and: `ComputeDomain`

   ```
   kubectl apply -f imex-claim-template.yaml
   kubectl apply -f imex-compute-domain.yaml
   kubectl apply -f imex-pod.yaml
   ```

1. Controlla lo stato. `ComputeDomain`

   ```
   kubectl get computedomain distributed-training-domain
   ```

1. Monitora la distribuzione del demone IMEX.

   ```
   kubectl get pods -n nvidia-dra-driver -l resource.nvidia.com/computeDomain
   ```

1. Controlla i canali IMEX nel Pod:

   ```
   kubectl exec imex-distributed-training -- ls -la /dev/nvidia-caps-imex-channels/
   ```

1. Visualizza i log del Pod:

   ```
   kubectl logs imex-distributed-training
   ```

   Di seguito è riportato un esempio di 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](https://github.com/NVIDIA/k8s-dra-driver-gpu/discussions/249) su GitHub.