

 **Contribuisci a migliorare questa pagina** 

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

Per contribuire a questa guida per l'utente, scegli il GitHub link **Modifica questa pagina** nel riquadro destro di ogni pagina.

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

# Configura il cluster Amazon EKS per i AI/ML carichi di lavoro utilizzando le CLI
<a name="ml-cluster-setup-cli"></a>

**Suggerimento**  
 [Registrati](https://events.eksworkshop.com/workshops/genai/) ai prossimi AI/ML workshop Amazon EKS.

Questa sezione illustra i passaggi per creare l'infrastruttura necessaria per eseguire carichi di lavoro di formazione o inferenza su Amazon EKS tramite comandi CLI. I passaggi includono la creazione di un cluster EKS, GPU-enabled nodi con EKS Auto Mode o Karpenter, uno stack di monitoraggio con Prometheus e Grafana e lo storage Amazon S3 per i pesi dei modelli.

Consulta la documentazione per [EKS Auto Mode](https://docs.aws.amazon.com/eks/latest/userguide/automode.html) e [Karpenter](https://karpenter.sh/docs/) per ulteriori informazioni su come queste funzionalità forniscono e scalano automaticamente le istanze EC2 nei cluster EKS.

 **High-level architettura e flusso di lavoro** 

![High-level architettura che mostra il cluster EKS con Karpenter NodeClass e NodePool, lo stack di monitoraggio Grafana e Prometheus, la scrittura su Amazon Managed Service for Prometheus, un bucket Amazon S3 per i pesi dei modelli e le fasi numerate del flusso di lavoro](http://docs.aws.amazon.com/it_it/eks/latest/userguide/images/ml-cluster-setup-architecture.png)


Il AWS diagramma mostra l'architettura di alto livello per la configurazione di questa sezione. I passaggi numerati sulla destra indicano l'ordine in cui si completa la configurazione nei passaggi seguenti.

## Prerequisiti
<a name="cluster-setup-cli-prerequisites"></a>
+  `kubectl`>= 1,35. Per le istruzioni di configurazione, vedere. [`Configura kubectl ed eksctl`](install-kubectl.md)
+  AWS CLI = 2,27. [Per le istruzioni di configurazione, consulta Installazione.](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html)
+ Elmo >= 3.14. [Per le istruzioni di configurazione, vedere Setup Helm.](helm.md)
+  `jq`. Per le istruzioni di configurazione, consulta [Download jq](https://jqlang.github.io/jq/download/).
+  `eksctl`>= 0.27,0. Per le istruzioni di configurazione, vedere [Installazione](https://eksctl.io/installation) nella documentazione. `eksctl`

Verifica la tua `eksctl` versione:

```
eksctl version
```

Se utilizzi una versione precedente alla 0.227.0, segui la [guida all'installazione di eksctl per](https://eksctl.io/installation/) eseguire l'aggiornamento alla versione più recente.

## Impostazione delle variabili di ambiente
<a name="cluster-setup-cli-set-environment-variables"></a>

Mantieni coerenti il nome e la AWS regione del cluster seguenti durante questi passaggi. La modifica potrebbe far sì che i comandi successivi indirizzino al cluster EKS sbagliato.

```
export CLUSTER_NAME=ai-eks-docs
export AWS_REGION=us-east-2
```

L'utilizzo di tutti gli AZ disponibili migliora la tolleranza agli errori e aumenta le possibilità di ottenere la capacità della GPU:

```
export AZS=$(aws ec2 describe-availability-zones \
  --region ${AWS_REGION} \
  --query "AvailabilityZones[?ZoneId!='use1-az3' && ZoneId!='usw1-az2' && ZoneId!='cac1-az3'].ZoneName" \
  --output text | tr '\t' ',')
echo $AZS
```

**Importante**  
Le zone di disponibilità `use1-az3``usw1-az2`, e `cac1-az3` sono escluse perché [Amazon EKS non supporta il posizionamento del piano di controllo in tali zone](https://repost.aws/knowledge-center/eks-cluster-creation-errors). La creazione di un cluster con sottoreti in una di queste zone produce un. `UnsupportedAvailabilityZoneException`

Output previsto:

```
us-east-2a,us-east-2b,us-east-2c
```

Le AZ nell'output varieranno in base alla regione. Questo esempio mostra le AZ disponibili per `us-east-2` regione.

## Crea cluster e GPU NodePool
<a name="cluster-setup-cli-create-cluster-and-gpu-nodepool"></a>

Questa sezione fornisce due percorsi per la creazione del cluster e GPU-enabled dei nodi EKS, illustrati nel diagramma seguente. Scegli una sola opzione in tutta la guida.
+  **EKS Auto Mode**: oltre ai principali [componenti aggiuntivi di rete, archiviazione e bilanciamento del carico,](https://docs.aws.amazon.com/eks/latest/userguide/eks-add-ons.html#addon-consider-auto) EKS Auto Mode include e gestisce le seguenti funzionalità per i carichi di lavoro di addestramento e inferenza: agente di monitoraggio dei nodi EKS, riparazione automatica dei nodi, snapshotter [SOCI per il prelievo](https://github.com/awslabs/soci-snapshotter) rapido dei container e disponibilità della GPU per l'impostazione predefinita. NodeClass Il plug-in per dispositivi NVIDIA è incluso nell'AMI accelerata Bottlerocket utilizzata da EKS Auto Mode per i nodi. GPU-enabled 
+  **Self-managed Karpenter**: su un cluster EKS senza EKS Auto Mode, l'utente è responsabile dell'installazione e della configurazione dei componenti necessari per i carichi di lavoro di addestramento e inferenza. Ciò include componenti aggiuntivi di rete (VPC CNI, CoredNS, kube-proxy), Karpenter, l'agente di monitoraggio dei nodi EKS, il plug-in del dispositivo NVIDIA e lo snapshotter SOCI per il prelievo rapido dei container.

 **Opzioni del cluster EKS: EKS Auto Mode e Karpenter autogestito** 

![Side-by-side confronto tra le due opzioni di cluster: un cluster EKS Auto Mode con un cluster EKS standard con Karpenter NodePool, CoredNS, VPC CNI, plug-in per dispositivi NVIDIA, EKS Pod Identity agent, Node Monitoring Agent, kube-proxy e un e NodeClass NodePool](http://docs.aws.amazon.com/it_it/eks/latest/userguide/images/ml-cluster-setup-cli-cluster-options.png)


In ciascuno dei passaggi seguenti, scegliete un percorso (EKS Auto Mode, Karpenter) e seguitelo per tutto il tempo. Dopo aver completato i passaggi per il percorso scelto, avrai un cluster EKS con una GPU NodePool pronto per pianificare i carichi di lavoro della GPU.

## Fase 1: Creazione del cluster
<a name="cluster-setup-cli-create-cluster"></a>

Inizia creando il tuo cluster EKS e installando i componenti del cluster necessari per i carichi di lavoro GPU.

Con EKS Auto Mode, un solo `eksctl create cluster --enable-auto-mode` comando effettua il provisioning di un cluster EKS pronto per i carichi di lavoro GPU.

Con Karpenter autogestito, il `eksctl create cluster` comando fornisce i componenti aggiuntivi di rete di base, quindi sono necessari passaggi aggiuntivi per abilitare la riparazione automatica dei nodi tramite un feature gate Karpenter, installare l'agente di monitoraggio dei nodi EKS e installare il plug-in del dispositivo NVIDIA.

------
#### [ EKS Auto Mode ]

 **Crea un cluster EKS Auto Mode** 

```
eksctl create cluster \
  --name=$CLUSTER_NAME \
  --region=$AWS_REGION \
  --enable-auto-mode \
  --version=1.35 \
  --zones=$AZS
```

Il completamento di questo comando richiede alcuni minuti. Al termine, aggiorna `eksctl` automaticamente il file kubeconfig in modo che funzioni con il cluster appena fornito. Verifica che il cluster sia operativo:

```
kubectl get pods --all-namespaces
```

Output previsto:

```
NAMESPACE     NAME                              READY   STATUS    RESTARTS   AGE
kube-system   metrics-server-55cf976ddd-cz2mw   1/1     Running   0          3m
kube-system   metrics-server-55cf976ddd-wrjvv   1/1     Running   0          3m
```

In modalità automatica EKS, VPC CNI, kube-proxy e CoredNS vengono eseguiti come componenti gestiti e non vengono visualizzati come pod in. `kube-system`

------
#### [ Self-managed Karpenter ]

 **Autentica Helm su ECR pubblico** 

 `eksctl`estrae il grafico Karpenter Helm da Amazon Public ECR. Effettua l'autenticazione prima di creare il cluster per evitare un errore 403 nella fase di installazione di Helm:

```
aws ecr-public get-login-password --region us-east-1 \
  | helm registry login --username AWS --password-stdin public.ecr.aws
```

Public ECR è un servizio globale ospitato in. `us-east-1` Usalo `--region us-east-1` qui indipendentemente dalla regione in cui si trova il cluster EKS.

Output previsto: `Login Succeeded` 

 **Crea il cluster EKS con Karpenter** 

Memorizza la tua versione di Karpenter in una variabile di ambiente per un uso successivo. [Per le ultime versioni di Karpenter, consulta le versioni di Karpenter su.](https://github.com/aws/karpenter-provider-aws/releases) GitHub

```
export KARPENTER_VERSION=1.12.0
```

### `Cluster config YAML ed eksctl creano cluster`
<a name="cluster-setup-cli-step1-karpenter-cluster-yaml"></a>

```
cat << EOF > /tmp/cluster-karpenter.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: ${CLUSTER_NAME}
  region: ${AWS_REGION}
  version: "1.35"
  tags:
    karpenter.sh/discovery: ${CLUSTER_NAME}

availabilityZones: [$(echo $AZS | sed 's/,/, /g')]

autoModeConfig:
  enabled: false

iam:
  withOIDC: true

karpenter:
  version: "${KARPENTER_VERSION}"
  withSpotInterruptionQueue: true

managedNodeGroups:
  - name: system
    instanceType: m6i.2xlarge
    desiredCapacity: 2
    minSize: 2
    maxSize: 3
    labels:
      node-role: system
    tags:
      karpenter.sh/discovery: ${CLUSTER_NAME}

addons:
  - name: eks-pod-identity-agent
  - name: eks-node-monitoring-agent
EOF

eksctl create cluster -f /tmp/cluster-karpenter.yaml
```

Questo comando richiede circa 15 minuti. Crea un cluster EKS con un gruppo di nodi gestiti dedicato all'hosting di componenti aggiuntivi e al controller Karpenter. Karpenter viene installato con la coda di interruzione Spot abilitata in modo da poter gestire le raccomandazioni relative all'interruzione e al ribilanciamento di Spot. L'`autoModeConfig.enabled: false`impostazione rende esplicito che questo cluster non utilizza la modalità EKS Auto, quindi i componenti Karpenter installati in questo percorso sono responsabili della gestione dei nodi.

Il cluster installa anche l'[EKS Pod Identity Agent e l'agente](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html) di [monitoraggio dei nodi EKS come componenti](https://docs.aws.amazon.com/eks/latest/userguide/node-health.html) aggiuntivi EKS. EKS Pod Identity viene utilizzato più avanti nella guida. L'agente di monitoraggio dei nodi EKS viene eseguito su ogni nodo e legge i log del kernel per impostare le condizioni del nodo, ad esempio, e `AcceleratedHardwareReady` `KernelReady``NetworkingReady`, che la riparazione automatica dei nodi di Karpenter utilizza per decidere quando sostituire un nodo non integro.

Verifica che il cluster sia operativo:

```
kubectl get pods --all-namespaces
```

L'output previsto include Karpenter, CoredNS, kube-proxy, aws-node (VPC CNI), EKS Pod Identity Agent e l'agente di monitoraggio dei nodi EKS.

```
NAMESPACE     NAME                              READY   STATUS    RESTARTS   AGE
karpenter     karpenter-567547464c-s6vkx        1/1     Running   0          3m40s
karpenter     karpenter-567547464c-x7gmw        1/1     Running   0          3m40s
kube-system   aws-node-b6gf2                    2/2     Running   0          12m
kube-system   aws-node-lcphh                    2/2     Running   0          12m
kube-system   coredns-7d4dcbf4fb-ccvrr          1/1     Running   0          16m
kube-system   coredns-7d4dcbf4fb-qbhk2          1/1     Running   0          16m
kube-system   eks-node-monitoring-agent-h79vm   1/1     Running   0          9m45s
kube-system   eks-node-monitoring-agent-tf4dw   1/1     Running   0          9m45s
kube-system   eks-pod-identity-agent-5jbtc      1/1     Running   0          12m
kube-system   eks-pod-identity-agent-rwcrc      1/1     Running   0          12m
kube-system   kube-proxy-p4bmq                  1/1     Running   0          12m
kube-system   kube-proxy-v5nwr                  1/1     Running   0          12m
kube-system   metrics-server-5b966ff79c-hr58p   1/1     Running   0          9m22s
kube-system   metrics-server-5b966ff79c-szs2d   1/1     Running   0          9m22s
```

 **Abilita la riparazione automatica dei nodi** 

La modalità automatica EKS abilita la riparazione automatica dei nodi per impostazione predefinita. Su Karpenter autogestito, la riparazione automatica dei nodi è nascosta dietro la porta delle funzionalità e deve essere `NodeRepair=true` abilitata in modo esplicito. Il comando seguente corregge la distribuzione di Karpenter per aggiungere il feature gate. `NodeRepair=true` L'aggiornamento dell'ambiente di distribuzione attiva il rollout dei pod Karpenter:

```
kubectl set env deployment/karpenter -n karpenter \
  FEATURE_GATES=NodeRepair=true
```

Output previsto:

```
deployment.apps/karpenter env updated
```

Attendi che i pod Karpenter vengano lanciati:

```
kubectl rollout status deployment/karpenter -n karpenter
```

 **Installa il plug-in per dispositivi NVIDIA** 

L' EKS-optimized AMI AL2023 non include il [plug-in del dispositivo NVIDIA](https://github.com/NVIDIA/k8s-device-plugin) (a differenza dell'AMI Bottlerocket utilizzata da EKS Auto Mode). Installalo tramite Helm per rendere utilizzabili le risorse della GPU con i Pods sul cluster.

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

```
cat << 'EOF' > /tmp/nvdp-values.yaml
mofedEnabled: false
nodeSelector:
  amiFamily: al2023
gfd:
  enabled: true
nfd:
  worker:
    tolerations:
      - operator: "Exists"
EOF
```

```
helm install nvidia-device-plugin nvdp/nvidia-device-plugin \
  --namespace kube-system \
  -f /tmp/nvdp-values.yaml
```
+  `mofedEnabled: false`: disabilita il controllo per Mellanox OFED (), che non utilizza InfiniBand AWS 
+  `nodeSelector.amiFamily: al2023`: indirizza solo DaemonSet i nodi AL2023 (Bottlerocket ha già il plugin integrato)
+  `gfd.enabled: true`: abilita le etichette GPU Feature Discovery (`nvidia.com/gpu.product`, ecc.) `nvidia.com/gpu.memory`

Verifica che il plug-in del dispositivo NVIDIA sia installato. L'aspettativa è che non ci siano Pod di plug-in per dispositivi fino a quando non verrà fornita una GPU NodePool con l'etichetta corrispondente.

```
kubectl get daemonset nvidia-device-plugin -n kube-system
```

Output previsto:

```
NAME                   DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR      AGE
nvidia-device-plugin   0         0         0       0            0           amiFamily=al2023   2m5s
```

------

**avvertimento**  
Sia per la modalità automatica EKS che per i percorsi Karpenter autogestiti, la riparazione automatica dei nodi si comporta allo stesso modo per i nodi forniti da. NodePools La riparazione automatica dei nodi in EKS Auto Mode e Karpenter è un metodo di interruzione *forzato che aggira* l'annotazione e. PodDisruptionBudgets `karpenter.sh/do-not-disrupt` `terminationGracePeriod` [La riparazione automatica dei nodi attende 10 minuti prima di sostituire un nodo con la `AcceleratedHardwareReady` condizione impostata su e 30 minuti per le altre condizioni di `False` riparazione.](https://docs.aws.amazon.com/eks/latest/userguide/node-repair.html)

## Fase 2: Creare una GPU dinamica NodePool
<a name="cluster-setup-cli-create-gpu-nodepool"></a>

Definisci una NodePool soluzione che effettui il provisioning dinamico di istanze G-family GPU con una generazione superiore a 4, utilizzando la capacità Spot come alternativa. On-Demand I percorsi EKS Auto Mode e Karpenter utilizzano entrambi la stessa NodePool API con l'unica differenza che indica. NodeClass In EKS Auto Mode, il pacchetto seleziona `default` NodeClass già l'AMI giusta e configura il pull parallelo SOCI, quindi NodePool è l'unico oggetto che crei. In Karpenter autogestito, è inoltre necessario un dispositivo personalizzato `EC2NodeClass` che colleghi l'AMI e ottimizzi il SOCI.

------
#### [ EKS Auto Mode ]

Nella modalità EKS Auto, il pacchetto seleziona `default` NodeClass automaticamente l'AMI Bottlerocket per le istanze GPU, che include i driver NVIDIA preinstallati, il plug-in per dispositivi NVIDIA e il pull parallelo SOCI. Devi solo applicare un riferimento a: NodePool `default` NodeClass

```
cat << 'EOF' | kubectl apply -f -
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: gpu-inf
spec:
  template:
    metadata:
      labels:
        guide: ai-eks-docs
    spec:
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: default
      taints:
        - key: nvidia.com/gpu
          effect: NoSchedule
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: eks.amazonaws.com/instance-category
          operator: In
          values: ["g"]
        - key: eks.amazonaws.com/instance-generation
          operator: Gt
          values: ["4"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
  limits:
    cpu: 1000
    memory: 5000Gi
EOF
```

[Ciò NodePool fornisce istanze G-family GPU con generazione superiore a 4 ([G5, G6e](https://aws.amazon.com/ec2/instance-types/g5/)[, G7e, ecc.](https://aws.amazon.com/ec2/instance-types/g6e/)).](https://aws.amazon.com/ec2/instance-types/g7e/) La `nvidia.com/gpu:NoSchedule` contaminazione garantisce che solo i Pod siano programmati su questi nodi. GPU-eligible 

------
#### [ Self-managed Karpenter ]

Self-managed Karpenter non include un valore predefinito. NodeClass Per prima cosa `EC2NodeClass` crei un pin dell'alias AMI EKS-optimized NVIDIA AL2023, abiliti SOCI tramite il `FastImagePull` feature gate e configuri per `instanceStorePolicy: RAID0` spostare la cache delle immagini containerd su NVMe locale. Quindi NodePool crei quello che gli fa riferimento.

 **Crea il EC2NodeClass** 

### EC2NodeClass YAML
<a name="cluster-setup-cli-step2-karpenter-ec2nodeclass-yaml"></a>

```
cat << EOF | kubectl apply -f -
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
  name: gpu-inf
  labels:
    guide: ai-eks-docs
spec:
  role: "eksctl-KarpenterNodeRole-${CLUSTER_NAME}"
  amiSelectorTerms:
    - alias: al2023@latest
  subnetSelectorTerms:
    - tags:
        karpenter.sh/discovery: ${CLUSTER_NAME}
  securityGroupSelectorTerms:
    - tags:
        karpenter.sh/discovery: ${CLUSTER_NAME}
  tags:
    karpenter.sh/discovery: ${CLUSTER_NAME}
  instanceStorePolicy: RAID0
  userData: |
    MIME-Version: 1.0
    Content-Type: multipart/mixed; boundary="BOUNDARY"

    --BOUNDARY
    Content-Type: application/node.eks.aws

    ---
    apiVersion: node.eks.aws/v1alpha1
    kind: NodeConfig
    spec:
      featureGates:
        FastImagePull: true
      containerd:
        config: |
          [plugins."io.containerd.snapshotter.v1.soci"]
            [plugins."io.containerd.snapshotter.v1.soci".blob]
              max_concurrent_downloads_per_image = 20
              concurrent_download_chunk_size = "16mb"
              max_concurrent_unpacks_per_image = 12
              discard_unpacked_layers = true

    --BOUNDARY--
EOF
```

 `instanceStorePolicy: RAID0`assembla i dischi NVMe locali in un array. RAID-0 L'alias `al2023@latest` AMI si risolve nell'AMI AL2023 EKS-optimized . Quando Karpenter avvia un tipo di istanza GPU, seleziona automaticamente la variante accelerata AL2023\_x86\_64\_NVIDIA, che include il driver NVIDIA preinstallato.

Il `FastImagePull` feature gate abilita la modalità pull parallela dello snapshotter SOCI, che scarica e decomprime i livelli di immagine contemporaneamente. Ciò corrisponde al comportamento della modalità automatica EKS sulle famiglie di istanze G, P e Trn. Il `containerd.config` blocco ottimizza lo snapshotter SOCI per le immagini: ECR-hosted 
+  `max_concurrent_downloads_per_image: 20`consente il download di fino a 20 livelli in parallelo per immagine. L'impostazione predefinita è 3 su Bottlerocket e 20 su AL2023. Valore consigliato per ECR.
+  `concurrent_download_chunk_size: "16mb"`divide ogni livello in blocchi da 16 MB scaricati in parallelo tramite richieste di intervallo HTTP. Consigliato per i registri che supportano l'intervallo GET (ECR sì).
+  `max_concurrent_unpacks_per_image: 12`decomprime fino a 12 strati contemporaneamente. L'impostazione predefinita è 1 su Bottlerocket e 12 su AL2023.
+  `discard_unpacked_layers: true`elimina i blob dei livelli compressi dopo la decompressione per risparmiare spazio su disco.

[Per ulteriori opzioni di ottimizzazione SOCI (download simultanei per immagine, dimensione dei blocchi, ecc.), consultate il modello SOCI di Karpenter.](https://github.com/aws-samples/karpenter-blueprints/tree/main/blueprints/soci-snapshotter)

 EC2NodeClassConvalida:

```
kubectl get ec2nodeclass gpu-inf
```

Output previsto:`READY True`. Se`False`, esegui `kubectl describe ec2nodeclass gpu-inf` e verifica le condizioni per la presenza di tag di sottorete o gruppi di sicurezza mancanti.

 **Crea la GPU NodePool** 

### NodePool YAML
<a name="cluster-setup-cli-step2-karpenter-nodepool-yaml"></a>

```
cat << EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: gpu-inf
spec:
  template:
    metadata:
      labels:
        guide: ai-eks-docs
        amiFamily: al2023
    spec:
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: gpu-inf
      taints:
        - key: nvidia.com/gpu
          effect: NoSchedule
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["g"]
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: ["4"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
  limits:
    cpu: 1000
    memory: 5000Gi
EOF
```

L'`amiFamily: al2023`etichetta sul modello del nodo è quella DaemonSet utilizzata dal plug-in del dispositivo NVIDIA per selezionare questi nodi.

------

Convalida il file NodePool creato:

```
kubectl get nodepool gpu-inf
```

Output previsto:

```
NAME      NODECLASS   NODES   READY   AGE
gpu-inf   default     0       True    8s
```

Nel percorso Karpenter autogestito, la colonna NODECLASS mostra invece di. `gpu-inf` `default`

## Fase 3: Esegui il test con un Pod campione
<a name="cluster-setup-cli-test-with-a-sample-pod"></a>

Testa la NodePool configurazione della GPU con un `nvidia-smi` Pod.

```
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: nvidia-smi
  labels:
    guide: ai-eks-docs
spec:
  tolerations:
    - key: "nvidia.com/gpu"
      operator: "Exists"
      effect: "NoSchedule"
  containers:
    - name: nvidia-smi
      image: public.ecr.aws/amazonlinux/amazonlinux:2023-minimal
      command: ["nvidia-smi"]
      resources:
        limits:
          nvidia.com/gpu: 1
  restartPolicy: OnFailure
EOF
```

Verifica che il Pod sia pianificato e completato correttamente.

```
kubectl get pods
```

Output previsto:

```
NAME         READY   STATUS      RESTARTS   AGE
nvidia-smi   0/1     Completed   0          67s
```

Lo STATUS: Completato indica che il comando nvidia-smi è stato eseguito ed è uscito. Controlla i log del Pod per vedere la GPU rilevata dal nodo.

```
kubectl logs nvidia-smi
```

Output previsto:

```
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.126.09             Driver Version: 580.126.09     CUDA Version: 13.0     |
+-----------------------------------------+------------------------+----------------------+
| 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 RTX PRO 6000 Blac...    On  |   00000000:2B:00.0 Off |                    0 |
| N/A   30C    P0             81W /  600W |       0MiB /  97887MiB |      0%      Default |
|                                         |                        |             Disabled |
+-----------------------------------------+------------------------+----------------------+
```

L'output mostra il modello di GPU, la versione del driver, la versione CUDA e la memoria disponibile. In questo esempio, Karpenter ha fornito un'istanza G7e con una GPU NVIDIA RTX PRO 6000 Blackwell con 96 GB di memoria. 30°C è la temperatura attuale della GPU e P0 indica che la GPU è al massimo delle prestazioni (inattiva ma pronta). Il valore 81 W/600 W mostra l'attuale consumo energetico rispetto alla capacità massima, mentre 0 MiB/97887 MiB mostra la memoria GPU attualmente utilizzata rispetto alla quantità totale disponibile. Poiché il Pod ha appena eseguito nvidia-smi ed è uscito, nessun carico di lavoro utilizza la GPU, quindi la memoria è a 0 e l'alimentazione è inattiva. La versione del driver GPU NVIDIA (580.126.09) proviene dall'AMI Bottlerocket, mentre la versione CUDA (13.0) proviene dall'immagine del contenitore. Il modello di GPU e la memoria variano a seconda del tipo di istanza selezionato da Karpenter. Le istanze G5 hanno GPU NVIDIA A10G (24 GB), le istanze G6e hanno GPU NVIDIA L40S (48 GB) e le istanze G7e hanno GPU NVIDIA RTX PRO 6000 (96 GB).

Per capire in che modo Karpenter e lo scheduler Kubernetes si sono coordinati per fornire un nodo e posizionare il Pod, controlla gli eventi del ciclo di vita del Pod:

```
kubectl describe po nvidia-smi
```

Output previsto:

```
Events:
  Type     Reason                  Age   From                   Message
  ----     ------                  ----  ----                   -------
  Warning  FailedScheduling        60s   default-scheduler      0/2 nodes are available: 2 node(s) had untolerated taint(s). no new claims to deallocate, preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling.
  Normal   Nominated               59s   eks-auto-mode/compute  Pod should schedule on: nodeclaim/gpu-inf-vxcnj
  Normal   Scheduled               24s   default-scheduler      Successfully assigned default/nvidia-smi to i-0fb17a09bc4203164
  Warning  FailedCreatePodSandBox  21s   kubelet                Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "7f85e25b220c8fb245187758dbbbc8efb3d40f3e49e13054404880daf4c3b2f0": plugin type="aws-cni" name="aws-cni" failed (add): add cmd: failed to setup network policy
  Normal   Pulling                  7s   kubelet                spec.containers{nvidia-smi}: Pulling image "public.ecr.aws/amazonlinux/amazonlinux:2023-minimal"
  Normal   Pulled                   5s   kubelet                spec.containers{nvidia-smi}: Successfully pulled image "public.ecr.aws/amazonlinux/amazonlinux:2023-minimal" in 1.237s (1.237s including waiting). Image size: 37442701 bytes.
  Normal   Created                  5s   kubelet                spec.containers{nvidia-smi}: Container created
  Normal   Started                  5s   kubelet                spec.containers{nvidia-smi}: Container started
```

Questi eventi mostrano la sequenza di pianificazione del Pod: il Pod inizialmente non riesce a pianificare perché non esistono nodi GPU (FailedScheduling), Karpenter ne nomina uno nuovo NodeClaim (Nominato), lo scheduler assegna il Pod una volta che il nodo è pronto (Pianificato), quindi l'immagine del contenitore viene estratta e avviata. EKS Auto Mode viene fornito con il pull parallelo SOCI (Seekable OCI) installato e configurato immediatamente su istanze G, P e Trn. Nota: grazie all'estrazione parallela SOCI, l'immagine del contenitore è stata estratta dall'ECR in meno di 2 secondi (1,237 secondi).

A NodeClaim è una richiesta che Karpenter crea per fornire un nodo specifico. Mostra il tipo di istanza, il tipo di capacità, AZ e se il nodo è pronto.

```
kubectl get nodeclaims
```

 NodeClaim Output previsto:

```
NAME            TYPE          CAPACITY    ZONE         NODE                  READY   AGE
gpu-inf-xxxxx   g7e.2xlarge   spot        us-east-2a   i-0xxxxxxxxxxxx       True    2m
```

Il tipo di istanza e la AZ varieranno. Qualsiasi G-family istanza con generazione > 4 è idonea.

L'`FailedCreatePodSandBox`avviso in entrata `kubectl describe pod nvidia-smi` è transitorio e previsto. Il VPC CNI si inizializza in modo asincrono dopo l'unione del nodo e il kubelet riprova automaticamente. Se il Pod rimane acceso, controlla gli eventi del nodo con. `ContainerCreating` `kubectl describe node <node-name>`

**Suggerimento**  
Se non viene visualizzato alcun nodo, verifica la presenza di errori di capacità insufficiente:  

```
kubectl get events | grep InsufficientCapacityError
```
Karpenter memorizza nella cache le offerte non disponibili per 3 minuti. L'ampliamento dei tipi di istanze e delle AZ consentiti NodePool aumenta le possibilità di atterraggio.

**Nota**  
Le istanze Spot lanciate da Karpenter non verranno visualizzate nella console Spot Requests di EC2. Karpenter utilizza l'API EC2 con. [https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateFleet.html](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateFleet.html)`type: instant` Le istanze vengono visualizzate nella console EC2 Instances con un ciclo di vita. `spot`

## Fase 4: Aggiungere capacità riservata a (opzionale) NodePool
<a name="cluster-setup-cli-attach-odcr"></a>

Per utilizzare prima la capacità riservata con il Spot/On-Demand fallback, crea un ODCR e collegalo al tuo NodeClass, quindi aggiorna la dinamica NodePool dello Step 2 per consentire `reserved` anche la capacità. La chiamata all'API di prenotazione è la stessa per entrambi i percorsi; l' NodeClass allegato è diverso perché EKS Auto Mode e Karpenter autogestito utilizzano tipi diversi. NodeClass 

**avvertimento**  
Il comando seguente comporta un addebito per il tipo di istanza riservato fino a quando non lo si annulla con. `aws ec2 cancel-capacity-reservation --capacity-reservation-id <id>`

Crea la prenotazione della capacità:

```
CR_AZ="us-east-2a"
INSTANCE_TYPE="g6e.4xlarge"

aws ec2 create-capacity-reservation \
  --instance-type $INSTANCE_TYPE \
  --instance-platform Linux/UNIX \
  --availability-zone "$CR_AZ" \
  --instance-count 1 \
  --instance-match-criteria open \
  --end-date-type unlimited
```

Se ricevi un `InsufficientInstanceCapacity` errore, passa `CR_AZ` a un'altra AZ e riprova.

Cerca l'ID di prenotazione della capacità e memorizzalo in una variabile di shell per i seguenti passaggi:

```
CAPACITY_RESERVATION_ID=$(aws ec2 describe-capacity-reservations \
  --filters "Name=state,Values=active" "Name=instance-type,Values=${INSTANCE_TYPE}" \
  --query 'CapacityReservations[0].CapacityReservationId' \
  --output text \
  --region ${AWS_REGION})
echo "Capacity reservation ID: ${CAPACITY_RESERVATION_ID}"
```

Quindi applica le NodePool modifiche NodeClass e al tuo percorso:

------
#### [ EKS Auto Mode ]

Nella modalità automatica EKS, il pacchetto `default` NodeClass è di sola lettura, quindi crea un codice personalizzato NodeClass che faccia riferimento alla prenotazione, quindi aggiorna il NodePool punto di arrivo NodeClass e aggiungi `reserved` capacità all'elenco. `capacity-type`

### YAML personalizzato NodeClass
<a name="cluster-setup-cli-step4-automode-nodeclass-yaml"></a>

```
NODE_ROLE=$(kubectl get nodeclass default -o jsonpath='{.spec.role}')

cat << EOF | kubectl apply -f -
apiVersion: eks.amazonaws.com/v1
kind: NodeClass
metadata:
  name: gpu-inf
  labels:
    guide: ai-eks-docs
spec:
  role: "$NODE_ROLE"
  subnetSelectorTerms:
    - tags:
        alpha.eksctl.io/cluster-name: "$CLUSTER_NAME"
        kubernetes.io/role/internal-elb: "1"
  securityGroupSelectorTerms:
    - tags:
        aws:eks:cluster-name: "$CLUSTER_NAME"
  capacityReservationSelectorTerms:
    - id: "$CAPACITY_RESERVATION_ID"
EOF
```

Il `kubernetes.io/role/internal-elb: "1"` tag garantisce l'avvio dei nodi solo nelle sottoreti private.

Aggiorna il NodePool per utilizzare ODCR-backed NodeClass e includi `reserved` come tipo di capacità:

### NodePool YAML aggiornato
<a name="cluster-setup-cli-step4-automode-nodepool-yaml"></a>

```
cat << EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: gpu-inf
spec:
  template:
    metadata:
      labels:
        guide: ai-eks-docs
    spec:
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: gpu-inf
      taints:
        - key: nvidia.com/gpu
          effect: NoSchedule
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand", "reserved"]
        - key: eks.amazonaws.com/instance-category
          operator: In
          values: ["g"]
        - key: eks.amazonaws.com/instance-generation
          operator: Gt
          values: ["4"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
  limits:
    cpu: 1000
    memory: 5000Gi
EOF
```

------
#### [ Self-managed Karpenter ]

Per Karpenter autogestito, riapplica quello che `EC2NodeClass` hai creato nel passaggio 2 con aggiunto. `capacityReservationSelectorTerms` Il nome e la forma del campo corrispondono alla modalità automatica EKS `NodeClass` mostrata nell'altra scheda.

### EC2NodeClass YAML aggiornato
<a name="cluster-setup-cli-step4-karpenter-nodeclass-yaml"></a>

```
cat << EOF | kubectl apply -f -
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
  name: gpu-inf
  labels:
    guide: ai-eks-docs
spec:
  role: "eksctl-KarpenterNodeRole-${CLUSTER_NAME}"
  amiSelectorTerms:
    - alias: al2023@latest
  subnetSelectorTerms:
    - tags:
        karpenter.sh/discovery: ${CLUSTER_NAME}
  securityGroupSelectorTerms:
    - tags:
        karpenter.sh/discovery: ${CLUSTER_NAME}
  tags:
    karpenter.sh/discovery: ${CLUSTER_NAME}
  instanceStorePolicy: RAID0
  capacityReservationSelectorTerms:
    - id: "$CAPACITY_RESERVATION_ID"
  userData: |
    MIME-Version: 1.0
    Content-Type: multipart/mixed; boundary="BOUNDARY"

    --BOUNDARY
    Content-Type: application/node.eks.aws

    ---
    apiVersion: node.eks.aws/v1alpha1
    kind: NodeConfig
    spec:
      featureGates:
        FastImagePull: true
      containerd:
        config: |
          [plugins."io.containerd.snapshotter.v1.soci"]
            [plugins."io.containerd.snapshotter.v1.soci".blob]
              max_concurrent_downloads_per_image = 20
              concurrent_download_chunk_size = "16mb"
              max_concurrent_unpacks_per_image = 12
              discard_unpacked_layers = true

    --BOUNDARY--
EOF
```

L'unica modifica rispetto alla Fase 2 è il nuovo `capacityReservationSelectorTerms` campo. Tutti gli altri campi rimangono invariati.

Aggiorna il NodePool file per includere `reserved` come tipo di capacità:

### NodePool YAML aggiornato
<a name="cluster-setup-cli-step4-karpenter-nodepool-yaml"></a>

```
cat << EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: gpu-inf
spec:
  template:
    metadata:
      labels:
        guide: ai-eks-docs
        amiFamily: al2023
    spec:
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: gpu-inf
      taints:
        - key: nvidia.com/gpu
          effect: NoSchedule
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand", "reserved"]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["g"]
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: ["4"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
  limits:
    cpu: 1000
    memory: 5000Gi
EOF
```

------

Karpenter la considera l'opzione `reserved` più economica e la lancia per prima. Una volta completata la prenotazione, torna a Spot o. On-Demand

### Verifica la priorità riservata e il fallback di Spot
<a name="cluster-setup-cli-step4-validate"></a>

Dopo aver applicato le modifiche, verifica che Karpenter dia priorità alla capacità riservata e ritorni a Spot o. On-Demand Implementa una distribuzione a 2 repliche che richiede 1 GPU per Pod. L'ODCR è per 1 istanza, quindi il primo Pod attiva Karpenter per avviare un nodo riservato. Il secondo Pod non può entrare nel nodo riservato e attiva Karpenter per avviare un altro nodo da Spot o dalla capacità. On-Demand 

```
cat << 'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gpu-overflow-test
  labels:
    guide: ai-eks-docs
spec:
  replicas: 2
  selector:
    matchLabels:
      app: gpu-overflow-test
  template:
    metadata:
      labels:
        app: gpu-overflow-test
        guide: ai-eks-docs
    spec:
      tolerations:
        - key: nvidia.com/gpu
          operator: Exists
          effect: NoSchedule
      containers:
        - name: nvidia-smi
          image: public.ecr.aws/amazonlinux/amazonlinux:2023-minimal
          command: ["sh", "-c", "nvidia-smi && sleep infinity"]
          resources:
            limits:
              nvidia.com/gpu: 1
EOF
```

A differenza del `nvidia-smi` test Pod dello Step 3, che veniva eseguito e chiuso, questa implementazione mantiene i Pod in funzione (`sleep infinity`) in modo da contenere la GPU e non rilasciare il nodo.

Verifica i Pod pianificati su nodi diversi:

```
kubectl get pods -l app=gpu-overflow-test -o wide
```

Output previsto:

```
NAME                                 READY   STATUS    RESTARTS   AGE     IP                NODE                  NOMINATED NODE   READINESS GATES
gpu-overflow-test-59b97944fb-lq56c   1/1     Running   0          2m42s   192.168.186.240   i-057692590480155da   <none>           <none>
gpu-overflow-test-59b97944fb-z4zcx   1/1     Running   0          2m42s   192.168.130.64    i-0521ecd1849fa0578   <none>           <none>
```

I due pod sono in esecuzione, ciascuno su un nodo diverso.

Controlla NodeClaims per vedere i tipi di capacità:

```
kubectl get nodeclaims
```

Output previsto:

```
NAME            TYPE          CAPACITY    ZONE         NODE                  READY   AGE
gpu-inf-shg5w   g6e.xlarge    reserved    us-east-2a   i-0ea91fdeef65b8cb6   True    2m2s
gpu-inf-ssnqf   g7e.2xlarge   spot        us-east-2b   i-00ccf7ce65cf3f6ca   True    112s
```

Il nodo riservato è stato avviato per primo, seguito da uno Spot o da un On-Demand nodo una volta completata la prenotazione.

Pulisci la distribuzione del test:

```
kubectl delete deployment gpu-overflow-test
```

## Monitoraggio
<a name="cluster-setup-cli-monitoring"></a>

Installa uno stack di monitoraggio che raccolga i parametri di cluster, nodi e GPU in Amazon Managed Service for Prometheus (AMP) e visualizzali con Grafana. Il grafico kube-prometheus-stack Helm utilizza Prometheus per lo scraping e la scrittura remota delle metriche su AMP, oltre a Grafana autogestita per i dashboard. NVIDIA DCGM Exporter aggiunge parametri (utilizzo, memoria, temperatura, potenza, NVLink, attività del tensore). GPU-specific 

Prometheus, Grafana e l'operatore accedono per impostazione predefinita a nodi non GPU perché i nodi GPU sono portatori della contaminazione. `nvidia.com/gpu:NoSchedule` Node-exporter e DCGM Exporter funzionano entrambi su nodi GPU, quindi possiamo analizzare le metriche dell'host e della GPU a livello di flotta.

Se hai aperto un nuovo terminale, imposta il nome e la regione del cluster:

```
export CLUSTER_NAME=ai-eks-docs
export AWS_REGION=us-east-2
```

### Crea lo spazio di lavoro AMP
<a name="_create_the_amp_workspace"></a>

Crea uno spazio di lavoro AMP per archiviare le metriche:

```
aws amp create-workspace \
  --alias "amp-ws-${CLUSTER_NAME}" \
  --region ${AWS_REGION}
```

Ottieni l'ID dell'area di lavoro:

```
AMP_WORKSPACE_ID=$(aws amp list-workspaces \
  --alias "amp-ws-${CLUSTER_NAME}" \
  --query 'workspaces[0].workspaceId' \
  --output text \
  --region ${AWS_REGION})

echo "AMP Workspace ID: ${AMP_WORKSPACE_ID}"
```

Ottieni l'endpoint di scrittura remota:

```
AMP_ENDPOINT=$(aws amp describe-workspace \
  --workspace-id ${AMP_WORKSPACE_ID} \
  --query 'workspace.prometheusEndpoint' \
  --output text \
  --region ${AWS_REGION})

echo "AMP Endpoint: ${AMP_ENDPOINT}"
```

### Crea policy IAM e associazioni EKS Pod Identity
<a name="_create_iam_policy_and_eks_pod_identity_associations"></a>

Crea una policy IAM che consenta a Prometheus di scrivere metriche in remoto e a Grafana di interrogarle:

```
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

AMP_POLICY_ARN=$(aws iam create-policy \
  --policy-name "${CLUSTER_NAME}-amp-grafana-policy" \
  --policy-document "{\"Version\": \"2012-10-17\", \"Statement\": [{\"Sid\": \"AllowAMPReadWrite\", \"Effect\": \"Allow\", \"Action\": [\"aps:ListWorkspaces\", \"aps:DescribeWorkspace\", \"aps:GetMetricMetadata\", \"aps:GetSeries\", \"aps:QueryMetrics\", \"aps:RemoteWrite\", \"aps:GetLabels\"], \"Resource\": \"arn:aws:aps:${AWS_REGION}:${ACCOUNT_ID}:workspace/*\"}, {\"Sid\": \"AllowCloudWatchMetrics\", \"Effect\": \"Allow\", \"Action\": [\"cloudwatch:DescribeAlarmsForMetric\", \"cloudwatch:ListMetrics\", \"cloudwatch:GetMetricData\", \"cloudwatch:GetMetricStatistics\"], \"Resource\": \"*\"}]}" \
  --query 'Policy.Arn' \
  --output text)

echo "AMP Policy ARN: ${AMP_POLICY_ARN}"
```

Crea il namespace di monitoraggio e gli account di servizio per Prometheus e Grafana:

```
kubectl create namespace monitoring
kubectl create serviceaccount amp-iamproxy-ingest-service-account -n monitoring
kubectl create serviceaccount grafana-sa -n monitoring
```

Crea le associazioni EKS Pod Identity per collegare gli account di servizio alla policy IAM:

```
eksctl create podidentityassociation \
  --cluster ${CLUSTER_NAME} \
  --namespace monitoring \
  --service-account-name amp-iamproxy-ingest-service-account \
  --role-name "${CLUSTER_NAME}-amp-ingest-role" \
  --permission-policy-arns ${AMP_POLICY_ARN} \
  --region ${AWS_REGION}

eksctl create podidentityassociation \
  --cluster ${CLUSTER_NAME} \
  --namespace monitoring \
  --service-account-name grafana-sa \
  --role-name "${CLUSTER_NAME}-grafana-role" \
  --permission-policy-arns ${AMP_POLICY_ARN} \
  --region ${AWS_REGION}
```

Verifica che entrambe le associazioni EKS Pod Identity siano state create:

```
eksctl get podidentityassociation --cluster ${CLUSTER_NAME} --region ${AWS_REGION}
```

L'output previsto dovrebbe includere entrambi `amp-iamproxy-ingest-service-account` e `grafana-sa` nel `monitoring` namespace.

### Installa kube-prometheus-stack
<a name="_install_kube_prometheus_stack"></a>

Aggiungi il repository Helm:

```
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
```

Questo file di valori omette un NodeSelector per Prometheus, Grafana e l'operatore: la contaminazione dei nodi GPU li tiene lontani dai nodi `nvidia.com/gpu:NoSchedule` GPU, quindi per impostazione predefinita finiscono sul sistema o sul pool generico. Node-exporter utilizza una tolleranza wildcard in modo da funzionare su ogni nodo, compresi i nodi GPU, per raccogliere metriche a livello di flotta.

Crea il file dei valori:

#### file di valori kube-prometheus-stack
<a name="cluster-setup-cli-monitoring-kube-prometheus-values"></a>

```
cat << EOF > /tmp/kube-prometheus-values.yaml
prometheus:
  serviceAccount:
    create: false
    name: amp-iamproxy-ingest-service-account
  prometheusSpec:
    serviceAccountName: amp-iamproxy-ingest-service-account
    remoteWrite:
      - url: "${AMP_ENDPOINT}api/v1/remote_write"
        sigv4:
          region: "${AWS_REGION}"
        queueConfig:
          maxSamplesPerSend: 1000
          maxShards: 200
          capacity: 2500
    retention: 5h
    scrapeInterval: 30s
    evaluationInterval: 30s
    podMonitorSelectorNilUsesHelmValues: false
    serviceMonitorSelectorNilUsesHelmValues: false

alertmanager:
  enabled: false

grafana:
  enabled: true
  serviceAccount:
    create: false
    name: grafana-sa
  grafana.ini:
    auth.sigv4:
      enabled: true
  sidecar:
    datasources:
      defaultDatasourceEnabled: false
  plugins:
    - grafana-amazonprometheus-datasource
  additionalDataSources:
    - name: Amazon-Managed-Prometheus
      type: grafana-amazonprometheus-datasource
      access: proxy
      url: "${AMP_ENDPOINT}"
      isDefault: true
      jsonData:
        sigV4Auth: true
        defaultRegion: "${AWS_REGION}"
        sigV4Region: "${AWS_REGION}"
      editable: true
  dashboardProviders:
    dashboardproviders.yaml:
      apiVersion: 1
      providers:
        - name: default
          orgId: 1
          folder: 'GPU Monitoring'
          type: file
          disableDeletion: false
          editable: true
          options:
            path: /var/lib/grafana/dashboards/default
  dashboards:
    default:
      nvidia-dcgm:
        gnetId: 25261
        revision: 1
        datasource:
          - name: DS_PROMETHEUS
            value: Amazon-Managed-Prometheus
      vllm:
        gnetId: 25263
        revision: 1
        datasource:
          - name: DS_PROMETHEUS
            value: Amazon-Managed-Prometheus

prometheus-node-exporter:
  tolerations:
    - operator: Exists
EOF
```

Verifica che le variabili siano state compilate correttamente:

```
grep -E "url:|region:|tolerations:" /tmp/kube-prometheus-values.yaml
```

Dovresti vedere l'URL completo dell'endpoint AMP (che inizia con`https://aps-workspaces…​`), la tua regione e la riga node-exporter. `tolerations:` Se qualcosa è vuoto, riesporta le variabili e ricrea il file.

Installa il grafico:

```
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  -f /tmp/kube-prometheus-values.yaml
```

Verifica che i pod funzionino:

```
kubectl get pods -n monitoring
```

Output previsto:

```
NAME                                                       READY   STATUS    RESTARTS   AGE
kube-prometheus-stack-grafana-7c58f54f77-rftrj             3/3     Running   0          4m
kube-prometheus-stack-kube-state-metrics-d68dcbc84-5smxq   1/1     Running   0          4m
kube-prometheus-stack-operator-5895df479f-ttm47            1/1     Running   0          4m
kube-prometheus-stack-prometheus-node-exporter-t9q7s       1/1     Running   0          4m
kube-prometheus-stack-prometheus-node-exporter-x6vfb       1/1     Running   0          4m
prometheus-kube-prometheus-stack-prometheus-0              2/2     Running   0          4m
```

Lo stack distribuisce i seguenti componenti:
+  **Prometheus** StatefulSet (): analizza le metriche e le scrive in remoto su AMP
+  **Grafana**: dashboard e visualizzazione, preconfigurate con l'origine dati AMP
+  **kube-state-metrics: genera metriche** sullo stato degli oggetti Kubernetes (Pod status, resource, states) requests/limits NodeClaim 
+  **node-exporter** (DaemonSet, uno per nodo): raccoglie metriche a livello di host (CPU, memoria, disco, rete)
+  **operatore**: gestisce le risorse personalizzate di Prometheus e Alertmanager

Alertmanager è disabilitato in questa configurazione.

### Accedi a Grafana
<a name="_access_grafana"></a>

Apri un terminale e un port-forward separati per accedere a Grafana:

```
kubectl port-forward svc/kube-prometheus-stack-grafana 3000:80 -n monitoring
```

Apri [http://localhost:3000](http://localhost:3000) nel tuo browser. Effettua il login con nome utente `admin` e password usando il seguente comando:

```
kubectl --namespace monitoring get secrets kube-prometheus-stack-grafana -o jsonpath="{.data.admin-password}" | base64 -d ; echo
```

Per verificare che la pipeline di metriche funzioni dall'inizio alla fine:

1. Passa a **Connessioni > Sorgenti dati** e conferma `Amazon-Managed-Prometheus` che sia elencata come origine dati predefinita.

    **Convalida l'origine dati AMP a Grafana**   
![Visualizzazione della pagina Grafana Connections Amazon-Managed-Prometheus come origine dati predefinita](http://docs.aws.amazon.com/it_it/eks/latest/userguide/images/ml-cluster-setup-cli-prometheus-ds-validate.png)

1. Vai a **Drilldown > Metriche e cerca la metrica**. `up` Dovresti vedere i risultati degli scrape target del tuo cluster.

    **Convalida la `up` metrica in Grafana**   
![Pagina Grafana Drilldown Metrics che mostra la metrica ascendente con barre di stato verdi che indicano i target di scrape attivi](http://docs.aws.amazon.com/it_it/eks/latest/userguide/images/ml-cluster-setup-cli-prometheus-metrics-validate.png)

Se `up` mostra risultati, la pipeline (cluster → Prometheus → AMP → Grafana) funziona.

### Implementa DCGM Exporter per le metriche della GPU
<a name="_deploy_the_dcgm_exporter_for_gpu_metrics"></a>

Il kube-prometheus-stack raccoglie i parametri della CPU e della memoria a livello di nodo ma non i parametri della GPU. NVIDIA DCGM Exporter aggiunge l'utilizzo della GPU, l'utilizzo della memoria, la temperatura, l'assorbimento di potenza, la larghezza di banda NVLink e l'attività dei tensori.

```
helm repo add gpu-helm-charts https://nvidia.github.io/dcgm-exporter/helm-charts
helm repo update
```

Imposta la chiave di selezione del nodo GPU per il tuo percorso. EKS Auto Mode e Karpenter autogestito utilizzano chiavi di etichetta diverse per il produttore della GPU.

------
#### [ EKS Auto Mode ]

```
GPU_NODE_SELECTOR_KEY="eks.amazonaws.com/instance-gpu-manufacturer"
```

------
#### [ Self-managed Karpenter ]

```
GPU_NODE_SELECTOR_KEY="karpenter.k8s.aws/instance-gpu-manufacturer"
```

------

Crea il file dei valori dell'esportatore DCGM:

#### file di valori dcgm-exporter
<a name="cluster-setup-cli-monitoring-dcgm-values"></a>

```
cat << EOF > /tmp/dcgm-exporter-values.yaml
resources:
  requests:
    memory: "512Mi"
    cpu: "100m"
  limits:
    memory: "1Gi"
    cpu: "500m"

serviceMonitor:
  enabled: true
  additionalLabels:
    release: kube-prometheus-stack

nodeSelector:
  ${GPU_NODE_SELECTOR_KEY}: nvidia

tolerations:
  - key: "nvidia.com/gpu"
    operator: "Exists"
    effect: "NoSchedule"

customMetrics: |
  # Clocks
  DCGM_FI_DEV_SM_CLOCK,  gauge, SM clock frequency (in MHz).
  DCGM_FI_DEV_MEM_CLOCK, gauge, Memory clock frequency (in MHz).
  # Temperature
  DCGM_FI_DEV_MEMORY_TEMP, gauge, Memory temperature (in C).
  DCGM_FI_DEV_GPU_TEMP,    gauge, GPU temperature (in C).
  # Power
  DCGM_FI_DEV_POWER_USAGE,              gauge, Power draw (in W).
  DCGM_FI_DEV_TOTAL_ENERGY_CONSUMPTION, counter, Total energy consumption since boot (in mJ).
  # PCIe
  DCGM_FI_PROF_PCIE_TX_BYTES,  counter, Number of bytes transmitted through PCIe TX (in KB) via NVML.
  DCGM_FI_PROF_PCIE_RX_BYTES,  counter, Number of bytes received through PCIe RX (in KB) via NVML.
  DCGM_FI_DEV_PCIE_REPLAY_COUNTER, counter, Total number of PCIe retries.
  # Utilization (the sample period varies depending on the product)
  DCGM_FI_DEV_GPU_UTIL,      gauge, GPU utilization (in %).
  DCGM_FI_DEV_MEM_COPY_UTIL, gauge, Memory utilization (in %).
  DCGM_FI_DEV_ENC_UTIL,      gauge, Encoder utilization (in %).
  DCGM_FI_DEV_DEC_UTIL,      gauge, Decoder utilization (in %).
  # Errors and violations
  DCGM_FI_DEV_XID_ERRORS,            gauge, Value of the last XID error encountered.
  DCGM_EXP_XID_ERRORS_COUNT,         gauge, Value of count of XID errors encountered.
  DCGM_FI_DEV_POWER_VIOLATION,       counter, Throttling duration due to power constraints (in us).
  DCGM_FI_DEV_THERMAL_VIOLATION,     counter, Throttling duration due to thermal constraints (in us).
  DCGM_FI_DEV_SYNC_BOOST_VIOLATION,  counter, Throttling duration due to sync-boost constraints (in us).
  DCGM_FI_DEV_BOARD_LIMIT_VIOLATION, counter, Throttling duration due to board limit constraints (in us).
  DCGM_FI_DEV_LOW_UTIL_VIOLATION,    counter, Throttling duration due to low utilization (in us).
  DCGM_FI_DEV_RELIABILITY_VIOLATION, counter, Throttling duration due to reliability constraints (in us).
  # Memory usage
  DCGM_FI_DEV_FB_FREE, gauge, Framebuffer memory free (in MiB).
  DCGM_FI_DEV_FB_USED, gauge, Framebuffer memory used (in MiB).
  # Retired pages
  DCGM_FI_DEV_RETIRED_SBE,     counter, Total number of retired pages due to single-bit errors.
  DCGM_FI_DEV_RETIRED_DBE,     counter, Total number of retired pages due to double-bit errors.
  DCGM_FI_DEV_RETIRED_PENDING, counter, Total number of pages pending retirement.
  # NVLink
  DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL, counter, Total number of NVLink bandwidth counters for all lanes.
  DCGM_FI_PROF_NVLINK_TX_BYTES,       counter, The rate of data transmitted over NVLink not including protocol headers in bytes per second.
  DCGM_FI_PROF_NVLINK_RX_BYTES,       counter, The rate of data received over NVLink not including protocol headers in bytes per second.
  # DCP metrics
  DCGM_FI_PROF_GR_ENGINE_ACTIVE,   gauge, Ratio of time the graphics engine is active (in %).
  DCGM_FI_PROF_SM_ACTIVE,          gauge, The ratio of cycles an SM has at least 1 warp assigned (in %).
  DCGM_FI_PROF_SM_OCCUPANCY,       gauge, The ratio of number of warps resident on an SM (in %).
  DCGM_FI_PROF_PIPE_TENSOR_ACTIVE, gauge, Ratio of cycles the tensor (HMMA) pipe is active (in %).
  DCGM_FI_PROF_DRAM_ACTIVE,        gauge, Ratio of cycles the device memory interface is active sending or receiving data (in %).
  DCGM_FI_DEV_CLOCK_THROTTLE_REASONS, gauge, Current clock throttle reasons (bitmask of DCGM_CLOCKS_THROTTLE_REASON_*).
  DCGM_FI_DEV_GPU_NVLINK_ERRORS,      gauge, Identifies a GPU NVLink error type returned by DCGM_FI_DEV_GPU_NVLINK_ERRORS.
  ## NVLink
  DCGM_FI_DEV_NVLINK_BANDWIDTH_L0, counter, The number of bytes of active NVLink rx or tx data including both header and payload.
  ## Remapped rows
  DCGM_FI_DEV_UNCORRECTABLE_REMAPPED_ROWS, counter, Number of remapped rows for uncorrectable errors.
  DCGM_FI_DEV_CORRECTABLE_REMAPPED_ROWS, counter, Number of remapped rows for correctable errors.
  DCGM_FI_DEV_ROW_REMAP_FAILURE, gauge, whether remapping of rows has failed.
  ## Profiling metrics
  DCGM_FI_PROF_PIPE_FP64_ACTIVE, gauge, Ratio of cycles the fp64 pipes are active (in %).
  DCGM_FI_PROF_PIPE_FP32_ACTIVE, gauge, Ratio of cycles the fp32 pipes are active (in %).
  DCGM_FI_PROF_PIPE_FP16_ACTIVE, gauge, Ratio of cycles the fp16 pipes are active (in %).
  # ECC
  DCGM_FI_DEV_ECC_SBE_VOL_TOTAL, counter, Total number of single-bit volatile ECC errors.
  DCGM_FI_DEV_ECC_DBE_VOL_TOTAL, counter, Total number of double-bit volatile ECC errors.
EOF
```

Il `customMetrics` campo sostituisce il set di parametri predefinito dell'esportatore DCGM con uno esteso che include la larghezza di banda NVLink, l'attività del tensore, il throughput PCIe, gli errori ECC e la limitazione termica. Per i carichi di lavoro di inferenza, consentono di capire se le unità di calcolo della GPU sono completamente utilizzate, se la GPU è inattiva tra una richiesta e l'altra a causa delle basse dimensioni dei batch, se il trasferimento di dati tra CPU e GPU è un collo di bottiglia, se la limitazione termica causa picchi di latenza e quanto spazio di memoria della GPU rimane per batch più grandi.

Installa l'esportatore DCGM:

```
helm install dcgm-exporter gpu-helm-charts/dcgm-exporter \
  --namespace monitoring \
  -f /tmp/dcgm-exporter-values.yaml
```

`tolerations`Consenti all'esportatore di funzionare sui GPU-tainted nodi che hai fornito nel passaggio 2. L'`serviceMonitor``release: kube-prometheus-stack`etichetta assicura che Prometheus lo scopra e lo cancelli automaticamente.

Verifica l'esportatore DCGM: DaemonSet

```
kubectl get daemonset dcgm-exporter -n monitoring
```

Una volta che un nodo GPU è in esecuzione, dovresti vedere un Pod pronto. Per convalidare le metriche DCGM, vai su **Drilldown > Metriche** in Grafana e cerca. `DCGM_`

 **Convalida le metriche DCGM in Grafana** 

![Pagina Grafana Drilldown Metrics filtrata da DCGM_ che mostra le metriche della GPU tra cui DCGM_FI_DEV_ECC_SBE_VOL_TOTAL, DCGM_FI_DEV_ENC_UTIL, DCGM_FI_DEV_FB_FREE e DCGM_FI_DEV_FB_USED](http://docs.aws.amazon.com/it_it/eks/latest/userguide/images/ml-cluster-setup-cli-dcgm-metrics-validate.png)


Per visualizzare la dashboard, vai a **Dashboard > GPU Monitoring > NVIDIA DCGM Exporter Dashboard**.

 **Dashboard di NVIDIA DCGM Exporter a Grafana** 

![Grafana NVIDIA DCGM Exporter dashboard che mostra l'utilizzo della GPU, la GPU Avg Temp, la GPU Framebuffer Mem Used e i pannelli GPU Power Total](http://docs.aws.amazon.com/it_it/eks/latest/userguide/images/ml-cluster-setup-cli-dcgm-dashboard.png)


## Pesi del modello S3 bucket
<a name="cluster-setup-cli-model-bucket"></a>

Crea un bucket Amazon S3 per archiviare i pesi dei modelli e configura un'EKS Pod Identity Association in modo che i pod del carico di lavoro possano leggerlo e scriverlo.

Se hai aperto un nuovo terminale, imposta il nome e la regione del cluster:

```
export CLUSTER_NAME=ai-eks-docs
export AWS_REGION=us-east-2
```

### Crea il bucket S3
<a name="_create_the_s3_bucket"></a>

Crea il bucket con un suffisso casuale per evitare collisioni di nomi:

```
BUCKET_SUFFIX=$(head -c 4 /dev/urandom | od -An -tx1 | tr -d ' \n')
MODEL_BUCKET="${CLUSTER_NAME}-models-${BUCKET_SUFFIX}"

aws s3 mb s3://${MODEL_BUCKET} --region ${AWS_REGION}
```

I bucket S3 creati dopo gennaio 2023 hanno la crittografia lato server (AES256) e il blocco dell'accesso pubblico abilitati per impostazione predefinita.

### Configura EKS Pod Identity per l'accesso a S3
<a name="_configure_eks_pod_identity_for_s3_access"></a>

Crea un `model-storage-sa` ServiceAccount nel `default` namespace, una policy IAM relativa al bucket del modello e un'associazione EKS Pod Identity che li colleghi. I pod di carico di lavoro impostati `serviceAccountName: model-storage-sa` saranno in grado di leggere e scrivere nel bucket.

```
kubectl create serviceaccount model-storage-sa
```

Crea la policy IAM:

```
POLICY_ARN=$(aws iam create-policy \
  --policy-name "${CLUSTER_NAME}-model-storage-policy" \
  --policy-document "{\"Version\": \"2012-10-17\", \"Statement\": [{\"Effect\": \"Allow\", \"Action\": [\"s3:GetObject\", \"s3:PutObject\", \"s3:ListBucket\", \"s3:DeleteObject\"], \"Resource\": [\"arn:aws:s3:::${MODEL_BUCKET}\", \"arn:aws:s3:::${MODEL_BUCKET}/*\"]}]}" \
  --query 'Policy.Arn' \
  --output text)

echo "Policy ARN: ${POLICY_ARN}"
```

**Nota**  
Questa politica concede `s3:DeleteObject` e `s3:PutObject` per la fase di convalida. Per i pod di inferenza di produzione che leggono solo i pesi dei modelli, `s3:PutObject` rimuovete e seguite least-privilege. `s3:DeleteObject`

Crea l'EKS Pod Identity Association. `eksctl`crea il ruolo IAM con la politica di fiducia corretta e lo collega a ServiceAccount:

```
eksctl create podidentityassociation \
  --cluster ${CLUSTER_NAME} \
  --namespace default \
  --service-account-name model-storage-sa \
  --role-name "${CLUSTER_NAME}-model-storage-role" \
  --permission-policy-arns ${POLICY_ARN} \
  --region ${AWS_REGION}
```

Verifica l'associazione:

```
eksctl get podidentityassociation --cluster ${CLUSTER_NAME} --region ${AWS_REGION}
```

L'output dovrebbe includere l'`model-storage-sa`associazione nel `default` namespace.

#### Convalida l'accesso a S3 da un Pod
<a name="cluster-setup-cli-s3-validate"></a>

Esegui un Pod singolo con l'immagine AWS CLI, utilizzando `model-storage-sa` ServiceAccount, per confermare che EKS Pod Identity è cablato e l'accesso S3 funziona:

```
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: s3-test
  labels:
    guide: ai-eks-docs
spec:
  serviceAccountName: model-storage-sa
  containers:
    - name: aws-cli
      image: public.ecr.aws/aws-cli/aws-cli:2.27.0
      command:
        - sh
        - -c
        - |
          echo "=== Caller Identity ==="
          aws sts get-caller-identity
          echo ""
          echo "=== S3 Write Test ==="
          echo "pod identity works" | aws s3 cp - s3://${MODEL_BUCKET}/test.txt
          echo ""
          echo "=== S3 List Test ==="
          aws s3 ls s3://${MODEL_BUCKET}/
          echo ""
          echo "=== S3 Delete Test ==="
          aws s3 rm s3://${MODEL_BUCKET}/test.txt
  restartPolicy: Never
EOF
```

Attendi il completamento del Pod e controlla i log:

```
kubectl wait --for=jsonpath='{.status.phase}'=Succeeded pod/s3-test --timeout=300s
kubectl logs s3-test
```

Output previsto:

```
=== Caller Identity ===
{
    "UserId": "AROA...:eks-ai-eks-docs-model-s-...",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/ai-eks-docs-model-storage-role/eks-ai-eks-docs-model-s-..."
}

=== S3 Write Test ===
upload: - to s3://ai-eks-docs-models-01234567/test.txt

=== S3 List Test ===
2026-05-04 12:00:00         19 test.txt

=== S3 Delete Test ===
delete: s3://ai-eks-docs-models-01234567/test.txt
```

L'identità del chiamante conferma che il Pod ha assunto il `${CLUSTER_NAME}-model-storage-role` ruolo tramite EKS Pod Identity. I comandi S3 confermano l'accesso in lettura e scrittura.

Pulisci il test Pod:

```
kubectl delete pod s3-test
```

## Fasi successive
<a name="cluster-setup-cli-next-steps"></a>

Con il cluster pronto, puoi passare al modello [Load & Serve per implementare un modello](ml-inference-load-serve-model.md) linguistico di grandi dimensioni e interagire con l'endpoint di inferenza.

## Pulizia
<a name="cluster-setup-cli-cleanup"></a>

**Suggerimento**  
Se intendi continuare con le sezioni successive di questa guida, salta la pulizia completa. Eseguilo solo quando hai finito.

```
export CLUSTER_NAME=ai-eks-docs
export AWS_REGION=us-east-2
```

```
kubectl delete pod nvidia-smi --ignore-not-found
kubectl delete deployment gpu-overflow-test --ignore-not-found
```

### Annulla la prenotazione della capacità
<a name="cluster-setup-cli-cleanup-cancel-reservation"></a>

Se hai creato un ODCR, annullalo prima:

```
INSTANCE_TYPE="g6e.4xlarge"
CAPACITY_RESERVATION_ID=$(aws ec2 describe-capacity-reservations \
  --filters "Name=state,Values=active" "Name=instance-type,Values=${INSTANCE_TYPE}" \
  --query 'CapacityReservations[0].CapacityReservationId' \
  --output text \
  --region ${AWS_REGION})
aws ec2 cancel-capacity-reservation --capacity-reservation-id ${CAPACITY_RESERVATION_ID}
```

**Importante**  
L'annullamento di una prenotazione non interrompe le istanze in esecuzione. Continuano alle On-Demand tariffe standard fino alla loro cessazione. Elimina prima la distribuzione per svuotare il nodo riservato prima di annullarla.

### Pulisci il monitoraggio
<a name="cluster-setup-cli-cleanup-monitoring"></a>

Cerca l'ARN della policy IAM:

```
AMP_POLICY_ARN=$(aws iam list-policies \
  --scope Local \
  --query "Policies[?PolicyName=='${CLUSTER_NAME}-amp-grafana-policy'].Arn" \
  --output text)
echo "AMP Policy ARN: ${AMP_POLICY_ARN}"
```

Cerca l'ID dell'area di lavoro AMP:

```
AMP_WORKSPACE_ID=$(aws amp list-workspaces \
  --alias "amp-ws-${CLUSTER_NAME}" \
  --query 'workspaces[0].workspaceId' \
  --output text \
  --region ${AWS_REGION})
echo "AMP Workspace ID: ${AMP_WORKSPACE_ID}"
```

Disinstalla la versione Helm dell'esportatore DCGM:

```
helm uninstall dcgm-exporter -n monitoring
```

Disinstalla la versione kube-prometheus-stack Helm:

```
helm uninstall kube-prometheus-stack -n monitoring
```

Elimina l'associazione EKS Pod Identity per l'account del servizio di ingest Prometheus:

```
eksctl delete podidentityassociation \
  --cluster ${CLUSTER_NAME} \
  --namespace monitoring \
  --service-account-name amp-iamproxy-ingest-service-account \
  --region ${AWS_REGION}
```

Eliminare l'associazione EKS Pod Identity per l'account del servizio Grafana:

```
eksctl delete podidentityassociation \
  --cluster ${CLUSTER_NAME} \
  --namespace monitoring \
  --service-account-name grafana-sa \
  --region ${AWS_REGION}
```

Elimina la policy IAM utilizzata da Prometheus e Grafana:

```
aws iam delete-policy --policy-arn ${AMP_POLICY_ARN}
```

Elimina l'area di lavoro AMP:

```
aws amp delete-workspace --workspace-id ${AMP_WORKSPACE_ID} --region ${AWS_REGION}
```

Elimina lo spazio dei nomi di monitoraggio:

```
kubectl delete namespace monitoring
```

### Pulisci i pesi del modello (bucket S3)
<a name="cluster-setup-cli-cleanup-model-bucket"></a>

Cerca il nome del bucket del modello:

```
MODEL_BUCKET=$(aws s3api list-buckets \
  --query "Buckets[?starts_with(Name, '${CLUSTER_NAME}-models-')].Name | [0]" \
  --output text)
echo "Model bucket: ${MODEL_BUCKET}"
```

Cerca l'ARN della policy IAM:

```
POLICY_ARN=$(aws iam list-policies \
  --scope Local \
  --query "Policies[?PolicyName=='${CLUSTER_NAME}-model-storage-policy'].Arn" \
  --output text)
echo "Policy ARN: ${POLICY_ARN}"
```

Elimina il bucket del modello S3 e tutti i suoi oggetti:

```
aws s3 rb s3://${MODEL_BUCKET} --force
```

Elimina l'associazione EKS Pod Identity:

```
eksctl delete podidentityassociation \
  --cluster ${CLUSTER_NAME} \
  --namespace default \
  --service-account-name model-storage-sa \
  --region ${AWS_REGION}
```

Elimina la politica IAM:

```
aws iam delete-policy --policy-arn ${POLICY_ARN}
```

Elimina Kubernetes: ServiceAccount

```
kubectl delete serviceaccount model-storage-sa
```

### Elimina le risorse rimanenti e il cluster
<a name="cluster-setup-cli-cleanup-delete-resources"></a>

```
kubectl delete nodepool gpu-inf --ignore-not-found
kubectl delete nodeclass gpu-inf --ignore-not-found
kubectl delete ec2nodeclass gpu-inf --ignore-not-found
eksctl delete cluster --name=$CLUSTER_NAME --region=$AWS_REGION
```