View a markdown version of this page

Configurer le cluster Amazon EKS pour les AI/ML charges de travail à l'aide des CLI - Amazon EKS

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 des CLI

Astuce

Inscrivez-vous 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 du stockage Amazon S3 pour les pondérations des modèles.

Consultez la documentation relative au mode automatique EKS et à Karpenter 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 montrant le cluster EKS avec Karpenter NodeClass et NodePool, la pile de surveillance Grafana et Prometheus écrivant dans Amazon Managed Service for Prometheus, un compartiment Amazon S3 pour les pondérations des modèles et les étapes numérotées du flux de travail

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 terminez la configuration dans les étapes ci-dessous.

Conditions préalables

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.

  • kubectl>= 1,36. Pour les instructions de configuration, consultezConfigurer kubectl et eksctl .

  • AWS CLI >= 2,27. Pour les instructions de configuration, reportez-vous à la section Installation.

  • Casque >= 3,14. Pour les instructions de configuration, voir Setup Helm.

  • jq. Pour les instructions de configuration, voir Télécharger jq.

  • eksctl>= 0,227,0. Pour les instructions de configuration, consultez la section 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 passer à la dernière version.

Définir les variables d'environnement

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 peuvent cibler le mauvais cluster EKS.

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

L'utilisation de tous les AZ disponibles améliore la tolérance aux pannes et augmente les chances d'obtenir de 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-az3usw1-az2, et cac1-az3 sont exclues car Amazon EKS ne prend pas en charge le placement de plans de contrôle dans ces zones. La création d'un cluster avec des sous-réseaux dans l'une de ces zones entraîne unUnsupportedAvailabilityZoneException.

Sortie attendue :

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

Les AZ de la sortie varient d'une région à l'autre. Cet exemple montre les AZ disponibles pour us-east-2 la région.

Création d'un cluster et d'un GPU NodePool

Cette section fournit deux chemins pour créer votre cluster et vos GPU-enabled nœuds EKS, comme indiqué dans le schéma suivant. Choisissez une seule option dans tout le guide.

  • Mode automatique EKS  : outre les principaux modules complémentaires de mise en réseau, de stockage et d'équilibrage de charge, 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 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 — Sur un cluster EKS sans mode automatique EKS, vous êtes responsable de l'installation et de la configuration des 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.

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

Dans chacune des étapes suivantes, choisissez un chemin (EKS Auto Mode, Karpenter) et suivez-le tout au long. Une fois les étapes correspondant au chemin que vous avez choisi, vous disposerez d'un cluster EKS avec un GPU NodePool prêt à planifier les charges de travail du GPU.

Étape 1 : créer un cluster

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 permet de provisionner un cluster EKS prêt pour les charges de travail GPU.

Avec Karpenter autogéré, la eksctl create cluster commande fournit les principaux modules complémentaires réseau, puis des étapes supplémentaires sont nécessaires pour activer la réparation automatique des nœuds via un portail de fonctionnalités 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 EKS Auto Mode

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

L'exécution de cette commande prend quelques minutes. Une fois terminé, met eksctl automatiquement à jour votre fichier kubeconfig 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 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

Créer la valeur par défaut StorageClass

Les charges de travail GPU ont souvent besoin d'un stockage permanent, par exemple pour mettre en cache les poids des modèles afin que Kubernetes ne les télécharge pas à chaque redémarrage du pod. Le mode automatique EKS inclut une fonctionnalité de stockage par blocs intégrée, vous n'installez donc pas le pilote Amazon EBS CSI. Créez un StorageClass qui fait référence au provisionneur du mode automatique :

cat << EOF | kubectl apply -f - apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: gp3 annotations: storageclass.kubernetes.io/is-default-class: "true" provisioner: ebs.csi.eks.amazonaws.com volumeBindingMode: WaitForFirstConsumer parameters: type: gp3 encrypted: "true" EOF

Cette commande crée un gp3 StorageClass et le marque comme valeur par défaut du cluster avec l'storageclass.kubernetes.io/is-default-classannotation. Toute PersistentVolumeClaim personne qui omet l'storageClassNameutilise. StorageClass Le volumeBindingMode: WaitForFirstConsumer paramètre retarde la création du volume jusqu'à ce que Kubernetes planifie un pod, de sorte que le volume EBS atterrisse dans la même zone de disponibilité que le pod.

Self-managed Karpenter

Authentifier Helm auprès de l'ECR public

eksctlextrait 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é dansus-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 sur. GitHub

export KARPENTER_VERSION=1.14.0
Exemple Configuration du cluster YAML
cat << EOF > /tmp/cluster-karpenter.yaml apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: ${CLUSTER_NAME} region: ${AWS_REGION} version: "1.36" 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 instanceTypes: ["m6i.2xlarge", "m5.2xlarge", "m6a.2xlarge", "m5a.2xlarge", "m7i.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 - name: aws-ebs-csi-driver EOF

Le groupe de nœuds system gérés répertorie plusieurs types d'instances de même taille (8 processeurs virtuels, 32 Go) au lieu d'un seul type. Si un type est temporairement indisponible dans une zone de disponibilité, le groupe Auto Scaling du groupe de nœuds revient à un autre type, ce qui évite les échecs de InsufficientInstanceCapacity lancement. Pour un groupe de nœuds On-Demand géré, tous les types d'instances répertoriés doivent disposer du même processeur virtuel et de la même mémoire afin que la taille des nœuds soit uniforme.

Créez le cluster à l'aide du fichier de configuration :

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é dédié à l'hébergement des modules complémentaires et du contrôleur Karpenter. Karpenter est installé avec la file d'attente d'interruptions ponctuelles activée afin qu'il puisse gérer les recommandations d'interruption ponctuelle et de rééquilibrage. 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 reçoit également l'agent EKS Pod Identity, l'agent de surveillance des nœuds EKS et le pilote Amazon EBS CSI installés 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 des nœuds AcceleratedHardwareReady KernelReadyNetworkingReady, telles que, et, que 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 EKS Pod Identity 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 les portes fonctionnelles de Karpenter

Le mode EKS Auto permet la réparation automatique des nœuds et la capacité statique par défaut. Sur Karpenter autogéré, vous devez activer explicitement la porte des NodeRepair fonctionnalités et la StaticCapacity porte pour la statique NodePools, ce qui permet de maintenir un nombre de nœuds fixe au spec.replicas lieu de procéder à une mise à l'échelle en réponse aux pods en attente. Les deux portes sont en mode Alpha et sont désactivées par défaut dans Karpenter. La commande suivante corrige le déploiement de Karpenter pour activer les deux portes. La mise à jour de l'environnement de déploiement déclenche le déploiement des modules Karpenter :

kubectl set env deployment/karpenter -n karpenter \ FEATURE_GATES=NodeRepair=true,StaticCapacity=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 de périphérique NVIDIA

L'AMI EKS-optimized AL2023 n'inclut pas le plug-in de périphérique NVIDIA (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 la présence de Mellanox OFED (InfiniBand), qui n'utilise pas AWS

  • nodeSelector.amiFamily: al2023: s'étend DaemonSet aux nœuds AL2023 uniquement (Bottlerocket a déjà intégré le plugin)

  • gfd.enabled: true: active les étiquettes de découverte des fonctionnalités du GPU (nvidia.com/gpu.productnvidia.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 pod de plug-in d'appareil jusqu'à ce qu'un GPU NodePool portant l'étiquette correspondante soit 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 2m5s

Ensuite, créez un objectif général. NodePool Le groupe de nœuds system géré exécute les modules complémentaires et les contrôleurs. Ajoutez un Karpenter polyvalent afin que les charges de travail non NodePool liées au GPU puissent évoluer à la demande sans avoir à se poser sur les nœuds. system Le GPU NodePool est créé ultérieurement à l'étape 2.

General-purpose EC2NodeClass et NodePool YAML

cat << EOF | kubectl apply -f - apiVersion: karpenter.k8s.aws/v1 kind: EC2NodeClass metadata: name: general-purpose 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} --- apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: general-purpose spec: template: spec: nodeClassRef: group: karpenter.k8s.aws kind: EC2NodeClass name: general-purpose requirements: - key: karpenter.sh/capacity-type operator: In values: ["on-demand"] - key: karpenter.k8s.aws/instance-category operator: In values: ["c", "m", "r"] - key: karpenter.k8s.aws/instance-generation operator: Gt values: ["4"] - key: kubernetes.io/arch operator: In values: ["amd64"] limits: cpu: 1000 memory: 1000Gi EOF

Cela n' NodePool a aucun inconvénient, donc tout Pod qui ne tolère pas l'altération du GPU peut le programmer.

Créer la valeur par défaut StorageClass

Les charges de travail GPU ont souvent besoin d'un stockage permanent, par exemple pour mettre en cache les poids des modèles afin que Kubernetes ne les télécharge pas à chaque redémarrage du pod. Le pilote Amazon EBS CSI est déjà installé par addons: bloc dans la configuration du cluster au début de cette étape. Il vous suffit donc de créer : StorageClass

cat << EOF | kubectl apply -f - apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: gp3 annotations: storageclass.kubernetes.io/is-default-class: "true" provisioner: ebs.csi.aws.com volumeBindingMode: WaitForFirstConsumer parameters: type: gp3 encrypted: "true" EOF

Cette commande crée un gp3 StorageClass et le marque comme valeur par défaut du cluster avec l'storageclass.kubernetes.io/is-default-classannotation. Toute PersistentVolumeClaim personne qui omet l'storageClassNameutilise. StorageClass Le volumeBindingMode: WaitForFirstConsumer paramètre retarde la création du volume jusqu'à ce que Kubernetes planifie un pod, de sorte que le volume EBS atterrisse dans la même zone de disponibilité que le pod.

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 pour les nœuds provisionnés par. NodePools La réparation automatique des nœuds en mode EKS Auto et Karpenter est une méthode de perturbation puissante qui contourne PodDisruptionBudgets, l'karpenter.sh/do-not-disruptannotation 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 False et 30 minutes pour les autres conditions de réparation.

Configurer l'équilibrage de charge

Les étapes suivantes de ce guide présentent Grafana (et, dans la procédure d'inférence, un point de terminaison du modèle) via un équilibreur de charge d' AWS application (ALB). Configurez dès maintenant les prérequis d'équilibrage de charge afin que ces sections puissent créer une configuration Ingress sans autre configuration.

L'ALB est placé dans vos sous-réseaux VPC en fonction AWS des balises de ressources. Les sous-réseaux publics utilisés pour les équilibreurs de charge connectés à Internet doivent être étiquetés kubernetes.io/role/elb =1, et les sous-réseaux privés utilisés pour les équilibreurs de charge internes doivent être étiquetés =. kubernetes.io/role/internal-elb 1 Comme vous avez créé ce cluster aveceksctl, ces balises existent déjà sur les sous-réseaux eksctl créés. Si vous apportez votre propre VPC ou des sous-réseaux importés, étiquetez-les manuellement. Pour en savoir plus, consultez Baliser les sous-réseaux pour le mode automatique EKS.

Création de l'équilibreur de charge IngressClass

Le reste de la configuration varie selon le chemin. Le mode automatique EKS comprend un contrôleur ALB intégré, ce qui vous permet de créer IngressClass vous-même un. Self-managed Karpenter nécessite l'installation du AWS Load Balancer Controller avec Helm, et le diagramme Helm le crée IngressClass pour vous.

EKS Auto Mode

Le mode automatique EKS comprend un contrôleur ALB intégré, vous n'installez donc aucun composant supplémentaire. Créez un IngressClass nom alb qui pointe vers le contrôleur intégré. Chacune de Ingress vos créations ultérieures fait référence à cette classe par son nom et définit son propre schéma et d'autres options par le biais d'annotations.

cat << EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: IngressClass metadata: name: alb spec: controller: eks.amazonaws.com/alb EOF
Self-managed Karpenter

Le AWS Load Balancer Controller n'est pas un EKS-managed module complémentaire, il ne peut donc pas entrer dans le addons: bloc de configuration du eksctl cluster comme le fait le pilote EBS CSI. Installez-le avec Helm.

Téléchargez la politique IAM

Le contrôleur a besoin d'autorisations IAM pour créer et gérer des ALB. Téléchargez la politique IAM officielle au format JSON :

curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/install/iam_policy.json

Créez la politique IAM :

aws iam create-policy \ --policy-name AWSLoadBalancerControllerIAMPolicy \ --policy-document file://iam_policy.json

Création de l'association Pod Identity

Le cluster installe déjà le eks-pod-identity-agent module complémentaire à l'étape 1. EKS Pod Identity est donc disponible. Créez une association Pod Identity qui lie la politique IAM au compte de service du contrôleur :

eksctl create podidentityassociation \ --cluster ${CLUSTER_NAME} \ --region ${AWS_REGION} \ --namespace kube-system \ --service-account-name aws-load-balancer-controller \ --permission-policy-arns arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):policy/AWSLoadBalancerControllerIAMPolicy

Installation avec Helm

Ajoutez le référentiel Helm des cartes EKS :

helm repo add eks https://aws.github.io/eks-charts helm repo update

Recherchez l'ID VPC de votre cluster. Les valeurs Helm en ont besoin pour que le contrôleur puisse découvrir les sous-réseaux :

VPC_ID=$(aws eks describe-cluster \ --name ${CLUSTER_NAME} \ --region ${AWS_REGION} \ --query 'cluster.resourcesVpcConfig.vpcId' \ --output text)

Installez le contrôleur. La tolérance nodeSelector et place le contrôleur dans le groupe de nœuds system géré, à côté de l'infrastructure critique du cluster, au lieu de concurrencer le GPU ou les nœuds Karpenter-launched polyvalents en termes de capacité :

helm install aws-load-balancer-controller eks/aws-load-balancer-controller \ --namespace kube-system \ --version 3.4.2 \ --set clusterName=${CLUSTER_NAME} \ --set region=${AWS_REGION} \ --set vpcId=${VPC_ID} \ --set serviceAccount.create=true \ --set serviceAccount.name=aws-load-balancer-controller \ --set "nodeSelector.node-role=system" \ --set "tolerations[0].key=CriticalAddonsOnly" \ --set "tolerations[0].operator=Exists"

Vérifiez que le contrôleur fonctionne. Il doit signaler deux répliques disponibles :

kubectl get deployment aws-load-balancer-controller -n kube-system

Vérifiez le IngressClass

Le graphique Helm crée un IngressClass nom dans le alb cadre de l'installation du contrôleur, pointant vers le contrôleur ingress.k8s.aws/alb autogéré. Il n'est pas nécessaire de le créer manuellement. Confirmez son existence :

kubectl get ingressclass alb

Sortie attendue :

NAME CONTROLLER PARAMETERS AGE alb ingress.k8s.aws/alb <none> 22s

Les deux voies ont désormais un albIngressClass. Les sections Grafana et d'inférence font référence ingressClassName: alb et définissent le schéma ALB, la liste d'autorisation des adresses IP source et d'autres comportements par le biais d'annotations par annotation. Ingress

Étape 2 : Création d'un GPU dynamique NodePool

Définissez une instance NodePool qui provisionne dynamiquement les instances G-family GPU dont la génération est supérieure à 4 et inférieure à 7, en utilisant la capacité Spot On-Demand comme solution de repli. Les chemins EKS Auto Mode et Karpenter utilisent tous deux la même NodePool API, la seule différence étant la direction vers NodeClass laquelle il pointe. En mode EKS Auto, le bundle sélectionne default NodeClass déjà la bonne AMI et configure l'extraction parallèle SOCI. NodePool C'est donc le seul objet que vous créez. Dans Karpenter autogéré, vous avez également besoin d'une personnalisation EC2NodeClass qui épingle l'AMI et règle SOCI.

Important

Le type d'instance G7 EC2 nécessite la version 595 ou ultérieure du pilote NVIDIA. Les AMI EKS-optimized accélérées incluent actuellement la version 580 du pilote NVIDIA, qui ne prend pas en charge les instances G7. NodePool Dans cette étape, la génération d'instances est limitée à moins de 7 afin que Karpenter ne sélectionne pas d'instance G7. Pour utiliser les instances G7 avec Amazon EKS, vous devez créer une AMI personnalisée avec la version 595 du pilote NVIDIA. Pour de plus amples informations, veuillez consulter Utiliser des AMI EKS-optimized accélérées pour les instances GPU.

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 la fonction SOCI parallel pull. 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: eks.amazonaws.com/instance-generation operator: Lt values: ["7"] - key: kubernetes.io/arch operator: In values: ["amd64"] limits: cpu: 1000 memory: 5000Gi EOF

Cela NodePool permet de G-family provisionner des instances GPU dont la génération est supérieure à 4 et inférieure à 7 (G5, G6e, etc.). Le mode EKS Auto choisit un type d'instance dans le cadre de ces contraintes.

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 AMI EKS-optimized NVIDIA AL2023, active SOCI via le FastImagePull Feature Gate et configure instanceStorePolicy: RAID0 pour déplacer le cache d'images conteneurées vers le NVMe local. Ensuite, vous créez le NodePool qui y fait référence.

Créez le EC2NodeClass

Exemple
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: | apiVersion: node.eks.aws/v1alpha1 kind: NodeConfig spec: featureGates: FastImagePull: true EOF

instanceStorePolicy: RAID0assemble les disques NVMe locaux en une RAID-0 matrice. L'alias al2023@latest AMI est résolu en AMI EKS-optimized 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é.

Le FastImagePull Feature Gate active le mode d'extraction parallèle de SOCI Snapshotter, 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.

Pour plus d'options de réglage SOCI (téléchargements simultanés par image, taille des morceaux, etc.), consultez le plan SOCI de Karpenter.

Validez les éléments EC2NodeClass suivants :

kubectl get ec2nodeclass gpu-inf

Résultat attendu :READY True. SiFalse, exécutez kubectl describe ec2nodeclass gpu-inf et vérifiez les conditions relatives aux balises de sous-réseau ou de groupe de sécurité manquantes.

Créez le GPU NodePool

Exemple
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: karpenter.k8s.aws/instance-generation operator: Lt values: ["7"] - key: kubernetes.io/arch operator: In values: ["amd64"] limits: cpu: 1000 memory: 5000Gi EOF

L'amiFamily: al2023étiquette sur le modèle de nœud est celle que le plug-in de périphérique NVIDIA DaemonSet utilise pour sélectionner ces nœuds. Karpenter choisit un type d'instance dans le cadre de ces contraintes. Cette nvidia.com/gpu:NoSchedule faille garantit que seuls les GPU-eligible Pods sont planifiés sur ces nœuds.

Validez que le NodePool produit 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 s'affiche à la place de. gpu-inf default

Étape 3 : Testez avec un échantillon de pod

Testez la NodePool configuration de votre GPU à l'aide d'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é correctement.

kubectl get pods

Sortie attendue :

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

Le statut : Terminé signifie que la commande nvidia-smi 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:35:00.0 Off | 0 | | N/A 42C P8 16W / 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. La température actuelle du GPU est de 42 °C et P8 correspond à un état de veille à faible consommation d'énergie, ce qui est normal car aucune charge de travail n'utilise le GPU. Le 16 W/72 W indique la consommation actuelle par rapport à la capacité de puissance maximale, et 0 MiB/23034 MiB indique la mémoire GPU actuelle utilisée par rapport au total disponible. Comme le Pod vient de lancer nvidia-smi et de sortir, aucune charge de travail n'utilise le GPU, donc la mémoire est à 0 et l'alimentation est inactive. La version du pilote GPU NVIDIA (580.159.03) 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 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 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 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 (Nominé), 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 automatique EKS est livré avec la fonction de traction parallèle SOCI (Seekable OCI) installée et configurée prête à l'emploi 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é, 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-vxcnj   g6.4xlarge   spot       us-east-2c   i-0fb17a09bc4203164   True    51s

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

L'FailedCreatePodSandBoxavertissement entrant kubectl describe pod nvidia-smi est transitoire et attendu. Le VPC CNI s'initialise de manière asynchrone après la jonction du nœud, et le kubelet réessaie automatiquement. Si le Pod reste alluméContainerCreating, vérifiez les événements du nœud aveckubectl describe node <node-name>.

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'apparaîtront pas dans la console EC2 Spot Requests. Karpenter utilise l'CreateFleetAPI 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)

Pour utiliser d'abord la capacité réservée avec Spot/On-Demand repli, créez une réservation de On-Demand capacité (ODCR) et joignez-la à la vôtre NodeClass, puis mettez à jour la dynamique à NodePool partir de l'étape 2 pour autoriser reserved également la capacité. L'appel à 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 avecaws 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 vous obtenez un InsufficientInstanceCapacity message d'erreur, passez CR_AZ à une autre AZ et réessayez.

Recherchez l'ID de réservation de capacité et stockez-le dans une variable shell en suivant 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 EKS Auto, l'offre groupée default NodeClass est en lecture seule. Créez donc une personnalisation NodeClass qui fait référence à la réservation, puis mettez-la à jour NodePool pour pointer vers la liste NodeClass et ajoutez de la reserved capacité à la liste. capacity-type

Exemple NodeClass YAML personnalisé
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 dans des sous-réseaux privés uniquement.

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

Exemple NodePool YAML mis à jour
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: eks.amazonaws.com/instance-generation operator: Lt values: ["7"] - key: kubernetes.io/arch operator: In values: ["amd64"] limits: cpu: 1000 memory: 5000Gi EOF
Self-managed Karpenter

Pour Karpenter autogéré, appliquez de nouveau la valeur EC2NodeClass que vous avez créée à l'étape 2 et que vous avez ajoutée. capacityReservationSelectorTerms Le nom et la forme du champ correspondent au mode automatique EKS NodeClass indiqué dans l'autre onglet.

Exemple EC2NodeClass YAML mis à jour
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: | apiVersion: node.eks.aws/v1alpha1 kind: NodeConfig spec: featureGates: FastImagePull: true EOF

Le seul changement par rapport à l'étape 2 est 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é :

Exemple NodePool YAML mis à jour
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: karpenter.k8s.aws/instance-generation operator: Lt values: ["7"] - 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.

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 une instance, 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 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 sont en cours d'exécution, chacun sur un nœud différent.

Vérifiez NodeClaims 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   g6e.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

Installez une pile de surveillance qui collecte les métriques des clusters, des nœuds et des GPU dans Amazon Managed Service for Prometheus (AMP), et visualisez-les avec Grafana. Le graphique Helm kube-prometheus-stack déploie Prometheus pour scraper 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 mesures (utilisation, mémoire, température, puissance, NVLink, activité du tenseur).

Prometheus, Grafana et l'opérateur atterrissent par défaut sur des nœuds non GPU, car les nœuds GPU sont porteurs de cette altération. nvidia.com/gpu:NoSchedule Node-exporter et l'exportateur DCGM fonctionnent tous deux sur des nœuds GPU afin que nous puissions extraire les métriques de l'hôte et du GPU à l'échelle de la flotte.

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

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'ID 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 EKS Pod Identity

Créez une politique IAM qui permet à Prometheus d'écrire des métriques à distance 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é de pod EKS 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 à la fois amp-iamproxy-ingest-service-account et grafana-sa dans l'monitoringespace de noms.

Installer kube-prometheus-stack

Ajoutez le repo 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 GPU, de sorte qu'ils nvidia.com/gpu:NoSchedule atterrissent par défaut sur le système ou le pool à usage général. Node-exporter utilise une tolérance de 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 de la flotte.

Le fichier de valeurs configure également un Grafana Ingress afin que le graphique fournisse un ALB connecté à Internet pour l'accès au navigateur, à l'aide de celui alb IngressClass que vous avez créé dans Configurer l'équilibrage de charge. L'alb.ingress.kubernetes.io/inbound-cidrsannotation limite l'équilibreur de charge à votre propre adresse IP. Configurez-le donc avant de l'installer.

Grafana est accessible au public via HTTP avec des informations d'identification par défaut

Grafana inclut des informations d'identification d'administrateur par défaut et fournit un accès administratif complet à vos données de surveillance. Un équilibreur de charge orienté Internet place cette interface sur l'Internet public via HTTP en texte brut. Les scanners automatisés détectent les équilibreurs de charge publics en quelques minutes. Vous devez restreindre l'accès à l'aide de l'alb.ingress.kubernetes.io/inbound-cidrsannotation et considérer la liste d'autorisation des adresses IP sources comme une garantie minimale et non comme une garantie complète. Modifiez également le mot de passe administrateur par défaut de Grafana. Pour une meilleure posture, utilisez un schéma interne (accessible uniquement depuis votre VPC ou un VPN connecté) en configurant le schéma surinternal, et ajoutez un certificat TLS.

Trouvez votre adresse IP publique et stockez-la en tant que /32 CIDR. Le fichier de valeurs lit ceci à partir de la variable d'MY_CIDRenvironnement :

export MY_CIDR="$(curl -s https://checkip.amazonaws.com)/32" echo $MY_CIDR

Le résultat ressemble à cela203.0.113.4/32. Si votre réseau attribue des adresses de manière dynamique, votre adresse IP peut changer au fil du temps. Pensez donc à définir une plage plus large, telle que203.0.113.0/24.

Créez le fichier de valeurs :

Exemple fichier de valeurs kube-prometheus-stack
cat << EOF > /tmp/kube-prometheus-values.yaml alertmanager: enabled: false prometheus-adapter: enabled: false prometheus: serviceAccount: create: false name: amp-iamproxy-ingest-service-account prometheusSpec: serviceAccountName: amp-iamproxy-ingest-service-account enableRemoteWriteReceiver: true retention: 2h scrapeInterval: 30s evaluationInterval: 30s podMonitorSelectorNilUsesHelmValues: false serviceMonitorSelectorNilUsesHelmValues: false resources: requests: cpu: 500m memory: 1Gi limits: memory: 8Gi remoteWrite: - url: "${AMP_ENDPOINT}api/v1/remote_write" sigv4: region: "${AWS_REGION}" queueConfig: maxSamplesPerSend: 1000 maxShards: 200 capacity: 2500 prometheusOperator: resources: requests: cpu: 100m memory: 128Mi limits: memory: 256Mi kube-state-metrics: resources: requests: cpu: 50m memory: 128Mi limits: memory: 512Mi grafana: enabled: true ingress: enabled: true ingressClassName: alb labels: guide: ai-eks-docs annotations: alb.ingress.kubernetes.io/scheme: internet-facing alb.ingress.kubernetes.io/target-type: ip alb.ingress.kubernetes.io/inbound-cidrs: ${MY_CIDR} alb.ingress.kubernetes.io/load-balancer-name: grafana-ai-eks-docs alb.ingress.kubernetes.io/healthcheck-path: /api/health serviceAccount: create: false name: grafana-sa resources: requests: cpu: 100m memory: 256Mi limits: memory: 1Gi 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 vllm-load-analysis: gnetId: 25494 revision: 1 datasource: - name: DS_PROMETHEUS value: Amazon-Managed-Prometheus prometheus-node-exporter: resources: requests: cpu: 50m memory: 64Mi limits: memory: 128Mi tolerations: - operator: Exists EOF

Validez que les variables ont été correctement renseignées :

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

L'URL complète du point de terminaison AMP (en commençant parhttps://aps-workspaces…​) et votre région devraient s'afficher. Si l'une des deux 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) : extrait 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 (DaemonSet, un 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

Alertmanager est désactivé dans cette configuration.

Accédez à Grafana

Vous accédez à Grafana via un équilibreur de charge d' AWS application (ALB) connecté à Internet. Vous ne le créez pas ici. Le graphique kube-prometheus-stack le provisionne à partir de la grafana.ingress configuration du fichier de valeurs, à l'aide de la commande de configuration de l'albIngressClasséquilibrage de charge. Configurer l'équilibrage de charge Le graphique Grafana Helm dispose d'un Ingress support intégré, aucun manifeste distinct n'est donc nécessaire. L'ALB est nommégrafana-ai-eks-docs, porte l'étiquette guide: ai-eks-docs et est limité à l'adresse IP que vous avez définie MY_CIDR au moment de l'installation.

Un parcours de contrôle de santé est requis pour le groupe cible Grafana ALB

L'alb.ingress.kubernetes.io/healthcheck-pathannotation contenue dans le fichier de valeurs pointe les contrôles de santé de l'équilibreur de charge vers le point de /api/health terminaison Grafana, qui renvoie. 200 Sans cela, les contrôles de santé ALB sont effectués par défaut/, auxquels Grafana répond par une 302 redirection/login, ce qui amène le groupe cible à signaler que le terminal est défectueux.

Imprimez l'URL de l'équilibreur de charge. L'équilibreur de charge est créé de manière asynchrone, prévoyez donc une minute ou deux :

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

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

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

Déployez l'exportateur DCGM pour les métriques GPU

La pile kube-prometheus collecte les métriques du processeur et de la mémoire au niveau des nœuds, mais pas les métriques GPU. L'exportateur NVIDIA DCGM ajoute l'utilisation du GPU, l'utilisation de la mémoire, la température, la consommation électrique, 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 touche de sélection de nœud GPU correspondant à votre chemin. EKS Auto Mode et Karpenter autogéré utilisent des clés d'étiquetage différentes pour le fabricant de 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 :

Exemple fichier de valeurs dcgm-exporter
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 la métrique par défaut de l'exportateur DCGM par une métrique étendue qui inclut la bande passante NVLink, l'activité du tenseur, le débit PCIe, les erreurs ECC et la limitation thermique. Pour les charges de travail d'inférence, ils vous aident à déterminer si les unités de calcul du GPU sont pleinement utilisées, si le GPU est inactif entre les requêtes en raison de la faible taille des lots, si le transfert de données entre le processeur et le GPU constitue un goulot d'étranglement, si la régulation thermique est à l'origine de pics de latence et quelle est la marge de mémoire du GPU 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

tolerationsAutorisez 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étecter 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 apparaître un Pod prêt. 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

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

Le modèle pèse le godet S3

Créez un compartiment Amazon S3 pour stocker les poids des modèles et configurez une association EKS Pod Identity afin que les modules 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

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}

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

Configurer EKS Pod Identity pour l'accès S3

Créez model-storage-sa ServiceAccount dans l'defaultespace de noms une politique IAM limitée au bucket de modèles et une association EKS Pod Identity qui les relie. Les modules 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 les poids des modèles, supprimez s3:PutObject et suivez s3:DeleteObject le moindre privilège.

Créez l'association EKS Pod Identity. eksctlcrée le rôle IAM avec la politique de confiance appropriée 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-saassociation dans l'espace de default noms.

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

Une fois votre cluster prêt, vous pouvez passer au modèle Load & Serve pour déployer un grand modèle de langage et interagir avec le point de terminaison d'inférence.

Nettoyage

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

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

Si vous avez créé un ODCR, annulez-le d'abord. Recherchez le numéro de réservation :

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}) echo "Capacity reservation ID: ${CAPACITY_RESERVATION_ID}"

Annuler la réservation :

aws ec2 cancel-capacity-reservation --capacity-reservation-id ${CAPACITY_RESERVATION_ID}
Important

L'annulation d'une réservation ne met pas fin aux instances en cours d'exécution. 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.

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'ID 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 de kube-prometheus-stack Helm :

helm uninstall kube-prometheus-stack -n monitoring

Supprimez l'association EKS Pod Identity pour le compte de 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

Recherchez le nom du compartiment 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 compartiment 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 Kubernetes ServiceAccount :

kubectl delete serviceaccount model-storage-sa
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