

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

# Configurer le cluster Amazon EKS pour les AI/ML charges de travail à l'aide de Terraform
<a name="ml-cluster-setup-tf"></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 à l'aide de Terraform. 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 du stockage Amazon S3 pour les pondérations des modèles.

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

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

![High-level architecture affichant un <shared id=](https://docs.aws.amazon.com/fr_fr/eks/latest/userguide/images/ml-cluster-setup-tf-architecture.png)


Le schéma montre l'architecture AWS de haut niveau pour la configuration de cette section.

## Conditions préalables
<a name="cluster-setup-tf-prerequisites"></a>

**Important**  
Les ressources que vous créez dans ce didacticiel, notamment les clusters EKS, les instances GPU, les équilibreurs de charge des applications et Amazon Managed Service pour Prometheus, sont payantes. Supprimez les ressources lorsque vous avez terminé pour éviter des frais permanents.
+ Terraforme >= 1.15.0. Pour les instructions de configuration, consultez la section [ Installation de Terraform](https://developer.hashicorp.com/terraform/install).
+  `kubectl`>= 1,36. Pour les instructions de configuration, consultez[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).
+  `jq`. Pour les instructions de configuration, voir [ Télécharger jq](https://jqlang.github.io/jq/download/).

Vérifiez les versions de vos outils :

```
terraform --version
aws --version
kubectl version --client
jq --version
```

## Étape 1 : Téléchargez et déployez le code Terraform
<a name="cluster-setup-tf-deploy"></a>

Cette procédure pas à pas utilise le code Terraform dans le référentiel d'[échantillons ](https://github.com/aws-samples/sample-eks-docs) AWS sample-eks-docs. GitHub Clonez le référentiel dans un répertoire de travail :

```
git clone git@github.com:aws-samples/sample-eks-docs.git
cd sample-eks-docs/ai-ml/set-up-cluster
```

Le référentiel a la structure suivante dans le `ai-ml/set-up-cluster/` répertoire dans lequel vous venez de changer :

```
set-up-cluster/
├── scripts/
│   └── cleanup.sh
└── terraform/
    ├── auto-mode/
    └── karpenter/
```

Le référentiel propose deux voies de déploiement. Choisissez-en une seule et utilisez-la tout au long du guide.
+  **Mode automatique EKS ** (`terraform/auto-mode/`) : 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 la formation et l'inférence des charges de travail : agent de surveillance des nœuds EKS, réparation automatique des nœuds, [ snapshotter ](https://github.com/awslabs/soci-snapshotter) SOCI pour une extraction rapide des conteneurs et préparation du GPU pour la configuration 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 ** (`terraform/karpenter/`) — Sur un cluster EKS sans mode automatique EKS, le code Terraform installe et configure les composants requis pour les charges de travail de formation et d'inférence. Cela inclut des modules complémentaires 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 une extraction rapide des conteneurs.

**Important**  
Choisissez le mode automatique EKS ou Karpenter autogéré et utilisez-le tout au long du guide. Le basculement en cours de chaîne nécessite de détruire le cluster et de recommencer à zéro.

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

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


**Grafana est accessible au public via HTTP avec des informations d'identification par défaut**  
La `Ingress` valeur par défaut de Grafana ALB est`0.0.0.0/0`, ce qui expose Grafana `var.my_cidr` à l'Internet public via HTTP simple avec des informations d'identification d'administrateur par défaut. Les scanners automatisés détectent les équilibreurs de charge publics en quelques minutes. Vous ** devez ** restreindre l'accès en saisissant `var.my_cidr` votre propre adresse IP :  

```
export MY_CIDR="$(curl -s https://checkip.amazonaws.com)/32"
terraform apply -var "my_cidr=${MY_CIDR}"
```
Traitez la liste des adresses IP autorisées comme une garantie minimale, et non comme une garantie complète. Modifiez également le mot de passe administrateur Grafana par défaut après la première connexion. Pour une meilleure posture, changez le `alb.ingress.kubernetes.io/scheme` to `internal` (accessible uniquement depuis votre VPC ou un VPN connecté) et ajoutez un certificat TLS.

### Déploiement du cluster
<a name="_deploy_the_cluster"></a>

Accédez au répertoire correspondant au chemin que vous avez choisi, initialisez Terraform et appliquez :

Les deux variantes utilisent par défaut la `us-east-2` région. Pour déployer dans une autre région, ajoutez `-var "region={{region-code}}"` à la `terraform apply` commande de l'étape suivante la AWS région dans laquelle {{region-code}} vous souhaitez effectuer le déploiement.

Le code Terraform utilise toutes les zones de disponibilité disponibles dans la région cible, à l'exception de `use1-az3``usw1-az2`, et `cac1-az3` parce qu'[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)

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

```
cd terraform/auto-mode
terraform init
terraform apply
```

L'exécution de cette commande prend quelques minutes.

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

```
cd terraform/karpenter
terraform init
terraform apply
```

Cette commande prend environ 15 minutes. Il crée un cluster EKS avec un groupe de nœuds géré dédié à l'hébergement des modules complémentaires et du contrôleur Karpenter. Terraform installe Karpenter en activant la file d'attente d'interruptions ponctuelles et en activant les portes `NodeRepair` et `StaticCapacity` fonctionnalités. Il installe également le plug-in de périphérique NVIDIA, le AWS Load Balancer Controller et la pile de surveillance.

------

### Passez en revue les sorties Terraform
<a name="_review_the_terraform_outputs"></a>

Une fois l'application terminée, Terraform imprime les sorties suivantes (les valeurs varient en fonction de votre configuration) :

```
Apply complete! Resources: 74 added, 0 changed, 0 destroyed.

Outputs:

cluster_name         = "ai-eks-docs"
configure_kubectl    = "aws eks update-kubeconfig --region us-east-2 --name ai-eks-docs --alias ai-eks-docs"
configure_model_bucket = "export MODEL_BUCKET=ai-eks-docs-models-20250612abc1"
model_bucket         = "ai-eks-docs-models-20250612abc1"
node_iam_role_name   = "ai-eks-docs-eks-auto-20250612..."
region               = "us-east-2"
```

La `configure_kubectl` sortie est une commande prête à être exécutée qui `kubectl` pointe vers le cluster. La `model_bucket` sortie contient le nom du compartiment S3 pour les pondérations des modèles. La `node_iam_role_name` sortie indique le rôle IAM utilisé par les nœuds.

### Configurer kubectl
<a name="_configure_kubectl"></a>

`kubectl`Pointez sur le nouveau cluster. La `configure_kubectl` sortie est une commande prête à être exécutée :

```
eval "$(terraform output -raw configure_kubectl)"
```

### Vérifiez le cluster
<a name="_verify_the_cluster"></a>

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

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

Sortie attendue :

```
NAMESPACE     NAME                                                       READY   STATUS    RESTARTS   AGE
kube-system   metrics-server-5db89f9ffd-h4mlr                            1/1     Running   0          3m
kube-system   metrics-server-5db89f9ffd-nd748                            1/1     Running   0          3m
monitoring    kube-prometheus-stack-grafana-ff9b5fd57-dh562              3/3     Running   0          3m
monitoring    kube-prometheus-stack-kube-state-metrics-5dcbfdf69b-wd6qn  1/1     Running   0          3m
monitoring    kube-prometheus-stack-operator-548c4f4485-m5wh2            1/1     Running   0          3m
monitoring    kube-prometheus-stack-prometheus-node-exporter-p2z7l       1/1     Running   0          3m
monitoring    prometheus-kube-prometheus-stack-prometheus-0              2/2     Running   0          3m
```

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

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

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

Les résultats attendus incluent Karpenter, CoreDNS, kube-proxy, aws-node (VPC CNI), l'agent EKS Pod Identity, l'agent de surveillance des nœuds EKS et le plug-in de périphérique NVIDIA :

```
NAMESPACE     NAME                                                              READY   STATUS    RESTARTS   AGE
kube-system   aws-node-bzdcz                                                    2/2     Running   0          5m
kube-system   aws-node-vkbhb                                                    2/2     Running   0          5m
kube-system   coredns-7dbb8998cf-9b9wk                                          1/1     Running   0          5m
kube-system   coredns-7dbb8998cf-pwtjd                                          1/1     Running   0          5m
kube-system   ebs-csi-controller-748f54b69-8h7jv                                6/6     Running   0          5m
kube-system   ebs-csi-controller-748f54b69-v2mv8                                6/6     Running   0          5m
kube-system   eks-node-monitoring-agent-5qw4l                                   1/1     Running   0          5m
kube-system   eks-node-monitoring-agent-7lrtm                                   1/1     Running   0          5m
kube-system   eks-pod-identity-agent-ddvlv                                      1/1     Running   0          5m
kube-system   eks-pod-identity-agent-q4g29                                      1/1     Running   0          5m
kube-system   karpenter-898ff78-cndbd                                           1/1     Running   0          5m
kube-system   karpenter-898ff78-hfbhn                                           1/1     Running   0          5m
kube-system   kube-proxy-gcfnh                                                  1/1     Running   0          5m
kube-system   kube-proxy-tktcf                                                  1/1     Running   0          5m
kube-system   metrics-server-5b789db597-cm9qd                                   1/1     Running   0          5m
kube-system   metrics-server-5b789db597-w57b6                                   1/1     Running   0          5m
kube-system   nvidia-device-plugin-node-feature-discovery-gc-66cb7f5dc-xvftc    1/1     Running   0          5m
kube-system   nvidia-device-plugin-node-feature-discovery-master-854d6b5hnqtp   1/1     Running   0          5m
monitoring    kube-prometheus-stack-grafana-6797bcb59f-2zlwg                    3/3     Running   0          5m
monitoring    kube-prometheus-stack-kube-state-metrics-8446bd549c-q6gjc         1/1     Running   0          5m
monitoring    kube-prometheus-stack-operator-5f499b784-vf5xb                    1/1     Running   0          5m
monitoring    kube-prometheus-stack-prometheus-node-exporter-4c6wq              1/1     Running   0          5m
monitoring    kube-prometheus-stack-prometheus-node-exporter-l5t25              1/1     Running   0          5m
monitoring    prometheus-kube-prometheus-stack-prometheus-0                     2/2     Running   0          5m
```

Vérifiez que le plug-in de l'appareil NVIDIA est installé. Aucun module de plug-in d'appareil n'apparaît tant qu'un GPU NodePool portant l'`amiFamily=al2023`étiquette correspondante n'est pas provisionné :

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

------

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

 NodePools Les GPU sont optionnels. Par défaut, `terraform apply` crée le cluster et la pile de surveillance sans capacité GPU et sans facturation GPU. Pour provisionner des nœuds GPU, transmettez la `nodepools` variable avec un nom de stratégie.

Activez la `spot-ondemand` stratégie, qui provisionne des instances G-family GPU d'une génération supérieure à 4, en utilisant la capacité Spot On-Demand comme solution de repli :

```
terraform apply -var 'nodepools={"spot-ondemand"={}}'
```

Cette commande applique les NodeClass modèles NodePool et du `nodepools/spot-ondemand/` répertoire. Les deux chemins utilisent la même NodePool API, mais leurs NodePool références diffèrent. NodeClass 

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

Les NodePool références au gestionnaire `default` NodeClass, qui sélectionne déjà l'AMI accélérée Bottlerocket, les pilotes NVIDIA, le plug-in de périphérique NVIDIA et l'extraction parallèle SOCI. La `spot-ondemand` stratégie n' NodeClass est pas autonome dans cette voie.

Validez les éléments NodePool suivants :

```
kubectl get nodepools,nodeclasses
```

Sortie attendue. Les `gpu-inf` NodePool jointures sont intégrées `general-purpose` et `system` NodePools, toutes les trois, font référence à la gestion `default` NodeClass :

```
NAME                                    NODECLASS   NODES   READY   AGE
nodepool.karpenter.sh/general-purpose   default     0       True    12m
nodepool.karpenter.sh/gpu-inf           default     0       True    20s
nodepool.karpenter.sh/system            default     1       True    12m

NAME                                  ROLE                       READY   AGE
nodeclass.eks.amazonaws.com/default   ai-eks-docs-eks-auto-...   True    12m
```

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

Terraform applique une coutume à `gpu-inf` `EC2NodeClass` côté du. NodePool Le code `EC2NodeClass` épingle l'alias AMI EKS-optimized AL2023, active SOCI via la porte des `FastImagePull` fonctionnalités et permet de déplacer le cache d'images conteneurisées `instanceStorePolicy: RAID0` vers le NVMe local.

Validez le NodePool et EC2NodeClass :

```
kubectl get nodepools,ec2nodeclasses
```

Sortie attendue. La `gpu-inf` paire rejoint le `general-purpose` NodePool et EC2NodeClass que Terraform crée pour les charges de travail non GPU :

```
NAME                                    NODECLASS         NODES   READY   AGE
nodepool.karpenter.sh/general-purpose   general-purpose   1       True    14m
nodepool.karpenter.sh/gpu-inf           gpu-inf           0       True    25s

NAME                                             READY   AGE
ec2nodeclass.karpenter.k8s.aws/general-purpose   True    14m
ec2nodeclass.karpenter.k8s.aws/gpu-inf           True    25s
```

------

Les deux chemins indiquent les `0` nœuds `gpu-inf` jusqu'à ce qu'une charge de travail du GPU soit planifiée. EKS Auto Mode et Karpenter ne lancent des nœuds que lorsque des pods en attente en ont besoin.

## Étape 3 : Testez avec un échantillon de pod
<a name="cluster-setup-tf-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:
  restartPolicy: OnFailure
  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
EOF
```

Vérifiez que le Pod est planifié et terminé correctement :

```
kubectl get pods nvidia-smi
```

Sortie attendue :

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

`STATUS: Completed`Cela signifie que la `nvidia-smi` commande a été exécutée et 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.159.03             Driver Version: 580.159.03     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 L4                      On  |   00000000:31:00.0 Off |                    0 |
| N/A   41C    P8             13W /   72W |       0MiB /  23034MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
```

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 G6 dotée d'un GPU NVIDIA L4 avec 24 Go de mémoire. 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 G6 de GPU NVIDIA L4 (24 Go) et les instances G6e de GPU NVIDIA L40S (48 Go).

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

```
kubectl describe pod nvidia-smi
```

Sortie attendue :

```
Events:
  Type     Reason            Age   From                   Message
  ----     ------            ----  ----                   -------
  Warning  FailedScheduling  75s   default-scheduler      0/2 nodes are available: 2 node(s) had untolerated taint(s).
  Normal   Nominated         74s   eks-auto-mode/compute  Pod should schedule on: nodeclaim/gpu-inf-z6q75
  Normal   Scheduled         35s   default-scheduler      Successfully assigned default/nvidia-smi to i-0eb897a8302551589
  Normal   Pulling           27s   kubelet                spec.containers{nvidia-smi}: Pulling image "public.ecr.aws/amazonlinux/amazonlinux:2023-minimal"
  Normal   Pulled            22s   kubelet                spec.containers{nvidia-smi}: Successfully pulled image "public.ecr.aws/amazonlinux/amazonlinux:2023-minimal" in 5.625s (5.626s including waiting). Image size: 37440620 bytes.
  Normal   Created           22s   kubelet                spec.containers{nvidia-smi}: Container created
  Normal   Started           21s   kubelet                spec.containers{nvidia-smi}: Container started
```

Ces événements indiquent la séquence de planification du Pod : le Pod échoue initialement à planifier car aucun nœud GPU n'existe (`FailedScheduling`), Karpenter en désigne un nouveau NodeClaim (`Nominated`), le planificateur attribue le Pod une fois que le nœud est prêt (`Scheduled`), puis l'image du conteneur est extraite et démarrée. Le mode EKS Auto dispose de l'extraction parallèle SOCI (Seekable OCI) installée et configurée par défaut sur les instances G, P et Trn, et le chemin Karpenter autogéré le configure explicitement via la porte des fonctionnalités. `FastImagePull`

**Note**  
Sur un cluster Karpenter autogéré, l'`Nominated`événement s'affiche `karpenter/compute` au lieu de. `eks-auto-mode/compute`

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é, AZ, et indique si le nœud est prêt :

```
kubectl get nodeclaims
```

Sortie attendue :

```
NAME            TYPE        CAPACITY   ZONE         NODE                  READY   AGE
gpu-inf-z6q75   g6.xlarge   spot       us-east-2a   i-0eb897a8302551589   True    5m
```

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

**Astuce**  
Si aucun nœud n'apparaît, vérifiez s'il y a des erreurs 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 dans votre instance NodePool augmente les chances d'obtenir de la capacité.

**Note**  
Les instances Spot lancées par Karpenter n'apparaissent pas dans la console EC2 Spot Requests. Karpenter utilise l'[`CreateFleet`](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 : Ajoutez de la capacité réservée au NodePool (facultatif)
<a name="cluster-setup-tf-attach-odcr"></a>

Alors que le GPU NodePool de l'étape 2 provisionne le Spot ou On-Demand les instances de manière dynamique, certains cas d'utilisation nécessitent une capacité garantie. Vous pouvez créer une réservation On-Demand de capacité (ODCR) pour vous assurer que la capacité du GPU est disponible en cas de besoin.

Avec Terraform, une seule commande crée l'ODCR, une personnalisation NodeClass qui fait référence à la réservation par tag, et la met à jour NodePool pour l'inclure en `reserved` tant que type de capacité. Terraform étiquette l'ODCR avec `nodepool=reserved-spot-ondemand` et le NodeClass sélectionne par cette balise.

**Avertissement**  
La commande suivante crée un ODCR qui facture immédiatement et continue à facturer jusqu'à ce que vous le détruisiez à l'aide du script de nettoyage `terraform destroy` ou du script de nettoyage, que des nœuds y soient exécutés ou non.

Utilisez les valeurs par défaut (`g6e.4xlarge`, 1 instance, premier cluster de A à Z) :

```
terraform apply -var 'nodepools={"reserved-spot-ondemand"={reservation={}}}'
```

Choisissez le type d'instance, le nombre et l'AZ :

```
terraform apply -var 'nodepools={"reserved-spot-ondemand"={reservation={instance_type="g6e.2xlarge",instance_count=1,az="us-east-2a"}}}'
```

L'`reservation`objet prend en charge les champs suivants :
+  `instance_type`— Type d'instance GPU à réserver. Valeur par défaut : `g6e.4xlarge`.
+  `instance_count`— Le nombre d'instances à réserver. Valeur par défaut : `1`.
+  `az`— La zone de disponibilité pour la réservation. Par défaut : `""` (utilise le premier cluster AZ).

**Important**  
Les `reserved-spot-ondemand` stratégies `spot-ondemand` et s'excluent mutuellement. Vous pouvez en activer au plus un dans la `nodepools` variable. Si vous l'avez déjà utilisée `spot-ondemand` à l'étape 2, la `reserved-spot-ondemand` commande la remplace car les deux gèrent la même chose `gpu-inf` NodePool.

Si vous obtenez une `InsufficientInstanceCapacity` erreur, la réservation ne peut pas être exécutée dans la zone Z spécifiée. Annulez l'opération Terraform (Ctrl\+C), puis relancez-la avec une valeur différente : `az`

```
terraform apply -var 'nodepools={"reserved-spot-ondemand"={reservation={instance_type="g6e.4xlarge",az="us-east-2b"}}}'
```

Après l'application, Terraform met à jour les exigences NodePool pour inclure `reserved``spot`, et `on-demand` dans les exigences de type de capacité. 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.

Sur le chemin du mode automatique EKS, Terraform crée une configuration personnalisée `gpu-inf` NodeClass (car le bundle `default` NodeClass est en lecture seule) qui fait référence à l'ODCR par balise. `capacityReservationSelectorTerms` Sur le chemin autogéré de Karpenter, Terraform réapplique le `gpu-inf` EC2NodeClass with `capacityReservationSelectorTerms` added et met à jour le to include. NodePool `reserved`

Vérifiez que l'ODCR a été créé :

```
aws ec2 describe-capacity-reservations \
  --filters "Name=state,Values=active" "Name=tag:nodepool,Values=reserved-spot-ondemand" \
  --query 'CapacityReservations[0].{Id:CapacityReservationId,State:State,InstanceType:InstanceType,AvailableCount:AvailableInstanceCount}' \
  --output table \
  --region $(terraform output -raw region)
```

Vérifiez les NodeClass références à l'ODCR :

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

```
kubectl get nodeclasses gpu-inf -o yaml | grep 'id: cr-.*'
```

Sortie attendue :

```
        id: cr-xxxxxxxxxxxxxxxxx
```

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

```
kubectl get ec2nodeclasses gpu-inf -o yaml | grep 'id: cr-.*'
```

Sortie attendue :

```
        id: cr-xxxxxxxxxxxxxxxxx
```

------

Vérifiez NodePool qu'il est prêt :

```
kubectl get nodepools gpu-inf
```

Sortie attendue :

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

### Vérifiez que la capacité réservée est utilisée en premier, avec Spot Fallback
<a name="cluster-setup-tf-step4-validate"></a>

Après avoir appliqué les modifications, vérifiez 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 pour 1 instance (1 GPU), donc le premier Pod déclenche Karpenter pour qu'il lance un nœud réservé. Le second Pod ne peut pas tenir sur le nœud réservé et incite Karpenter à lancer un autre nœud depuis Spot ou 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'est exécuté et s'est terminé, ce déploiement permet aux pods de fonctionner (`sleep infinity`) afin qu'ils contiennent le GPU et empêchent la consolidation du 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-55d55ff5b9-dvg52   1/1     Running   0          4m42s   10.0.75.210   i-08741a36089ff2088   <none>           <none>
gpu-overflow-test-55d55ff5b9-hw4m9   1/1     Running   0          4m43s   10.0.82.49    i-0f50cdbacb2017202   <none>           <none>
```

Vérifiez NodeClaims les types de capacité :

```
kubectl get nodeclaims
```

Sortie attendue :

```
NAME            TYPE          CAPACITY   ZONE         NODE                  READY   AGE
gpu-inf-vw99m   g6e.4xlarge   reserved   us-east-2c   i-0f50cdbacb2017202   True    6m
gpu-inf-s65s6   g6.xlarge     spot       us-east-2b   i-08741a36089ff2088   True    5m59s
```

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-tf-monitoring"></a>

Terraform a déjà provisionné la pile de surveillance complète lors `terraform apply` de l'étape 1. La pile comprend un espace de travail Amazon Managed Service for Prometheus (AMP), des politiques IAM et des associations d'identité de pod EKS pour l'écriture à distance de Prometheus et l'accès aux requêtes Grafana, le graphique Helm de la pile kube-prometheus (Prometheus, Grafana, kube-state-metrics, node-exporter) et l'exportateur NVIDIA DCGM pour les métriques GPU.

Cette section couvre la vérification des composants de surveillance déployés.

### Vérifiez les modules de surveillance
<a name="_verify_monitoring_pods"></a>

Attendez que tous les modules de surveillance soient prêts :

```
kubectl wait --for=condition=Ready pod --all -n monitoring --timeout=300s
kubectl get pods -n monitoring
```

Sortie attendue :

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

### Accédez à Grafana
<a name="cluster-setup-tf-grafana"></a>

Grafana est exposé via un équilibreur de charge d' AWS application (ALB) connecté à Internet, limité au CIDR que vous avez défini. `var.my_cidr` Imprimez l'URL de l'équilibreur de charge (attendez une minute ou deux pour que l'ALB soit provisionné) :

```
echo "http://$(kubectl get ingress kube-prometheus-stack-grafana -n monitoring -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')"
```

Ouvrez l'URL 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
```

### Vérifiez le pipeline de métriques
<a name="_verify_the_metrics_pipeline"></a>

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

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

    **Validez la source de données AMP dans Grafana **   
![La page Grafana Connections s' Amazon-Managed-Prometheus affiche comme source de données par défaut](https://docs.aws.amazon.com/fr_fr/eks/latest/userguide/images/ml-cluster-setup-cli-prometheus-ds-validate.png)

1. Accédez à ** Drilldown > Metrics ** 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](https://docs.aws.amazon.com/fr_fr/eks/latest/userguide/images/ml-cluster-setup-cli-prometheus-metrics-validate.png)

Si `up` les résultats s'affichent, le pipeline (cluster → Prometheus → AMP → Grafana) fonctionne.

### Valider les métriques du GPU DCGM
<a name="_validate_dcgm_gpu_metrics"></a>

L'exportateur DCGM DaemonSet s'exécute sur des nœuds GPU et indique l'utilisation du GPU, la mémoire, la température, la consommation électrique, la bande passante NVLink et les mesures d'activité des tenseurs.

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 (à partir de l'étape 2 ou de l'étape 4), vous devriez voir apparaître un ou plusieurs pods prêts. Pour valider les métriques DCGM, accédez à ** Drilldown > Metrics ** in Grafana et recherchez. `DCGM_`

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

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


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

 **Tableau de bord de l'exportateur NVIDIA DCGM dans Grafana ** 

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


## Le modèle pèse le godet S3
<a name="cluster-setup-tf-model-bucket"></a>

Terraform a déjà créé un compartiment Amazon S3 pour stocker les poids des modèles, un `model-storage-sa` ServiceAccount dans l'`default`espace de noms, une politique IAM limitée au compartiment et une association EKS Pod Identity qui les relie. Les modules de charge de travail qui définissent `serviceAccountName: model-storage-sa` peuvent lire et écrire dans le compartiment.

### Vérifiez le compartiment
<a name="_verify_the_bucket"></a>

Récupérez le nom du compartiment à partir des sorties Terraform :

```
MODEL_BUCKET=$(terraform output -raw model_bucket)
echo ${MODEL_BUCKET}
```

Vérifiez que le compartiment existe :

```
aws s3api head-bucket --bucket ${MODEL_BUCKET}
```

Sortie attendue :

```
{
    "BucketArn": "arn:aws:s3:::ai-eks-docs-models-20250612abc1",
    "BucketRegion": "us-east-2",
    "AccessPointAlias": false
}
```

#### Valider l'accès S3 depuis un Pod
<a name="cluster-setup-tf-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 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 vérifiez 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-models-.../eks-ai-eks-docs-..."
}

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

=== S3 List Test ===
2026-07-15 12:00:00         19 test.txt

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

L'identité de l'appelant confirme que le Pod a assumé le rôle de stockage du modè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-tf-next-steps"></a>

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

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

**Astuce**  
Si vous prévoyez de passer aux sections suivantes de ce guide, ignorez le nettoyage complet. Ne le lancez que lorsque vous avez terminé.

Supprimez les charges de travail de test afin qu'aucun pod ne contienne de nœuds GPU :

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

### Annuler la réservation de capacité sans détruire le cluster
<a name="cluster-setup-tf-cleanup-cancel-reservation"></a>

Si vous souhaitez uniquement libérer l'ODCR et revenir à Spot et à la On-Demand capacité, replacez la `nodepools` variable sur la `spot-ondemand` stratégie :

```
terraform apply -var 'nodepools={"spot-ondemand"={}}'
```

Cela réduit les exigences `reserved` de NodePool type de capacité et détruit l'ODCR, laissant le cluster, la pile de surveillance et le compartiment S3 en place.

**Important**  
L'annulation d'une réservation ne met pas fin aux instances qui s'exécutent déjà sur celle-ci. Ces instances continuent de fonctionner à On-Demand des taux standard jusqu'à leur fermeture. Supprimez d'abord les charges de travail du GPU, comme indiqué ci-dessus, afin que le nœud réservé soit vidé avant que la réservation ne soit publiée.

### Détruisez le cluster et toutes les Terraform-managed ressources
<a name="cluster-setup-tf-cleanup-destroy"></a>

Videz les Karpenter-managed nœuds avant de les détruire, afin qu'aucun cycle de vie des nœuds en vol ne bloque la destruction. Supprimez tous PodDisruptionBudgets ceux qui empêcheraient un drainage, puis supprimez les éléments NodeClaims suivants :

```
kubectl delete pdb -A --all --ignore-not-found
kubectl delete nodeclaim --all --wait=true --timeout=900s
```

Détruisez ensuite tout ce que Terraform a créé, y compris le cluster EKS, le VPC, la pile de surveillance, le NodePools et NodeClasses, le compartiment du modèle S3 et tout ODCR :

```
terraform destroy
```

**Avertissement**  
Le compartiment S3 est créé avec `force_destroy = true` les poids du modèle. Il `terraform destroy` supprime donc le compartiment ainsi que tous les poids des modèles que vous y avez chargés. Copiez d'abord tout ce que vous souhaitez conserver dans un autre emplacement.

**Note**  
Le référentiel fournit également un `scripts/cleanup.sh` assistant qui exécute les étapes de vidange et de destruction ci-dessus, puis balaie tous les volumes EBS orphelins étiquetés avec le nom du cluster. Exécutez-le depuis le `terraform/<mode>/` répertoire à partir duquel vous avez postulé et passez `--auto-approve` pour ignorer l'invite de confirmation de Terraform.

### Vérifiez que la réservation est terminée
<a name="cluster-setup-tf-cleanup-verify"></a>

Vérifiez qu'il ne reste aucune réservation de capacité active pour le cluster :

```
aws ec2 describe-capacity-reservations \
  --filters "Name=state,Values=active" "Name=tag:nodepool,Values=reserved-spot-ondemand" \
  --query 'CapacityReservations[].CapacityReservationId' \
  --output text
```

Un résultat vide signifie qu'aucune réservation n'est active et qu'aucun autre frais ne s'applique.