

 **Aidez à améliorer cette page** 

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Pour contribuer à ce guide de l'utilisateur, cliquez sur le GitHub lien **Modifier cette page sur** qui se trouve dans le volet droit de chaque page.

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Configuration du cluster Amazon EKS pour les AI/ML charges de travail à l'aide de CLI
<a name="ml-cluster-setup-cli"></a>

**Astuce**  
 [Inscrivez-vous](https://events.eksworkshop.com/workshops/genai/) aux prochains AI/ML ateliers Amazon EKS.

Cette section explique les étapes à suivre pour créer l'infrastructure requise pour exécuter des charges de travail de formation ou d'inférence sur Amazon EKS via des commandes CLI. Les étapes incluent la création d'un cluster EKS, de GPU-enabled nœuds avec EKS Auto Mode ou Karpenter, d'une pile de surveillance avec Prometheus et Grafana et d'un stockage Amazon S3 pour le poids des modèles.

Consultez la documentation d'[EKS Auto Mode](https://docs.aws.amazon.com/eks/latest/userguide/automode.html) et de [Karpenter](https://karpenter.sh/docs/) pour plus d'informations sur la manière dont ces fonctionnalités fournissent et dimensionnent automatiquement les instances EC2 dans les clusters EKS.

 **High-level architecture et flux de travail** 

![High-level architecture illustrant le cluster EKS avec Karpenter NodeClass et NodePool la pile de surveillance Grafana et Prometheus écrivant sur Amazon Managed Service pour Prometheus, un compartiment Amazon S3 pour les poids des modèles et les étapes numérotées du flux de travail](http://docs.aws.amazon.com/fr_fr/eks/latest/userguide/images/ml-cluster-setup-architecture.png)


Le schéma montre l'architecture AWS de haut niveau pour la configuration de cette section. Les étapes numérotées sur la droite indiquent l'ordre dans lequel vous avez effectué la configuration dans les étapes ci-dessous.

## Conditions préalables
<a name="cluster-setup-cli-prerequisites"></a>
+  `kubectl`>= 1,35. Pour les instructions de configuration, voir[`Configurer kubectl et eksctl`](install-kubectl.md).
+  AWS CLI >= 2,27. Pour les instructions de configuration, reportez-vous à la section [Installation](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html).
+ Casque >= 3.14. Pour les instructions de configuration, voir [Setup Helm](helm.md).
+  `jq`. Pour les instructions de configuration, voir [Download jq](https://jqlang.github.io/jq/download/).
+  `eksctl`>= 0,227,0. Pour les instructions de configuration, consultez la section [Installation](https://eksctl.io/installation) dans la `eksctl` documentation.

Vérifiez votre `eksctl` version :

```
eksctl version
```

Si vous utilisez une version antérieure à 0.227.0, suivez le [guide d'installation d'eksctl pour](https://eksctl.io/installation/) passer à la dernière version.

## Définir les variables d'environnement
<a name="cluster-setup-cli-set-environment-variables"></a>

Veillez à ce que le nom du cluster et AWS la région suivants soient cohérents tout au long de ces étapes. Si vous le modifiez, les commandes suivantes risquent de cibler le mauvais cluster EKS.

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

L'utilisation de tous les AZs disponibles améliore la tolérance aux pannes et augmente les chances d'obtenir la capacité du 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
```

**Important**  
Les zones de disponibilité `use1-az3``usw1-az2`, et `cac1-az3` sont exclues car [Amazon EKS ne prend pas en charge le placement de plans de contrôle dans ces zones](https://repost.aws/knowledge-center/eks-cluster-creation-errors). La création d'un cluster avec des sous-réseaux dans l'une de ces zones entraîne un`UnsupportedAvailabilityZoneException`.

Sortie attendue :

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

Les AZ de la sortie varient selon les régions. Cet exemple montre les AZ disponibles pour `us-east-2` la région.

## Création d'un cluster et d'un GPU NodePool
<a name="cluster-setup-cli-create-cluster-and-gpu-nodepool"></a>

Cette section fournit deux chemins pour créer votre cluster et vos GPU-enabled nœuds EKS, illustrés dans le schéma suivant. Choisissez une seule option dans le guide.
+  **Mode automatique EKS** — Outre les principaux [modules complémentaires de mise en réseau, de stockage et d'équilibrage de charge](https://docs.aws.amazon.com/eks/latest/userguide/eks-add-ons.html#addon-consider-auto), le mode automatique EKS inclut et gère les fonctionnalités suivantes pour les charges de travail d'entraînement et d'inférence : agent de surveillance des nœuds EKS, réparation automatique des nœuds, snapshotter [SOCI](https://github.com/awslabs/soci-snapshotter) pour des extractions rapides de conteneurs et disponibilité du GPU pour le réglage par défaut. NodeClass Le plug-in de périphérique NVIDIA est inclus dans l'AMI accélérée Bottlerocket qu'EKS Auto Mode utilise pour les nœuds. GPU-enabled 
+  **Self-managed Karpenter** — Sur un cluster EKS sans mode automatique EKS, vous êtes responsable de l'installation et de la configuration des composants nécessaires aux charges de travail de formation et d'inférence. Cela inclut les extensions réseau (VPC CNI, CoreDNS, kube-proxy), Karpenter, l'agent de surveillance des nœuds EKS, le plug-in de périphérique NVIDIA et le snapshotter SOCI pour des extractions rapides de conteneurs.

 **Options du cluster EKS : mode automatique EKS et Karpenter autogéré** 

![Side-by-side comparaison des deux options de cluster : un cluster en mode automatique EKS avec a NodePool, et un cluster standard EKS avec Karpenter, CoreDNS, VPC CNI, plug-in de périphérique NVIDIA, agent EKS Pod Identity, agent EKS Pod Identity, agent de surveillance des nœuds, kube-proxy et a et NodeClass NodePool](http://docs.aws.amazon.com/fr_fr/eks/latest/userguide/images/ml-cluster-setup-cli-cluster-options.png)


Dans chacune des étapes suivantes, choisissez un chemin (mode automatique EKS, Karpenter) et suivez-le tout au long de la procédure. Après avoir effectué les étapes correspondant au chemin que vous avez choisi, vous disposerez d'un cluster EKS doté d'un GPU NodePool prêt à planifier les charges de travail du GPU.

## Étape 1 : créer un cluster
<a name="cluster-setup-cli-create-cluster"></a>

Commencez par créer votre cluster EKS et installez les composants du cluster nécessaires aux charges de travail du GPU.

Avec le mode automatique EKS, une seule `eksctl create cluster --enable-auto-mode` commande approvisionne un cluster EKS prêt à supporter les charges de travail du GPU.

Avec Karpenter autogéré, la `eksctl create cluster` commande fournit les modules complémentaires réseau principaux, puis des étapes supplémentaires sont nécessaires pour activer la réparation automatique des nœuds via une fonctionnalité Karpenter, installer l'agent de surveillance des nœuds EKS et installer le plug-in de périphérique NVIDIA.

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

 **Création d'un cluster en mode automatique EKS** 

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

L'exécution de cette commande prend quelques minutes. Une fois l'opération terminée, votre fichier kubeconfig est `eksctl` automatiquement mis à jour pour qu'il fonctionne avec le cluster nouvellement provisionné. Vérifiez que le cluster est opérationnel :

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

Sortie attendue :

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

En mode automatique d'EKS, le CNI, le kube-proxy et le CoreDNS du VPC s'exécutent en tant que composants gérés et n'apparaissent pas sous forme de pods. `kube-system`

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

 **Authentifier Helm auprès de l'ECR public** 

 `eksctl`extrait le graphique Karpenter Helm d'Amazon Public ECR. Authentifiez-vous avant de créer le cluster pour éviter une erreur 403 lors de l'étape d'installation de Helm :

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

Public ECR est un service mondial hébergé dans`us-east-1`. À utiliser `--region us-east-1` ici quelle que soit la région dans laquelle se trouve votre cluster EKS.

Résultat attendu : `Login Succeeded` 

 **Créez le cluster EKS avec Karpenter** 

Stockez votre version de Karpenter dans une variable d'environnement pour une utilisation ultérieure. Pour les dernières versions de Karpenter, consultez les versions de [Karpenter](https://github.com/aws/karpenter-provider-aws/releases) sur. GitHub

```
export KARPENTER_VERSION=1.12.0
```

### Configuration du cluster : YAML et `eksctl` créent un 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
```

Cette commande prend environ 15 minutes. Il crée un cluster EKS avec un groupe de nœuds gérés dédié à l'hébergement des modules complémentaires et du contrôleur Karpenter. Karpenter est installé avec la file d'attente d'interruption Spot activée afin de pouvoir gérer les recommandations d'interruption et de rééquilibrage Spot. Le `autoModeConfig.enabled: false` paramètre indique clairement que ce cluster n'utilise pas le mode automatique EKS. Les composants Karpenter installés dans ce chemin sont donc responsables de la gestion des nœuds.

Le cluster dispose également de l'agent [EKS Pod Identity et de l'agent](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html) de [surveillance des nœuds EKS](https://docs.aws.amazon.com/eks/latest/userguide/node-health.html) en tant que modules complémentaires EKS. EKS Pod Identity est utilisé plus loin dans le guide. L'agent de surveillance des nœuds EKS s'exécute sur chaque nœud et lit les journaux du noyau pour définir les conditions du nœud `AcceleratedHardwareReady``KernelReady`, telles que`NetworkingReady`, et, que la réparation automatique des nœuds de Karpenter utilise pour décider quand remplacer un nœud défectueux.

Vérifiez que le cluster est opérationnel :

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

Les résultats attendus incluent Karpenter, CoreDNS, kube-proxy, aws-node (VPC CNI), l'agent d'identité EKS Pod et l'agent de surveillance des nœuds 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
```

 **Activer la réparation automatique des nœuds** 

Le mode automatique EKS active la réparation automatique des nœuds par défaut. Sur Karpenter autogéré, la réparation automatique des nœuds est bloquée derrière la porte des `NodeRepair=true` fonctionnalités et doit être activée explicitement. La commande suivante corrige le déploiement de Karpenter pour ajouter le portail des `NodeRepair=true` fonctionnalités. La mise à jour de l'environnement de déploiement déclenche le déploiement des pods Karpenter :

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

Sortie attendue :

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

Attendez que les capsules Karpenter soient déployées :

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

 **Installer le plug-in pour appareil NVIDIA** 

L' EKS-optimized AMI AL2023 n'inclut pas le [plug-in de périphérique NVIDIA](https://github.com/NVIDIA/k8s-device-plugin) (contrairement à l'AMI Bottlerocket utilisée par EKS Auto Mode). Installez-le via Helm pour rendre les ressources GPU utilisables avec les pods du 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`: désactive la vérification de Mellanox OFED (InfiniBand), qui n'utilise pas AWS 
+  `nodeSelector.amiFamily: al2023`: s'étend uniquement DaemonSet aux nœuds AL2023 (le plugin est déjà intégré à Bottlerocket)
+  `gfd.enabled: true`: active les étiquettes de découverte des fonctionnalités du GPU (`nvidia.com/gpu.product``nvidia.com/gpu.memory`,, etc.)

Vérifiez que le plug-in de l'appareil NVIDIA est installé. On s'attend à ce qu'il n'y ait aucun module d'extension pour appareil tant qu'un GPU NodePool portant l'étiquette correspondante n'est pas configuré.

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

Sortie attendue :

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

------

**Avertissement**  
Pour le mode automatique EKS et les chemins Karpenter autogérés, la réparation automatique des nœuds se comporte de la même manière que pour les nœuds approvisionnés par. NodePools La réparation automatique des nœuds en mode automatique EKS et Karpenter est une méthode de perturbation *puissante* qui contourne l'`karpenter.sh/do-not-disrupt`annotation PodDisruptionBudgets et. `terminationGracePeriod` La réparation automatique des nœuds attend 10 minutes avant de remplacer un nœud dont la `AcceleratedHardwareReady` condition est définie sur `False` et 30 minutes pour les [autres conditions de réparation](https://docs.aws.amazon.com/eks/latest/userguide/node-repair.html).

## Étape 2 : Création d'un GPU dynamique NodePool
<a name="cluster-setup-cli-create-gpu-nodepool"></a>

Définissez un NodePool qui approvisionne dynamiquement les instances de G-family GPU avec une génération supérieure à 4, en utilisant la capacité Spot On-Demand comme solution de secours. Le mode automatique EKS et les chemins Karpenter utilisent tous deux la même NodePool API, la seule différence étant celle vers laquelle ils NodeClass pointent. En mode EKS Auto, le bundle sélectionne `default` NodeClass déjà l'AMI appropriée et configure le pull parallèle SOCI, de sorte que c'est NodePool le seul objet que vous créez. Dans Karpenter autogéré, vous avez également besoin d'une personnalisation `EC2NodeClass` qui épingle l'AMI et ajuste le SOCI.

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

En mode EKS Auto, le bundle sélectionne `default` NodeClass automatiquement l'AMI Bottlerocket pour les instances GPU, qui inclut les pilotes NVIDIA préinstallés, le plug-in de périphérique NVIDIA et le pull parallèle SOCI. Il vous suffit d'appliquer un NodePool qui fait référence à `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
```

Cela NodePool provisionne les instances G-family GPU avec une génération supérieure à 4 ([G5](https://aws.amazon.com/ec2/instance-types/g5/), [G6e](https://aws.amazon.com/ec2/instance-types/g6e/), [G7e](https://aws.amazon.com/ec2/instance-types/g7e/), etc.). Cette `nvidia.com/gpu:NoSchedule` odeur garantit que seuls les GPU-eligible pods sont planifiés sur ces nœuds.

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

Self-managed Karpenter n'inclut pas de valeur par défaut NodeClass. Vous devez d'abord créer un `EC2NodeClass` identifiant qui épingle l'alias de l'AMI EKS-optimized NVIDIA AL2023, active le protocole SOCI via le portail des `FastImagePull` fonctionnalités et configure pour `instanceStorePolicy: RAID0` déplacer le cache d'images containerd vers le NVMe local. Ensuite, vous créez le NodePool qui y fait référence.

 **Créez le 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`assemble des disques NVMe locaux dans une RAID-0 matrice. L'alias de l'`al2023@latest`AMI devient l' EKS-optimized AMI AL2023. Lorsque Karpenter lance un type d'instance GPU, il sélectionne automatiquement la variante accélérée AL2023\_x86\_64\_NVIDIA, qui inclut le pilote NVIDIA préinstallé.

La porte de `FastImagePull` fonctionnalités active le mode SOCI Snapshotter parallel pull, qui télécharge et décompresse les couches d'images simultanément. Cela correspond au comportement du mode automatique EKS sur les familles d'instances G, P et Trn. Le `containerd.config` bloc règle le snapshotter SOCI pour les images : ECR-hosted 
+  `max_concurrent_downloads_per_image: 20`permet de télécharger jusqu'à 20 couches en parallèle par image. La valeur par défaut est de 3 sur Bottlerocket et de 20 sur AL2023. Valeur recommandée pour l'ECR.
+  `concurrent_download_chunk_size: "16mb"`divise chaque couche en segments de 16 Mo téléchargés en parallèle via des requêtes de plage HTTP. Recommandé pour les registres qui prennent en charge les Range GET (ECR le fait).
+  `max_concurrent_unpacks_per_image: 12`déballe jusqu'à 12 couches à la fois. La valeur par défaut est 1 sur Bottlerocket et 12 sur AL2023.
+  `discard_unpacked_layers: true`supprime les blobs de couches compressés après le déballage pour économiser de l'espace disque.

Pour plus d'options de réglage SOCI (téléchargements simultanés par image, taille des blocs, etc.), consultez le plan SOCI de [Karpenter](https://github.com/aws-samples/karpenter-blueprints/tree/main/blueprints/soci-snapshotter).

Validez le EC2NodeClass :

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

Résultat attendu :`READY True`. Si`False`, exécutez `kubectl describe ec2nodeclass gpu-inf` et vérifiez les conditions pour détecter les balises de sous-réseau ou de groupe de sécurité manquantes.

 **Créez le 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`étiquette figurant sur le modèle de nœud est celle DaemonSet utilisée par le plug-in de périphérique NVIDIA pour sélectionner ces nœuds.

------

Validez que le NodePool a été créé :

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

Sortie attendue :

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

Sur le chemin Karpenter autogéré, la colonne NODECLASS affiche au lieu de. `gpu-inf` `default`

## Étape 3 : Test avec un module d'échantillonnage
<a name="cluster-setup-cli-test-with-a-sample-pod"></a>

Testez la NodePool configuration de votre GPU avec 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
```

Vérifiez que le Pod est planifié et terminé avec succès.

```
kubectl get pods
```

Sortie attendue :

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

Le STATUS : Terminé signifie que la commande nvidia-smi a été exécutée et s'est terminée. Consultez les journaux du Pod pour voir le GPU détecté par le nœud.

```
kubectl logs nvidia-smi
```

Sortie attendue :

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

La sortie indique le modèle de GPU, la version du pilote, la version CUDA et la mémoire disponible. Dans cet exemple, Karpenter a provisionné une instance G7e dotée d'un GPU NVIDIA RTX PRO 6000 Blackwell avec 96 Go de mémoire. La température actuelle du GPU est de 30°C et P0 signifie que le GPU est dans son état de performance le plus élevé (inactif mais prêt). Le 81 W/600 W indique la consommation électrique actuelle par rapport à la capacité maximale, et 0 MiB/97887 MiB indique la mémoire GPU actuellement utilisée par rapport au total disponible. Comme le Pod vient d'exécuter nvidia-smi et de le quitter, aucune charge de travail n'utilise le GPU. La mémoire est donc à 0 et l'alimentation est inactive. La version du pilote GPU NVIDIA (580.126.09) provient de l'AMI Bottlerocket, tandis que la version CUDA (13.0) provient de l'image du conteneur. Le modèle de GPU et la mémoire varient en fonction du type d'instance sélectionné par Karpenter. Les instances G5 sont équipées de GPU NVIDIA A10G (24 Go), les instances G6e de GPU NVIDIA L40S (48 Go) et les instances G7e de GPU NVIDIA RTX PRO 6000 (96 Go).

Pour comprendre comment Karpenter et le planificateur Kubernetes se sont coordonnés pour approvisionner un nœud et placer le pod, vérifiez les événements du cycle de vie du pod :

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

Sortie attendue :

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

Ces événements montrent la séquence de planification du Pod : le Pod échoue initialement car aucun nœud GPU n'existe (FailedScheduling), Karpenter désigne un nouveau NodeClaim (Nominé), le planificateur attribue le Pod une fois que le nœud est prêt (programmé), puis l'image du conteneur est extraite et démarrée. Le mode automatique EKS est livré avec un pull parallèle SOCI (Seekable OCI) installé et configuré immédiatement sur les instances G, P et Trn. Notez qu'en raison de l'extraction parallèle SOCI, l'image du conteneur a été extraite de l'ECR en moins de 2 secondes (1,237 s).

A NodeClaim est une demande créée par Karpenter pour approvisionner un nœud spécifique. Il indique le type d'instance, le type de capacité, l'AZ et indique si le nœud est prêt.

```
kubectl get nodeclaims
```

 NodeClaim Résultat attendu :

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

Le type d'instance et l'AZ peuvent varier. Toute G-family instance dont la génération est supérieure à 4 est éligible.

L'`FailedCreatePodSandBox`avertissement entrant `kubectl describe pod nvidia-smi` est transitoire et attendu. Le VPC CNI s'initialise de manière asynchrone une fois le nœud rejoint, et le kubelet réessaie automatiquement. Si le Pod reste à l'`ContainerCreating`intérieur, vérifiez les événements du nœud avec`kubectl describe node <node-name>`.

**Astuce**  
Si aucun nœud n'apparaît, vérifiez s'il n'y a pas d'erreur de capacité insuffisante :  

```
kubectl get events | grep InsufficientCapacityError
```
Karpenter met en cache les offres non disponibles pendant 3 minutes. L'élargissement des types d'instances et des AZ autorisés NodePool augmente les chances d'obtenir une capacité d'atterrissage.

**Note**  
Les instances Spot lancées par Karpenter n'apparaîtront pas dans la console EC2 Spot Requests. Karpenter utilise l'[https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateFleet.html](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateFleet.html)API EC2 avec. `type: instant` Les instances apparaissent dans la console EC2 Instances avec un `spot` cycle de vie.

## Étape 4 : ajouter de la capacité réservée au NodePool (facultatif)
<a name="cluster-setup-cli-attach-odcr"></a>

Pour utiliser d'abord la capacité réservée avec une solution de Spot/On-Demand secours, créez un ODCR et attachez-le à votre NodeClass, puis mettez à jour la dynamique NodePool de l'étape 2 pour autoriser `reserved` également la capacité. L'appel de l'API de réservation est le même pour les deux chemins ; la NodeClass pièce jointe est différente car EKS Auto Mode et Karpenter autogéré utilisent des types différents NodeClass .

**Avertissement**  
La commande suivante entraîne des frais pour le type d'instance réservée jusqu'à ce que vous l'annuliez avec`aws ec2 cancel-capacity-reservation --capacity-reservation-id <id>`.

Créez la réservation de 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
```

Si un `InsufficientInstanceCapacity` message d'erreur s'affiche, passez `CR_AZ` à un autre AZ et réessayez.

Recherchez l'ID de réservation de capacité et stockez-le dans une variable shell pour les étapes suivantes :

```
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}"
```

Appliquez ensuite les NodePool modifications NodeClass et à votre chemin :

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

En mode automatique d'EKS, le bundle `default` NodeClass est en lecture seule. Créez donc une personnalisation NodeClass qui fait référence à la réservation, puis mettez à jour le point de NodePool destination NodeClass et ajoutez de la `reserved` capacité à la liste. `capacity-type`

### NodeClass YAML personnalisé
<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
```

La `kubernetes.io/role/internal-elb: "1"` balise garantit le lancement des nœuds uniquement dans des sous-réseaux privés.

Mettez NodePool à jour le pour utiliser ODCR-backed NodeClass et inclure `reserved` comme type de capacité :

### NodePool YAML mis à jour
<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 ]

Pour Karpenter autogéré, réappliquez le code `EC2NodeClass` que vous avez créé à l'étape 2 en ajoutant. `capacityReservationSelectorTerms` Le nom et la forme du champ correspondent au mode automatique EKS `NodeClass` affiché dans l'autre onglet.

### EC2NodeClass YAML mis à jour
<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
```

Le seul changement par rapport à l'étape 2 concerne le nouveau `capacityReservationSelectorTerms` champ. Tous les autres champs restent les mêmes.

Mettez à jour le NodePool pour inclure `reserved` en tant que type de capacité :

### NodePool YAML mis à jour
<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 considère `reserved` que c'est l'option la plus rentable et la lance en premier. Une fois la réservation complète, elle revient à Spot or On-Demand.

### Vérifiez la priorité réservée et la solution de secours Spot
<a name="cluster-setup-cli-step4-validate"></a>

Après avoir appliqué les modifications, confirmez que Karpenter donne la priorité à la capacité réservée et revient à Spot ou. On-Demand Déployez un déploiement à 2 répliques qui nécessite 1 GPU par pod. L'ODCR est destiné à une instance, donc le premier Pod déclenche Karpenter pour lancer un nœud réservé. Le deuxième Pod ne peut pas tenir sur le nœud réservé et incite Karpenter à lancer un autre nœud à partir de Spot ou de On-Demand sa capacité.

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

Contrairement au pod de `nvidia-smi` test de l'étape 3 qui s'exécutait et s'arrêtait, ce déploiement permet aux pods de fonctionner (`sleep infinity`) afin qu'ils contiennent le GPU et ne libèrent pas le nœud.

Vérifiez les pods planifiés sur les différents nœuds :

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

Sortie attendue :

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

Les deux pods fonctionnent, chacun sur un nœud différent.

Consultez le NodeClaims pour connaître les types de capacité :

```
kubectl get nodeclaims
```

Sortie attendue :

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

Le nœud réservé a été lancé en premier, suivi d'un Spot ou d'un On-Demand nœud une fois la réservation complète.

Nettoyez le déploiement des tests :

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

## Contrôle
<a name="cluster-setup-cli-monitoring"></a>

Installez une pile de surveillance qui collecte les métriques des clusters, des nœuds et du GPU dans Amazon Managed Service for Prometheus (AMP), et visualisez-les avec Grafana. Le graphique Helm kube-prometheus-stack déploie Prometheus pour extraire et écrire à distance des métriques dans AMP, ainsi qu'un Grafana autogéré pour les tableaux de bord. L'exportateur NVIDIA DCGM ajoute GPU-specific des métriques (utilisation, mémoire, température, puissance, NVLink, activité tensorielle).

Prometheus, Grafana et l'opérateur atterrissent par défaut sur des nœuds autres que le GPU, car les nœuds GPU sont porteurs de cette odeur. `nvidia.com/gpu:NoSchedule` Node-exporter et l'exportateur DCGM fonctionnent tous deux sur des nœuds GPU, ce qui nous permet de récupérer les métriques de l'hôte et du GPU à l'échelle du parc.

Si vous avez ouvert un nouveau terminal, définissez le nom et la région du cluster :

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

### Création de l'espace de travail AMP
<a name="_create_the_amp_workspace"></a>

Créez un espace de travail AMP pour stocker les métriques :

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

Obtenez l'identifiant de l'espace de travail :

```
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}"
```

Obtenez le point de terminaison d'écriture à distance :

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

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

### Création d'une politique IAM et d'associations d'identité EKS Pod
<a name="_create_iam_policy_and_eks_pod_identity_associations"></a>

Créez une politique IAM qui permet à Prometheus d'écrire à distance des métriques et à Grafana de les interroger :

```
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}"
```

Créez l'espace de noms de surveillance et les comptes de service pour Prometheus et Grafana :

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

Créez des associations d'identité EKS Pod pour lier les comptes de service à la politique 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}
```

Vérifiez que les deux associations EKS Pod Identity ont été créées :

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

La sortie attendue doit inclure les deux `amp-iamproxy-ingest-service-account` et `grafana-sa` dans l'espace de `monitoring` noms.

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

Ajoutez le dépôt Helm :

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

Ce fichier de valeurs omet un NodeSelector pour Prometheus, Grafana et l'opérateur : l'altération des nœuds GPU les empêche d'accéder aux nœuds `nvidia.com/gpu:NoSchedule` GPU, de sorte qu'ils atterrissent par défaut sur le système ou sur le pool à usage général. Node-exporter utilise une tolérance par caractères génériques afin de s'exécuter sur tous les nœuds, y compris les nœuds GPU, afin de collecter des métriques à l'échelle du parc.

Créez le fichier de valeurs :

#### fichier de valeurs 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
```

Vérifiez que les variables ont été correctement renseignées :

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

Vous devriez voir l'URL complète du point de terminaison AMP (en commençant par`https://aps-workspaces…​`), votre région et la ligne node-exporter`tolerations:`. Si un élément est vide, réexportez les variables et recréez le fichier.

Installez le graphique :

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

Vérifiez que les pods fonctionnent :

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

Sortie attendue :

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

La pile déploie les composants suivants :
+  **Prometheus** StatefulSet () : supprime les métriques et les écrit à distance dans AMP
+  **Grafana** : tableaux de bord et visualisation, préconfigurés avec la source de données AMP
+  **kube-state-metrics** : génère des métriques sur l'état des objets Kubernetes (état du pod, ressource, états) requests/limits NodeClaim 
+  **node-exporter** (DaemonSetun par nœud) : collecte les métriques au niveau de l'hôte (processeur, mémoire, disque, réseau)
+  **opérateur** : gère les ressources personnalisées Prometheus et Alertmanager

Le gestionnaire d'alertes est désactivé dans cette configuration.

### Accédez à Grafana
<a name="_access_grafana"></a>

Ouvrez un terminal séparé et redirigez le port pour accéder à Grafana :

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

Ouvrez [http://localhost:3000](http://localhost:3000) dans votre navigateur. Connectez-vous avec le nom d'utilisateur `admin` et le mot de passe à l'aide de la commande suivante :

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

Pour vérifier que le pipeline de métriques fonctionne de bout en bout :

1. Accédez à **Connexions > Sources de données** et confirmez qu'elle `Amazon-Managed-Prometheus` est répertoriée comme source de données par défaut.

    **Valider la source de données AMP dans Grafana**   
![Page Grafana Connections Amazon-Managed-Prometheus répertoriée comme source de données par défaut](http://docs.aws.amazon.com/fr_fr/eks/latest/userguide/images/ml-cluster-setup-cli-prometheus-ds-validate.png)

1. Accédez à **Drilldown > Métriques** et recherchez la `up` métrique. Vous devriez voir les résultats des cibles de scrape de votre cluster.

    **Validez la `up` métrique dans Grafana**   
![Page Grafana Drilldown Metrics affichant la métrique ascendante avec des barres d'état vertes indiquant les cibles de scrape actives](http://docs.aws.amazon.com/fr_fr/eks/latest/userguide/images/ml-cluster-setup-cli-prometheus-metrics-validate.png)

S'il `up` affiche des résultats, le pipeline (cluster → Prometheus → AMP → Grafana) fonctionne.

### Déployez l'exportateur DCGM pour les métriques du GPU
<a name="_deploy_the_dcgm_exporter_for_gpu_metrics"></a>

Le kube-prometheus-stack collecte les métriques du processeur et de la mémoire au niveau du nœud, mais pas les métriques du GPU. L'exportateur NVIDIA DCGM ajoute l'utilisation du GPU, l'utilisation de la mémoire, la température, la consommation d'énergie, la bande passante NVLink et l'activité des tenseurs.

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

Définissez la clé de sélection du nœud GPU pour votre trajectoire. Le mode automatique EKS et Karpenter autogéré utilisent des clés d'étiquette différentes selon le fabricant du 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"
```

------

Créez le fichier de valeurs de l'exportateur DCGM :

#### fichier de valeurs 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
```

Le `customMetrics` champ remplace l'ensemble de mesures par défaut de l'exportateur DCGM par un ensemble étendu qui inclut la bande passante NVLink, l'activité des tenseurs, le débit PCIe, les erreurs ECC et la régulation thermique. Pour les charges de travail d'inférence, elles vous aident à déterminer si les unités de calcul du processeur graphique sont pleinement utilisées, si le processeur graphique est inactif entre les demandes en raison de la faible taille des lots, si le transfert de données entre le processeur et le processeur graphique constitue un goulot d'étranglement, si le ralentissement thermique est à l'origine des pics de latence et quelle est la marge de mémoire restante pour les lots plus importants.

Installez l'exportateur DCGM :

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

`tolerations`Autorisez l'exportateur à s'exécuter sur les GPU-tainted nœuds que vous avez provisionnés à l'étape 2. L'`release: kube-prometheus-stack`étiquette permet `serviceMonitor` à Prometheus de le découvrir et de le gratter automatiquement.

Vérifiez l'exportateur DaemonSet DCGM :

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

Une fois qu'un nœud GPU est en cours d'exécution, vous devriez voir un pod prêt. Pour valider les métriques DCGM, accédez à **Drilldown > Metrics in** Grafana et recherchez. `DCGM_`

 **Valider les métriques DCGM dans Grafana** 

![Page des métriques Grafana Drilldown filtrée par DCGM_ affichant les métriques du GPU, notamment DCGM_FI_DEV_ECC_SBE_VOL_TOTAL, DCGM_FI_DEV_ENC_UTIL, DCGM_FI_DEV_FB_FREE et DCGM_FI_DEV_FB_USED](http://docs.aws.amazon.com/fr_fr/eks/latest/userguide/images/ml-cluster-setup-cli-dcgm-metrics-validate.png)


Pour consulter le tableau de bord, accédez à **Tableaux de bord > Surveillance du GPU > Tableau de bord NVIDIA DCGM Exporter**.

 **Tableau de bord NVIDIA DCGM Exporter à Grafana** 

![Tableau de bord Grafana NVIDIA DCGM Exporter indiquant l'utilisation du GPU, la température moyenne du GPU, la mémoire tampon du GPU utilisée et la puissance totale du GPU](http://docs.aws.amazon.com/fr_fr/eks/latest/userguide/images/ml-cluster-setup-cli-dcgm-dashboard.png)


## Poids du modèle : seau S3
<a name="cluster-setup-cli-model-bucket"></a>

Créez un compartiment Amazon S3 pour stocker les poids des modèles et configurez une association d'identité EKS Pod afin que les pods de charge de travail puissent y lire et écrire.

Si vous avez ouvert un nouveau terminal, définissez le nom et la région du cluster :

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

### Création du compartiment S3
<a name="_create_the_s3_bucket"></a>

Créez le bucket avec un suffixe aléatoire pour éviter les collisions de noms :

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

Le chiffrement côté serveur (AES256) et le blocage de l'accès public sont activés par défaut pour les compartiments S3 créés après janvier 2023.

### Configurer EKS Pod Identity pour l'accès à S3
<a name="_configure_eks_pod_identity_for_s3_access"></a>

Créez une politique IAM étendue au bucket du modèle `model-storage-sa` ServiceAccount dans l'`default`espace de noms et une association d'identité EKS Pod qui les relie. Les pods de charge de travail définis `serviceAccountName: model-storage-sa` pourront lire et écrire dans le compartiment.

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

Créez la politique 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}"
```

**Note**  
Cette politique accorde `s3:DeleteObject` et `s3:PutObject` pour l'étape de validation. Pour les modules d'inférence de production qui ne lisent que le poids des modèles, supprimez-les `s3:PutObject` et respectez le `s3:DeleteObject` principe du moindre privilège.

Créez l'association EKS Pod Identity. `eksctl`crée le rôle IAM avec la bonne politique de confiance et le ServiceAccount lie à :

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

Vérifiez l'association :

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

La sortie doit inclure l'`model-storage-sa`association dans l'espace de `default` noms.

#### Valider l'accès au S3 depuis un Pod
<a name="cluster-setup-cli-s3-validate"></a>

Exécutez un pod unique avec l'image AWS CLI, en utilisant le `model-storage-sa` ServiceAccount, pour confirmer que EKS Pod Identity est câblé et que l'accès au S3 fonctionne :

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

Attendez que le Pod soit terminé et consultez les journaux :

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

Sortie attendue :

```
=== 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é de l'appelant confirme que le Pod a assumé le `${CLUSTER_NAME}-model-storage-role` rôle via EKS Pod Identity. Les commandes S3 confirment l'accès en lecture et en écriture.

Nettoyez le module de test :

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

## Étapes suivantes
<a name="cluster-setup-cli-next-steps"></a>

Une fois votre cluster prêt, vous pouvez passer au modèle [Load & Serve pour déployer un grand modèle](ml-inference-load-serve-model.md) de langage et interagir avec le point de terminaison d'inférence.

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

**Astuce**  
Si vous comptez poursuivre avec les sections suivantes de ce guide, ignorez le nettoyage complet. Ne le lancez que lorsque vous avez terminé.

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

### Annuler la réservation de capacité
<a name="cluster-setup-cli-cleanup-cancel-reservation"></a>

Si vous avez créé un ODCR, annulez-le d'abord :

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

**Important**  
L'annulation d'une réservation ne met pas fin à l'exécution des instances. Ils se poursuivent aux On-Demand taux standard jusqu'à leur résiliation. Supprimez d'abord le déploiement pour vider le nœud réservé avant de l'annuler.

### Surveillance du nettoyage
<a name="cluster-setup-cli-cleanup-monitoring"></a>

Recherchez l'ARN de la politique 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}"
```

Recherchez l'identifiant de l'espace de travail 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}"
```

Désinstallez la version Helm de l'exportateur DCGM :

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

Désinstallez la version Helm de kube-prometheus-stack :

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

Supprimez l'association EKS Pod Identity pour le compte du service d'ingestion Prometheus :

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

Supprimez l'association EKS Pod Identity pour le compte de service Grafana :

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

Supprimez la politique IAM utilisée par Prometheus et Grafana :

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

Supprimez l'espace de travail AMP :

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

Supprimez l'espace de noms de surveillance :

```
kubectl delete namespace monitoring
```

### Nettoyez le compartiment S3 du poids du modèle
<a name="cluster-setup-cli-cleanup-model-bucket"></a>

Recherchez le nom du bucket du modèle :

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

Recherchez l'ARN de la politique 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}"
```

Supprimez le bucket du modèle S3 et tous ses objets :

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

Supprimez l'association EKS Pod Identity :

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

Supprimez la politique IAM :

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

Supprimez les Kubernetes ServiceAccount :

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

### Supprimer les ressources restantes et le 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
```