Ayude a mejorar esta página
Para contribuir a esta guía del usuario, elija el enlace Edit this page on GitHub que se encuentra en el panel derecho de cada página.
Configuración del clúster de Amazon EKS para cargas de trabajo de IA y ML con la CLI
sugerencia
Regístrese
En esta sección, se explican los pasos necesarios para crear la infraestructura necesaria para ejecutar cargas de trabajo de formación o inferencia en Amazon EKS mediante comandos de la CLI. Los pasos incluyen la creación de un clúster de EKS, nodos habilitados para GPU con el modo automático de EKS o Karpenter, una pila de supervisión con Prometheus y Grafana y almacenamiento en Amazon S3 para el peso de los modelos.
Consulte la documentación del modo automático de EKS y Karpenter
Arquitectura y flujo de trabajo de alto nivel
En el diagrama se muestra la arquitectura de alto nivel de AWS para la configuración de esta sección. Los pasos numerados de la derecha indican el orden en el que se completa la configuración en los pasos siguientes.
Requisitos previos
importante
Los recursos que cree en este tutorial, lo que incluye los clústeres de EKS, las instancias de GPU, los equilibradores de carga de aplicación y Amazon Managed Service para Prometheus, conllevan cargos. Elimine los recursos cuando haya terminado para evitar que se sigan cobrando los cargos.
-
kubectl>= 1.36. Para obtener instrucciones de configuración, consulte Configuración de kubectl y eksctl. -
AWS CLI >= 2.27. Para obtener instrucciones de configuración, consulte Instalación.
-
Helm >= 3.14. Para obtener instrucciones de configuración, consulte Configuración de Helm.
-
jq. Para obtener instrucciones de configuración, consulte Descarga de jq. -
eksctl>= 0.227.0. Para obtener instrucciones de configuración, consulte Instalaciónen la documentación de eksctl.
Verifique la versión de eksctl:
eksctl version
Si tiene una versión anterior a la 0.227.0, siga la guía de instalación de eksctl
Configuración de las variables de entorno
Mantenga la coherencia entre el nombre del clúster y la región de AWS siguientes a lo largo de estos pasos. Si se cambia, es posible que los siguientes comandos se dirijan al clúster de EKS incorrecto.
export CLUSTER_NAME=ai-eks-docs export AWS_REGION=us-east-2
El uso de todas las AZ disponibles mejora la tolerancia a errores y aumenta las posibilidades de obtener la capacidad de GPU:
export AZS=$(aws ec2 describe-availability-zones \ --region ${AWS_REGION} \ --query "AvailabilityZones[?ZoneId!='use1-az3' && ZoneId!='usw1-az2' && ZoneId!='cac1-az3'].ZoneName" \ --output text | tr '\t' ',') echo $AZS
importante
Las zonas de disponibilidad use1-az3, usw1-az2 y cac1-az3 están excluidas porque Amazon EKS no admite la colocación de planos de control en esas zonasUnsupportedAvailabilityZoneException.
Resultado previsto:
us-east-2a,us-east-2b,us-east-2c
Las AZ de la salida variarán según la región. En este ejemplo, se muestran las AZ disponibles para la región us-east-2.
Creación de NodePool de GPU y clúster
En esta sección, se proporcionan dos rutas para crear el clúster de EKS y los nodos habilitados para GPU, como se muestra en el siguiente diagrama. Elija solo una opción a lo largo de la guía.
-
Modo automático de EKS: además de los complementos de redes, almacenamiento y equilibrio de carga principales, el modo automático de EKS incluye y administra las siguientes capacidades para las cargas de trabajo de entrenamiento e inferencia: agente de supervisión de nodos de EKS, reparación automática de nodos, capturador de instantáneas SOCI
para extraer contenedores rápidamente y preparación de la GPU para la NodeClass predeterminada. El complemento para dispositivos de NVIDIA se incluye en la AMI acelerada de Bottlerocket que utiliza el modo automático de EKS para los nodos habilitados para GPU. -
Karpenter autoadministrado: en un clúster de EKS sin el modo automático de EKS, es su responsabilidad instalar y configurar los componentes necesarios para las cargas de trabajo de entrenamiento e inferencia. Esto incluye complementos de red (CNI de VPC, CoreDNS, kube-proxy), Karpenter, el agente de supervisión de nodos de EKS, el complemento para dispositivos de NVIDIA y el capturador de instantáneas SOCI para extraer contenedores rápidamente.
Opciones de clústeres de EKS: modo automático de EKS y Karpenter autoadministrado
En cada uno de los pasos siguientes, elija una ruta (modo automático de EKS o Karpenter) y sígala en todo momento. Después de completar los pasos de la ruta elegida, dispondrá de un clúster de EKS con NodePool de GPU listo para programar las cargas de trabajo de la GPU.
Paso 1: crear el clúster
Comience por crear su clúster de EKS e instalar los componentes del clúster necesarios para las cargas de trabajo de GPU.
Con el modo automático de EKS, un solo comando eksctl create cluster --enable-auto-mode proporciona un clúster de EKS listo para las cargas de trabajo de la GPU.
En el caso de Karpenter autoadministrado, el comando eksctl create cluster proporciona los complementos principales de red y, a continuación, es necesario adoptar medidas adicionales para permitir la reparación automática de los nodos mediante una puerta de la característica de Karpenter, instalar el agente de supervisión de nodos de EKS e instalar el complemento para dispositivo de NVIDIA.
aviso
Tanto para las rutas del modo automático de EKS como las de Karpenter autoadministrado, la reparación automática de nodos se comporta de la misma manera en los nodos aprovisionados por NodePools. La reparación automática de nodos en el modo automático de EKS y Karpenter es un método de interrupción forzosa que evita PodDisruptionBudgets, la anotación karpenter.sh/do-not-disrupt y terminationGracePeriod. La reparación automática de nodos espera 10 minutos antes de sustituir un nodo con la condición AcceleratedHardwareReady establecida en False y 30 minutos si se trata de otras condiciones de reparación.
Configuración del equilibrio de carga
Los pasos posteriores de esta guía exponen Grafana (y, en el tutorial de inferencia, un punto de conexión del modelo) a través de un equilibrador de carga de aplicación (ALB) de AWS. Configure ahora los requisitos previos de equilibrio de carga para que esas secciones puedan crear una Ingress sin necesidad de configuración adicional.
El ALB se coloca en las subredes de la VPC en función de las etiquetas de recursos AWS. Las subredes públicas utilizadas para los equilibradores de carga orientados a Internet deben tener la etiqueta kubernetes.io/role/elb = 1, mientras que las subredes privadas utilizadas para los equilibradores de carga internos deben tener la etiqueta kubernetes.io/role/internal-elb = 1. Como creó este clúster con eksctl, esas etiquetas ya existen en las subredes que creó eksctl. Si trae su propia VPC o subredes importadas, etiquételas manualmente. Para obtener más información, consulte Etiquetado de subredes para el modo automático de EKS.
Creación del equilibrador de carga IngressClass
El resto de la configuración varía según la ruta. El modo automático de EKS incluye un controlador del ALB integrado, por lo que puede crear una IngressClass por su cuenta. El Karpenter autoadministrado requiere instalar el controlador del equilibrador de carga de AWS con Helm y el gráfico de Helm crea la IngressClass en su nombre.
Ambas rutas ahora tienen una IngressClass alb. Las secciones de Grafana e inferencia hacen referencia a ingressClassName: alb y establecen el esquema del ALB, la lista de IP de origen permitidas y otros comportamientos mediante anotaciones por Ingress.
Paso 2: creación de NodePool de GPU dinámica
Defina un NodePool que aprovisione dinámicamente las instancias de GPU de la familia G con una generación superior a 4 e inferior a 7 mediante la capacidad de spot con un uso bajo demanda como alternativa. Tanto las rutas del modo automático de EKS como las de Karpenter utilizan la misma API de NodePool, con la única diferencia de la NodeClass a la que apunta. En el modo automático de EKS, la NodeClass default agrupada ya selecciona la AMI correcta y configura la extracción paralela de SOCI, por lo que NodePool es el único objeto que se crea. En Karpenter autoadministrado, también se necesita una EC2NodeClass personalizada que fije la AMI y ajuste SOCI.
importante
El tipo de instancia de EC2 G7 requiere la versión 595 o posterior del controlador de NVIDIA. Las AMI aceleradas optimizadas para EKS incluyen actualmente la versión 580 del controlador de NVIDIA, que no es compatible con las instancias G7. En este paso, el NodePool limita la generación de instancias a menos de 7 para que Karpenter no seleccione una instancia G7. Para utilizar instancias G7 con Amazon EKS, debe crear una AMI personalizada con la versión 595 del controlador de NVIDIA. Para obtener más información, consulte Uso de AMI aceleradas optimizadas para EKS para instancias de GPU.
Valide que se haya creado el NodePool:
kubectl get nodepool gpu-inf
Resultado previsto:
NAME NODECLASS NODES READY AGE gpu-inf default 0 True 8s
En la ruta de Karpenter autoadministrado, la columna NODECLASS muestra gpu-inf en lugar de default.
Paso 3: prueba con un pod de muestra
Pruebe la configuración de NodePool de GPU con un pod nvidia-smi.
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
Compruebe que el pod se haya programado y completado correctamente.
kubectl get pods
Resultado previsto:
NAME READY STATUS RESTARTS AGE nvidia-smi 0/1 Completed 0 67s
Si aparece ESTADO: Completado, significa que el comando nvidia-smi se ejecutó y se cerró. Compruebe los registros del pod para ver la GPU detectada por el nodo.
kubectl logs nvidia-smi
Resultado previsto:
+-----------------------------------------------------------------------------------------+ | 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 salida muestra el modelo de GPU, la versión del controlador, la versión de CUDA y la memoria disponible. En este ejemplo, Karpenter aprovisionó una instancia G6 que tiene una GPU L4 de NVIDIA con 24 GB de memoria. La temperatura actual de la GPU es de 42 °C y P8 es un estado inactivo de bajo consumo de energía, lo que es de esperar ya que ninguna carga de trabajo está usando la GPU. El valor de 16 W o 72 W muestra el consumo de energía actual en comparación con la capacidad máxima de energía, mientras que 0 MiB / 23 034 MiB muestra el consumo actual de la GPU en comparación con el total disponible. Como el pod acaba de ejecutar nvidia-smi y se ha cerrado, no hay carga de trabajo que utilice la GPU, por lo que la memoria está a 0 y la alimentación está inactiva. La versión del controlador de GPU de NVIDIA (580.159.03) proviene de la AMI de Bottlerocket, mientras que la versión de CUDA (13.0) proviene de la imagen del contenedor. El modelo de GPU y la memoria variarán según el tipo de instancia que seleccione Karpenter. Las instancias G5 tienen GPU A10G de NVIDIA (24 GB), las instancias G6 tienen GPU L4 de NVIDIA (24 GB) y las instancias G6e tienen GPU L40S de NVIDIA (48 GB).
Para entender cómo Karpenter y el programador de Kubernetes se coordinaron para aprovisionar un nodo y colocar el pod, compruebe los eventos del ciclo de vida del pod:
kubectl describe po nvidia-smi
Resultado previsto:
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 60s default-scheduler 0/2 nodes are available: 2 node(s) had untolerated taint(s). no new claims to deallocate, preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling. Normal Nominated 59s eks-auto-mode/compute Pod should schedule on: nodeclaim/gpu-inf-vxcnj Normal Scheduled 24s default-scheduler Successfully assigned default/nvidia-smi to i-0fb17a09bc4203164 Warning FailedCreatePodSandBox 21s kubelet Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "7f85e25b220c8fb245187758dbbbc8efb3d40f3e49e13054404880daf4c3b2f0": plugin type="aws-cni" name="aws-cni" failed (add): add cmd: failed to setup network policy Normal Pulling 7s kubelet spec.containers{nvidia-smi}: Pulling image "public.ecr.aws/amazonlinux/amazonlinux:2023-minimal" Normal Pulled 5s kubelet spec.containers{nvidia-smi}: Successfully pulled image "public.ecr.aws/amazonlinux/amazonlinux:2023-minimal" in 1.237s (1.237s including waiting). Image size: 37442701 bytes. Normal Created 5s kubelet spec.containers{nvidia-smi}: Container created Normal Started 5s kubelet spec.containers{nvidia-smi}: Container started
Estos eventos muestran la secuencia de programación del pod: el pod inicialmente no se programa porque no existen nodos de GPU (FailedScheduling), Karpenter nomina un nuevo NodeClaim (nominado), el programador asigna el pod una vez que el nodo está listo (programado) y, a continuación, se extrae e inicia la imagen del contenedor. El modo automático de EKS viene con la extracción paralela de SOCI (Seekable OCI) instalada y configurada de fábrica en las instancias G, P y Trn. Tenga en cuenta que, debido a la extracción paralela de SOCI, la imagen del contenedor se extrajo de ECR en menos de 2 segundos (1,237 s).
NodeClaim es una solicitud que Karpenter crea para aprovisionar un nodo específico. Muestra el tipo de instancia, el tipo de capacidad, la AZ y si el nodo está listo.
kubectl get nodeclaims
Salida esperada de NodeClaim:
NAME TYPE CAPACITY ZONE NODE READY AGE gpu-inf-vxcnj g6.4xlarge spot us-east-2c i-0fb17a09bc4203164 True 51s
El tipo de instancia y la AZ variarán. Todas las instancias de la familia G con una generación superior a 4 e inferior a 7 son aptas.
La advertencia FailedCreatePodSandBox en kubectl describe pod nvidia-smi es transitoria y esperada. CNI de VPC se inicializa de forma asíncrona una vez que el nodo se une y el kubelet lo vuelve a intentar automáticamente. Si el pod permanece en ContainerCreating, compruebe los eventos del nodo con kubectl describe node <node-name>.
sugerencia
Si no aparece ningún nodo, compruebe si hay errores de capacidad insuficiente:
kubectl get events | grep InsufficientCapacityError
Karpenter almacena en caché las ofertas no disponibles durante 3 minutos. Ampliar los tipos de instancias y las zonas de disponibilidad permitidos en el NodePool aumenta las posibilidades de conseguir capacidad.
nota
Las instancias de spot lanzadas por Karpenter no aparecerán en la consola de solicitudes de spot de EC2. Karpenter utiliza la API CreateFleet de EC2 con type: instant. Las instancias aparecen en la consola de instancias de EC2 con un ciclo de vida de spot.
Paso 4: adición de capacidad reservada al NodePool (opcional)
Para utilizar primero la capacidad reservada con la reserva de spot o bajo demanda, cree una reserva de capacidad bajo demanda (ODCR), adjúntela a su NodeClass y, a continuación, actualice el NodePool dinámico del paso 2 para permitir también la capacidad reserved. La llamada a la API de reserva es la misma para ambas rutas; el adjunto de NodeClass es diferente porque el modo automático de EKS y Karpenter autoadministrado utilizan diferentes tipos de NodeClass.
aviso
El siguiente comando genera un cargo por el tipo de instancia reservada hasta que lo cancele con aws ec2 cancel-capacity-reservation --capacity-reservation-id <id>.
Cree la reserva de capacidad:
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 se produce un error InsufficientInstanceCapacity, cambie CR_AZ a una AZ diferente y vuelva a intentarlo.
Busque el ID de reserva de capacidad y guárdelo en una variable del intérprete de comandos para los siguientes pasos:
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}"
A continuación, aplique los cambios de NodeClass y NodePool a la ruta:
Karpenter considera reserved como la opción más rentable y la lanza primero. Una vez que la reserva esté completa, volverá a ser de spot o bajo demanda.
Tras aplicar los cambios, valide que Karpenter priorice la capacidad reservada y recurra a las opciones de spot o bajo demanda. Implemente una implementación de 2 réplicas que solicite 1 GPU por pod. El ODCR es para 1 instancia, por lo que el primer pod activa Karpenter para lanzar un nodo reservado. El segundo pod no cabe en el nodo reservado y hace que Karpenter lance otro nodo desde la capacidad de spot o bajo demanda.
cat << 'EOF' | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: gpu-overflow-test labels: guide: ai-eks-docs spec: replicas: 2 selector: matchLabels: app: gpu-overflow-test template: metadata: labels: app: gpu-overflow-test guide: ai-eks-docs spec: tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule containers: - name: nvidia-smi image: public.ecr.aws/amazonlinux/amazonlinux:2023-minimal command: ["sh", "-c", "nvidia-smi && sleep infinity"] resources: limits: nvidia.com/gpu: 1 EOF
A diferencia del pod de prueba nvidia-smi del paso 3 que se ejecutó y cerró, esta implementación mantiene los pods en ejecución (sleep infinity) para que mantengan la GPU y no lancen el nodo.
Verifique los pods programados en los distintos nodos:
kubectl get pods -l app=gpu-overflow-test -o wide
Resultado previsto:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES gpu-overflow-test-59b97944fb-lq56c 1/1 Running 0 2m42s 192.168.186.240 i-057692590480155da <none> <none> gpu-overflow-test-59b97944fb-z4zcx 1/1 Running 0 2m42s 192.168.130.64 i-0521ecd1849fa0578 <none> <none>
Los dos pods se están ejecutando, cada uno en un nodo diferente.
Compruebe NodeClaims para ver los tipos de capacidad:
kubectl get nodeclaims
Resultado previsto:
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
El nodo reservado se lanzó primero, seguido de un nodo de spot o bajo demanda una vez que se completó la reserva.
Elimine la implementación de prueba:
kubectl delete deployment gpu-overflow-test
Supervisión
Instale una pila de supervisión que recopile métricas de clústeres, nodos y GPU en Amazon Managed Service para Prometheus (AMP) y visualícelas con Grafana. El gráfico de Helm kube-prometheus-stack implementa Prometheus para raspar y escribir métricas de forma remota en AMP, además de Grafana autoadministrado para los paneles. El Exportador DCGM de NVIDIA agrega métricas específicas de la GPU (uso, memoria, temperatura, potencia, NVLink y actividad de los tensores).
Prometheus, Grafana y el operador aterrizan en nodos que no son de la GPU de forma predeterminada, ya que los nodos de la GPU incluyen el taint nvidia.com/gpu:NoSchedule. Tanto el exportador de nodos como el Exportador DCGM se ejecutan en nodos de GPU, por lo que podemos raspar las métricas del host y de la GPU de toda la flota.
Si abrió un terminal nuevo, establezca el nombre y la región del clúster:
export CLUSTER_NAME=ai-eks-docs export AWS_REGION=us-east-2
Creación del espacio de trabajo de AMP
Cree un espacio de trabajo de AMP para almacenar las métricas:
aws amp create-workspace \ --alias "amp-ws-${CLUSTER_NAME}" \ --region ${AWS_REGION}
Obtenga el ID de espacio de trabajo:
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}"
Obtenga el punto de conexión de escritura remota:
AMP_ENDPOINT=$(aws amp describe-workspace \ --workspace-id ${AMP_WORKSPACE_ID} \ --query 'workspace.prometheusEndpoint' \ --output text \ --region ${AWS_REGION}) echo "AMP Endpoint: ${AMP_ENDPOINT}"
Creación de asociaciones de Pod Identity de EKS y política de IAM
Cree una política de IAM que permita a Prometheus escribir métricas de forma remota y a Grafana consultarlas:
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}"
Cree el espacio de nombres de supervisión y las cuentas de servicio para Prometheus y Grafana:
kubectl create namespace monitoring kubectl create serviceaccount amp-iamproxy-ingest-service-account -n monitoring kubectl create serviceaccount grafana-sa -n monitoring
Cree asociaciones de Pod Identity de EKS para vincular las cuentas de servicio a la política de 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}
Verifique que se hayan creado ambas asociaciones de Pod Identity de EKS:
eksctl get podidentityassociation --cluster ${CLUSTER_NAME} --region ${AWS_REGION}
La salida esperada debe incluir amp-iamproxy-ingest-service-account y grafana-sa en el espacio de nombres monitoring.
Instalación de kube-prometheus-stack
Agregue el repositorio de Helm:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update
Este archivo de valores omite un nodeSelector para Prometheus, Grafana y el operador: el taint nvidia.com/gpu:NoSchedule de los nodos de la GPU los mantiene alejados de los nodos de la GPU, por lo que aterrizan en el sistema o en un grupo de uso general de forma predeterminada. El exportador de nodos utiliza una tolerancia comodín, por lo que se ejecuta en todos los nodos (incluidos los nodos de la GPU) para recopilar las métricas de toda la flota.
El archivo de valores también configura una Ingress de Grafana para que el gráfico proporcione un ALB con acceso a Internet para el acceso del navegador, con la IngressClass alb que creó en Configuración del equilibrio de carga. La anotación alb.ingress.kubernetes.io/inbound-cidrs restringe el equilibrador de carga a su propia dirección IP, así que configúrela antes de instalarlo.
Grafana es de acceso público a través de HTTP con las credenciales predeterminadas
Grafana incluye credenciales de administrador predeterminadas y proporciona acceso administrativo completo a sus datos de supervisión. Un equilibrador de carga orientado a Internet coloca esta interfaz en la Internet pública a través de HTTP de texto sin formato. Los escáneres automatizados detectan los equilibradores de carga públicos en cuestión de minutos. Debe restringir el acceso con la anotación alb.ingress.kubernetes.io/inbound-cidrs y tratar las listas de direcciones IP de origen permitidas como una protección mínima, no como una protección completa. Cambie también la contraseña de administrador predeterminada de Grafana. Para una posición más sólida, utilice un esquema interno (al que solo se pueda acceder desde su VPC o una VPN conectada) mediante la configuración del esquema en internal y agregue un certificado TLS.
Busque su dirección IP pública y guárdela como CIDR /32. El archivo de valores lee lo siguiente de la variable de entorno MY_CIDR:
export MY_CIDR="$(curl -s https://checkip.amazonaws.com)/32" echo $MY_CIDR
El resultado es similar a 203.0.113.4/32. Si la red asigna direcciones de forma dinámica, es posible que la dirección IP cambie con el tiempo, por lo que considere la posibilidad de establecer un intervalo más amplio, como 203.0.113.0/24.
Cree el archivo de valores:
ejemplo Archivo de valores de 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
Valide que las variables se hayan rellenado correctamente:
grep -E "url:|region:" /tmp/kube-prometheus-values.yaml
Debería ver la URL completa del punto de conexión de AMP (comienza por https://aps-workspaces…) y la región. Si hay algo vacío, vuelva a exportar las variables y a crear el archivo.
Instale el gráfico:
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \ --namespace monitoring \ -f /tmp/kube-prometheus-values.yaml
Verifique que los pods se estén ejecutando:
kubectl get pods -n monitoring
Resultado previsto:
NAME READY STATUS RESTARTS AGE kube-prometheus-stack-grafana-7c58f54f77-rftrj 3/3 Running 0 4m kube-prometheus-stack-kube-state-metrics-d68dcbc84-5smxq 1/1 Running 0 4m kube-prometheus-stack-operator-5895df479f-ttm47 1/1 Running 0 4m kube-prometheus-stack-prometheus-node-exporter-t9q7s 1/1 Running 0 4m kube-prometheus-stack-prometheus-node-exporter-x6vfb 1/1 Running 0 4m prometheus-kube-prometheus-stack-prometheus-0 2/2 Running 0 4m
La pila incluye los siguientes componentes:
-
Prometheus (StatefulSet): raspa métricas y las escribe de forma remota en AMP
-
Grafana: paneles y visualización, preconfigurados con el origen de datos de AMP
-
kube-state-metrics: genera métricas sobre el estado de objetos de Kubernetes (estado del Pod, límites y solicitudes de recursos, estados de NodeClaim)
-
node-exporter (DaemonSet, uno por nodo): recopila métricas de host (CPU, memoria, disco, red)
-
operador: administra los recursos personalizados de Prometheus y Alertmanager
Alertmanager está deshabilitado en esta configuración.
Acceso a Grafana
Accede a Grafana a través de un equilibrador de carga de aplicación (ALB) de AWS orientado a Internet. No lo cree aquí. El gráfico kube-prometheus-stack lo aprovisiona a partir de la configuración grafana.ingress del archivo de valores, con la IngressClass alb de Configuración del equilibrio de carga. El gráfico de Helm de Grafana tiene compatibilidad integrada con Ingress, por lo que no se necesita un manifiesto independiente. El ALB tiene el nombre grafana-ai-eks-docs, lleva la etiqueta guide: ai-eks-docs y está restringido a la dirección IP que estableció en MY_CIDR en el momento de la instalación.
Se requiere una ruta de comprobación de estado para el grupo de destino del ALB de Grafana.
La anotación alb.ingress.kubernetes.io/healthcheck-path del archivo de valores apunta las comprobaciones de estado del equilibrador de carga al punto de conexión /api/health de Grafana, que devuelve 200. Sin él, las comprobaciones de estado del ALB tienen como valor predeterminado /, a las que Grafana responde con una redirección de 302 a /login, lo que hace que el grupo de destino informe de que el punto de conexión no está en buen estado.
Imprima la URL del equilibrador de carga. El equilibrador de carga se crea de forma asíncrona, así que espere uno o dos minutos:
echo "http://$(kubectl get ingress kube-prometheus-stack-grafana -n monitoring -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')"
Abra la dirección URL en el navegador. Inicie sesión con el nombre de usuario admin y la contraseña con el siguiente comando:
kubectl --namespace monitoring get secrets kube-prometheus-stack-grafana -o jsonpath="{.data.admin-password}" | base64 -d ; echo
Para comprobar que la canalización de métricas funciona de principio a fin:
-
Vaya a Conexiones > Orígenes de datos y confirme que
Amazon-Managed-Prometheusaparezca como origen de datos predeterminado.Validación del origen de datos de AMP en Grafana
-
Vaya a Desglose > Métricas y busque la métrica
up. Debería ver los resultados de los objetivos de raspado del clúster.Validación de la métrica
upen Grafana
Si up muestra resultados, la canalización (clúster → Prometheus → AMP → Grafana) está funcionando.
Implementación del Exportador DCGM para las métricas de la GPU
kube-prometheus-stack recopila métricas de CPU y memoria de nodo, pero no métricas de GPU. El Exportador DCGM de NVIDIA agrega el uso de GPU, el uso de memoria, la temperatura, el consumo de energía, el ancho de banda de NVLink y la actividad de los tensores.
helm repo add gpu-helm-charts https://nvidia.github.io/dcgm-exporter/helm-charts helm repo update
Establezca la clave del selector de nodos de GPU para la ruta. El modo automático de EKS y Karpenter autoadministrado utilizan diferentes etiquetas según el fabricante de la GPU.
Cree el archivo de valores del Exportador DCGM:
ejemplo Archivo de valores de 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
El campo customMetrics anula el conjunto de métricas predeterminado del Exportador DCGM por uno ampliado que incluye el ancho de banda de NVLink, la actividad de los tensores, el rendimiento de PCIe, los errores de ECC y la limitación térmica. Para las cargas de trabajo de inferencia, esto le permite comprender si las unidades de computación de la GPU se utilizan al máximo, si la GPU está inactiva entre las solicitudes debido al bajo tamaño de los lotes, si la transferencia de datos entre la CPU y la GPU es un cuello de botella, si la limitación térmica provoca picos de latencia y cuánto espacio de memoria queda en la GPU para lotes más grandes.
Instale el Exportador DCGM:
helm install dcgm-exporter gpu-helm-charts/dcgm-exporter \ --namespace monitoring \ -f /tmp/dcgm-exporter-values.yaml
Las tolerations permiten al exportador ejecutarse en los nodos con taint de GPU que aprovisionó en el paso 2. La opción serviceMonitor con la etiqueta release: kube-prometheus-stack garantiza que Prometheus lo detecte y raspe automáticamente.
Verificación del DaemonSet del Exportador DCGM:
kubectl get daemonset dcgm-exporter -n monitoring
Una vez que se ejecute un nodo de la GPU, debería ver un pod listo para usar. Para validar las métricas de DCGM, vaya a Desglose > Métricas en Grafana y busque DCGM_.
Validación de las métricas de DCGM en Grafana
Para ver el panel, vaya a Paneles > Supervisión de GPU > Panel del Exportador DCGM de NVIDIA.
Panel del Exportador DCGM de NVIDIA en Grafana
Bucket de S3 de pesos de los modelos
Cree un bucket de Amazon S3 para almacenar los pesos de los modelos y configure una asociación de Pod Identity de EKS para que los pods de carga de trabajo puedan leer y escribir en él.
Si abrió un terminal nuevo, establezca el nombre y la región del clúster:
export CLUSTER_NAME=ai-eks-docs export AWS_REGION=us-east-2
Crear el bucket de S3
Cree el bucket con un sufijo aleatorio para evitar colisiones de nombres:
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}
Los buckets de S3 creados después de enero de 2023 tienen habilitados de forma predeterminada el cifrado del servidor (AES256) y el bloqueo del acceso público.
Configuración de Pod Identity de EKS para el acceso a S3
Cree una ServiceAccount model-storage-sa en el espacio de nombres default, una política de IAM que se ajuste al bucket de modelos y una asociación de Pod Identity de EKS que las vincule. Los pods de carga de trabajo que establezcan serviceAccountName: model-storage-sa podrán leer y escribir en el bucket.
kubectl create serviceaccount model-storage-sa
Cree la política de IAM:
POLICY_ARN=$(aws iam create-policy \ --policy-name "${CLUSTER_NAME}-model-storage-policy" \ --policy-document "{\"Version\": \"2012-10-17\", \"Statement\": [{\"Effect\": \"Allow\", \"Action\": [\"s3:GetObject\", \"s3:PutObject\", \"s3:ListBucket\", \"s3:DeleteObject\"], \"Resource\": [\"arn:aws:s3:::${MODEL_BUCKET}\", \"arn:aws:s3:::${MODEL_BUCKET}/*\"]}]}" \ --query 'Policy.Arn' \ --output text) echo "Policy ARN: ${POLICY_ARN}"
nota
Esta política concede s3:DeleteObject y s3:PutObject para el paso de validación. Para los pods de inferencia de producción que solo leen los pesos de los modelos, elimine s3:PutObject y s3:DeleteObject siga el privilegio mínimo.
Cree la asociación de Pod Identity de EKS. eksctl crea el rol de IAM con la política de confianza correcta y lo vincula a la ServiceAccount:
eksctl create podidentityassociation \ --cluster ${CLUSTER_NAME} \ --namespace default \ --service-account-name model-storage-sa \ --role-name "${CLUSTER_NAME}-model-storage-role" \ --permission-policy-arns ${POLICY_ARN} \ --region ${AWS_REGION}
Verifique la asociación:
eksctl get podidentityassociation --cluster ${CLUSTER_NAME} --region ${AWS_REGION}
La salida debe incluir la asociación model-storage-sa en el espacio de nombres default.
Ejecute un pod único con la imagen de la AWS CLI, mediante la ServiceAccount model-storage-sa, para confirmar que Pod Identity de EKS esté conectado y que el acceso a S3 funcione:
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
Espere a que el pod se complete y compruebe los registros:
kubectl wait --for=jsonpath='{.status.phase}'=Succeeded pod/s3-test --timeout=300s kubectl logs s3-test
Resultado previsto:
=== Caller Identity ===
{
"UserId": "AROA...:eks-ai-eks-docs-model-s-...",
"Account": "123456789012",
"Arn": "arn:aws:sts::123456789012:assumed-role/ai-eks-docs-model-storage-role/eks-ai-eks-docs-model-s-..."
}
=== S3 Write Test ===
upload: - to s3://ai-eks-docs-models-01234567/test.txt
=== S3 List Test ===
2026-05-04 12:00:00 19 test.txt
=== S3 Delete Test ===
delete: s3://ai-eks-docs-models-01234567/test.txtLa identidad de la persona que llama confirma que el pod asumió el rol ${CLUSTER_NAME}-model-storage-role a través de Pod Identity de EKS. Los comandos de S3 confirman el acceso de lectura y escritura.
Elimine el pod de prueba:
kubectl delete pod s3-test
Siguientes pasos
Con el clúster listo, puede pasar al modelo de carga y servicio para implementar un modelo de lenguaje de gran tamaño e interactuar con el punto de conexión de inferencia.
Eliminación
sugerencia
Si planea continuar con las siguientes secciones de esta guía, omita la limpieza completa. Ejecútela solo cuando haya terminado.
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 ha creado una ODCR, cancélela antes. Busque el ID de reserva:
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}"
Cancele la reserva:
aws ec2 cancel-capacity-reservation --capacity-reservation-id ${CAPACITY_RESERVATION_ID}
importante
La cancelación de una reserva no termina las instancias en ejecución. Se mantienen con las tasas bajo demanda estándar hasta que se terminen. Elimine antes la implementación para vaciar el nodo reservado antes de cancelarlo.
Busque el ARN de la política de 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}"
Busque el ID del espacio de trabajo de 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}"
Desinstale la versión de Helm del Exportador DCGM:
helm uninstall dcgm-exporter -n monitoring
Desinstale la versión de Helm de kube-prometheus-stack:
helm uninstall kube-prometheus-stack -n monitoring
Elimine la asociación de Pod Identity de EKS para la cuenta de servicio de ingesta de Prometheus:
eksctl delete podidentityassociation \ --cluster ${CLUSTER_NAME} \ --namespace monitoring \ --service-account-name amp-iamproxy-ingest-service-account \ --region ${AWS_REGION}
Elimine la asociación de Pod Identity de EKS para la cuenta de servicio de Grafana:
eksctl delete podidentityassociation \ --cluster ${CLUSTER_NAME} \ --namespace monitoring \ --service-account-name grafana-sa \ --region ${AWS_REGION}
Elimine la política de IAM utilizada por Prometheus y Grafana:
aws iam delete-policy --policy-arn ${AMP_POLICY_ARN}
Elimine el espacio de trabajo de AMP:
aws amp delete-workspace --workspace-id ${AMP_WORKSPACE_ID} --region ${AWS_REGION}
Elimine el espacio de nombres de supervisión:
kubectl delete namespace monitoring
Busque el nombre del bucket del modelo:
MODEL_BUCKET=$(aws s3api list-buckets \ --query "Buckets[?starts_with(Name, '${CLUSTER_NAME}-models-')].Name | [0]" \ --output text) echo "Model bucket: ${MODEL_BUCKET}"
Busque el ARN de la política de 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}"
Elimine el bucket del modelo S3 y todos sus objetos:
aws s3 rb s3://${MODEL_BUCKET} --force
Elimine la asociación de Pod Identity de EKS:
eksctl delete podidentityassociation \ --cluster ${CLUSTER_NAME} \ --namespace default \ --service-account-name model-storage-sa \ --region ${AWS_REGION}
Elimine la política de IAM:
aws iam delete-policy --policy-arn ${POLICY_ARN}
Elimine la ServiceAccount de Kubernetes:
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