帮助改进此页面
要帮助改进本用户指南,请选择位于每个页面右侧窗格中的在 GitHub 上编辑此页面链接。
使用 CLI 为人工智能/机器学习工作负载设置 Amazon EKS 集群
提示
注册参加
本节将演示通过 CLI 命令创建在 Amazon EKS 上运行训练或推理工作负载所需基础设施的步骤。这些步骤包括创建一个 EKS 集群、若干使用 EKS 自动模式或 Karpenter 的 GPU 节点、一个使用 Prometheus 和 Grafana 的监控堆栈以及用于存储模型权重的 Amazon S3 存储。
有关这些功能如何在 EKS 集群中预调配和自动扩展 EC2 实例的更多信息,请参阅 EKS 自动模式和 Karpenter
高层架构和工作流
下图显示了本节设置的 AWS 高层架构。右侧带编号的步骤表示您按以下步骤完成配置的顺序。
先决条件
-
kubectl>= 1.35。有关设置说明,请参阅设置 kubectl 和 eksctl。 -
AWS CLI >= 2.27。有关设置说明,请参阅安装。
-
Helm >= 3.14。有关设置说明,请参阅设置 Helm。
-
jq。有关设置说明,请参阅 Download jq。 -
eksctl>= 0.227.0。有关设置说明,请参阅eksctl文档中的 Installation。
验证您的 eksctl 版本:
eksctl version
如果您使用的版本早于 0.227.0,请按照 eksctl 安装指南
设置环境变量
在这些步骤中,以下集群名称和 AWS 区域应保持一致。如果更改则可能会导致后续命令使用的目标 EKS 集群不正确。
export CLUSTER_NAME=ai-eks-docs export AWS_REGION=us-east-2
使用所有可用的可用区可提高容错能力并增加获得 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
重要
应排除 use1-az3、usw1-az2 和 cac1-az3 可用区,因为 Amazon EKS 不支持将控制面板置于这些可用区中UnsupportedAvailabilityZoneException 错误。
预期输出:
us-east-2a,us-east-2b,us-east-2c
输出中的可用区因区域而异。此示例显示的是 us-east-2 区域的可用区。
创建集群和 GPU 节点池
本节提供了两种创建 EKS 集群和 GPU 节点的路径,如下图所示。在整个指南中请仅选择一个选项。
-
EKS 自动模式:除了核心的联网、存储和负载均衡附加组件外,EKS 自动模式还会包括并管理下列用于训练和推理工作负载的功能:EKS 节点监控代理、自动节点修复、用于快速提取容器的 SOCI
快照拍摄器,并为默认节点类准备好 GPU。NVIDIA 设备插件包含在EKS 自动模式用于 GPU 节点的 Bottlerocket 加速型 AMI 中。 -
自行管理的 Karpenter:对于不使用 EKS 自动模式的 EKS 集群,您负责安装和配置训练和推理工作负载所需的组件。这包括联网附加组件(VPC CNI、CoreDNS、kube-proxy)、Karpenter、EKS 节点监控代理、NVIDIA 设备插件和用于快速提取容器的 SOCI 快照拍摄器。
EKS 集群选项:EKS 自动模式和自行管理的 Karpenter
在以下每个步骤中,选择一条路径(EKS 自动模式、Karpenter),然后全程遵循该路径。完成所选路径的步骤后,您将获得一个具有 GPU 节点池,可随时用于调度 GPU 工作负载的 EKS 集群。
第 1 步:创建集群
首先创建 EKS 集群并安装 GPU 工作负载所需的集群组件。
使用 EKS 自动模式时,只需一条 eksctl create cluster --enable-auto-mode 命令即可预调配一个可随时用于 GPU 工作负载的 EKS 集群。
使用自行管理的 Karpenter 时,eksctl create cluster 命令会预调配核心联网附加组件,然后您需要完成其他步骤以通过 Karpenter 特定门控启用自动节点修复功能、安装 EKS 节点监控代理并安装 NVIDIA 设备插件。
警告
无论是 EKS 自动模式路径还是自行管理的 Karpenter 路径,对于由节点池预调配的节点,自动节点修复功能的行为方式是相同的。EKS 自动模式和 Karpenter 中的自动节点修复是一种强制中断方法,可以绕过容器组中断预算、karpenter.sh/do-not-disrupt 注释和 terminationGracePeriod。自动节点修复需要等待 10 分钟,然后才会替换 AcceleratedHardwareReady 条件设置为 False 的节点;对于其他修复条件,则需要等待 30 分钟。
第 2 步:创建动态 GPU 节点池
定义一个将使用竞价型容量动态预调配 4 代以上 G 系列 GPU 实例,并以按需型实例为备用容量的节点池。EKS 自动模式和 Karpenter 路径都使用相同的节点池 API,唯一区别是所指向的节点类不同。使用 EKS 自动模式时,捆绑的 default 节点类已经选择了正确的 AMI 并配置了 SOCI 并行拉取,因此您唯一需要创建的对象是节点池。使用自行管理的 Karpenter 时,您还需要一个可以固定 AMI 并微调 SOCI 的自定义 EC2NodeClass。
验证该节点池是否已创建:
kubectl get nodepool gpu-inf
预期输出:
NAME NODECLASS NODES READY AGE gpu-inf default 0 True 8s
对于自行管理的 Karpenter 路径,NODECLASS 列将会显示 gpu-inf,而不是 default。
第 3 步:使用示例容器组进行测试
使用一个 nvidia-smi 容器组测试 GPU 节点池设置。
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
验证容器组是否已成功调度并完成。
kubectl get pods
预期输出:
NAME READY STATUS RESTARTS AGE nvidia-smi 0/1 Completed 0 67s
若状态为“已完成”,则表示 nvidia-smi 命令已完成运行并已退出。检查容器组日志,以查看节点检测到的 GPU。
kubectl logs nvidia-smi
预期输出:
+-----------------------------------------------------------------------------------------+ | NVIDIA-SMI 580.126.09 Driver Version: 580.126.09 CUDA Version: 13.0 | +-----------------------------------------+------------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+========================+======================| | 0 NVIDIA RTX PRO 6000 Blac... On | 00000000:2B:00.0 Off | 0 | | N/A 30C P0 81W / 600W | 0MiB / 97887MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+
输出会显示 GPU 型号、驱动程序版本、CUDA 版本以及可用内存。在此示例中,Karpenter 预调配了一个 G7e 实例。该实例具有一个 NVIDIA RTX PRO 6000 Blackwell GPU 和 96 GB 内存。30C 表示当前 GPU 温度,P0 表示 GPU 处于最高性能状态(空闲但已就绪)。81W/600W 分别指当前功耗与最大功率容量,0miB/97887MiB 分别指当前使用的 GPU 内存与可用总内存。由于容器组刚刚运行完 nvidia-smi 并退出,因此没有工作负载使用 GPU,内存为 0,功率处于空闲状态。NVIDIA GPU 驱动程序版本(580.126.09)来自 Bottlerocket AMI,而 CUDA 版本(13.0)来自容器映像。GPU 型号和内存将因 Karpenter 选择的实例类型而异。G5 实例搭载 NVIDIA A10G GPU(24 GB),G6e 实例搭载 NVIDIA L40S GPU(48 GB),G7e 实例搭载 NVIDIA RTX PRO 6000 GPU(96 GB)。
要了解 Karpenter 和 Kubernetes 调度器如何协调工作来预调配节点和置放容器组,请查看容器组的生命周期事件:
kubectl describe po nvidia-smi
预期输出:
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
这些事件会显示容器组的调度顺序:容器组最初因 GPU 节点不存在而调度失败(FailedScheduling),然后 Karpenter 提名一个新的 NodeClaim(Nominated),然后调度器在节点准备就绪后分配容器组(Scheduled),最后拉取并启动容器映像。EKS 自动模式已在 G、P 和 Trn 实例上预先安装并配置了 SOCI(Seekable OCI)并行拉取。请注意,由于 SOCI 并行拉取的原因,从 ECR 中拉取容器映像的时间不到 2 秒(1.237 秒)。
NodeClaim 是 Karpenter 为预调配特定节点而创建的请求。该请求会显示实例类型、容量类型、可用区以及该节点是否准备就绪。
kubectl get nodeclaims
NodeClaim 的预期输出:
NAME TYPE CAPACITY ZONE NODE READY AGE gpu-inf-xxxxx g7e.2xlarge spot us-east-2a i-0xxxxxxxxxxxx True 2m
实例类型和可用区会有差异。任何 4 代以上的 G 系列实例均符合要求。
kubectl describe pod nvidia-smi 中的 FailedCreatePodSandBox 警告是暂时性的,也符合预期。在节点加入后,VPC CNI 会异步初始化,kubelet 也会自动重试。如果容器组留在 ContainerCreating 中,请使用 kubectl describe node <node-name> 检查节点事件。
提示
如果未显示任何节点,请检查是否存在容量不足错误:
kubectl get events | grep InsufficientCapacityError
Karpenter 会将不可用实例缓存 3 分钟。扩大节点池中允许的实例类型和可用区可以提升获得容量的几率。
注意
Karpenter 启动的竞价型实例不会在 EC2 竞价型请求控制台中显示。Karpenter 将 EC2 CreateFleet API 与 type: instant 结合使用。这些实例会以 spot 生命周期在 EC2 实例控制台中显示。
第 4 步:将预留容量添加到节点池(可选)
要首先使用预留容量,然后再回退到竞价型/按需型容量,请创建一个 ODCR 并将其附加到您的节点类,然后更新第 2 步中的动态节点池以同时允许 reserved 容量。这两条路径的预留 API 调用相同;但节点类附件不同,因为 EKS 自动模式和自行管理的 Karpenter 使用不同种类的节点类。
警告
以下命令会产生预留实例类型费用,直到您使用 aws ec2 cancel-capacity-reservation --capacity-reservation-id <id> 将其取消为止。
创建容量预留:
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
如果出现 InsufficientInstanceCapacity 错误,请将 CR_AZ 更改为其他可用区并重试。
查找容量预留 ID 并将其存储在 Shell 变量中,以用于以下步骤:
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}"
然后根据您的路径应用节点类和节点池更改:
Karpenter 将 reserved 视为最具成本效益的选项,因此会首先启动该容量。预留容量用完后,将会回退到竞价型或按需型容量。
应用更改后,验证 Karpenter 是否会优先使用预留容量并回退到竞价型或按需型容量。部署一个将为每个容器组请求 1 个 GPU 的双副本部署。ODCR 用于 1 个实例,因此第一个容器组会触发 Karpenter 启动预留节点。预留节点无法容纳第二个容器组,会触发 Karpenter 利用竞价型或按需型容量启动另一个节点。
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
与第 3 步中运行并退出的 nvidia-smi 测试容器组不同,此部署会保持容器组运行 (sleep infinity),因此会保持 GPU 且不释放节点。
验证在不同节点上调度的容器组:
kubectl get pods -l app=gpu-overflow-test -o wide
预期输出:
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>
这两个容器组会分别在不同的节点上保持运行。
查看节点声明以查看容量类型:
kubectl get nodeclaims
预期输出:
NAME TYPE CAPACITY ZONE NODE READY AGE gpu-inf-shg5w g6e.xlarge reserved us-east-2a i-0ea91fdeef65b8cb6 True 2m2s gpu-inf-ssnqf g7e.2xlarge spot us-east-2b i-00ccf7ce65cf3f6ca True 112s
会首先启动预留节点,然后在预留容量用完后启动竞价型或按需型节点。
清理测试部署:
kubectl delete deployment gpu-overflow-test
监控
将用于收集集群、节点和 GPU 指标的监控堆栈安装到 Amazon Managed Service for Prometheus(AMP)中,然后使用 Grafana 将其可视化。kube-prometheus-stack Helm 图表会部署 Prometheus 来抓取指标并将其远程写入 AMP,此外还将部署一个自行管理的 Grafana 来用于控制面板。NVIDIA DCGM Exporter 会添加 GPU 特定的指标(利用率、内存、温度、功耗、NVLink、张量活动)。
默认情况下,Prometheus、Grafana 和运算符会着陆于非 GPU 节点,因为 GPU 节点带有 nvidia.com/gpu:NoSchedule 污点。节点导出器和 DCGM Exporter 都在 GPU 节点上运行,因此我们可以抓取整个实例集的主机和 GPU 指标。
如果您打开了新终端,请设置集群名称和区域:
export CLUSTER_NAME=ai-eks-docs export AWS_REGION=us-east-2
创建 AMP 工作区
创建一个 AMP 工作空间以存储指标:
aws amp create-workspace \ --alias "amp-ws-${CLUSTER_NAME}" \ --region ${AWS_REGION}
获取工作区 ID:
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}"
获取远程写入端点:
AMP_ENDPOINT=$(aws amp describe-workspace \ --workspace-id ${AMP_WORKSPACE_ID} \ --query 'workspace.prometheusEndpoint' \ --output text \ --region ${AWS_REGION}) echo "AMP Endpoint: ${AMP_ENDPOINT}"
创建 IAM 策略和 EKS 容器组身份关联
创建一个 IAM 策略,以允许 Prometheus 远程写入指标并允许 Grafana 查询这些指标:
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}"
为 Prometheus 和 Grafana 创建监控命名空间和服务账户:
kubectl create namespace monitoring kubectl create serviceaccount amp-iamproxy-ingest-service-account -n monitoring kubectl create serviceaccount grafana-sa -n monitoring
创建 EKS 容器组身份关联以将服务账户关联到 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}
验证这两个 EKS 容器组身份关联是否均已创建:
eksctl get podidentityassociation --cluster ${CLUSTER_NAME} --region ${AWS_REGION}
预期输出应在 monitoring 命名空间中同时包含 amp-iamproxy-ingest-service-account 和 grafana-sa。
安装 kube-prometheus-stack
添加 Helm 存储库:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update
该值文件省略了 Prometheus、Grafana 和运算符的 nodeSelector:GPU 节点的 nvidia.com/gpu:NoSchedule 污点导致它们不能着陆于 GPU 节点,因此默认情况下会着陆于系统或通用池中。节点导出器使用通配符容差,因此可以在每个节点(包括 GPU 节点)上运行,以收集整个实例集的指标。
创建值文件:
cat << EOF > /tmp/kube-prometheus-values.yaml prometheus: serviceAccount: create: false name: amp-iamproxy-ingest-service-account prometheusSpec: serviceAccountName: amp-iamproxy-ingest-service-account remoteWrite: - url: "${AMP_ENDPOINT}api/v1/remote_write" sigv4: region: "${AWS_REGION}" queueConfig: maxSamplesPerSend: 1000 maxShards: 200 capacity: 2500 retention: 5h scrapeInterval: 30s evaluationInterval: 30s podMonitorSelectorNilUsesHelmValues: false serviceMonitorSelectorNilUsesHelmValues: false alertmanager: enabled: false grafana: enabled: true serviceAccount: create: false name: grafana-sa grafana.ini: auth.sigv4: enabled: true sidecar: datasources: defaultDatasourceEnabled: false plugins: - grafana-amazonprometheus-datasource additionalDataSources: - name: Amazon-Managed-Prometheus type: grafana-amazonprometheus-datasource access: proxy url: "${AMP_ENDPOINT}" isDefault: true jsonData: sigV4Auth: true defaultRegion: "${AWS_REGION}" sigV4Region: "${AWS_REGION}" editable: true dashboardProviders: dashboardproviders.yaml: apiVersion: 1 providers: - name: default orgId: 1 folder: 'GPU Monitoring' type: file disableDeletion: false editable: true options: path: /var/lib/grafana/dashboards/default dashboards: default: nvidia-dcgm: gnetId: 25261 revision: 1 datasource: - name: DS_PROMETHEUS value: Amazon-Managed-Prometheus vllm: gnetId: 25263 revision: 1 datasource: - name: DS_PROMETHEUS value: Amazon-Managed-Prometheus prometheus-node-exporter: tolerations: - operator: Exists EOF
验证变量是否已正确填充:
grep -E "url:|region:|tolerations:" /tmp/kube-prometheus-values.yaml
您应会看到完整的 AMP 端点 URL(以 https://aps-workspaces… 开头)、您所在的区域以及节点导出器 tolerations: 行。如果有任何为空,请重新导出变量并重新创建该文件。
安装图表:
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \ --namespace monitoring \ -f /tmp/kube-prometheus-values.yaml
验证容器组是否正在运行:
kubectl get pods -n monitoring
预期输出:
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
该堆栈会部署以下组件:
-
Prometheus(StatefulSet):抓取指标并将其远程写入 AMP
-
Grafana:控制面板和可视化组件,已预先配置 AMP 数据来源
-
kube-state-metrics:生成有关 Kubernetes 对象状态的指标(容器组状态、资源请求量/限制、节点声明状态)
-
节点导出器(DaemonSet,每个节点一个):收集主机级别指标(CPU、内存、磁盘、网络)
-
运算符:管理 Prometheus 和 Alertmanager 自定义资源
Alertmanager 在此设置中处于已禁用状态。
访问 Grafana
打开一个单独的终端和端口转发来访问 Grafana:
kubectl port-forward svc/kube-prometheus-stack-grafana 3000:80 -n monitoring
在浏览器中打开 http://localhost:3000admin 和来自以下命令的密码登录:
kubectl --namespace monitoring get secrets kube-prometheus-stack-grafana -o jsonpath="{.data.admin-password}" | base64 -d ; echo
要验证指标管道是否端对端正常运行,请执行以下操作:
-
导航至连接 > 数据来源,并确认已将
Amazon-Managed-Prometheus作为默认数据来源列出。在 Grafana 中验证 AMP 数据来源
-
导航至 Drilldown > 指标,然后搜索
up指标。您应会看到集群抓取目标的结果。在 Grafana 中验证
up指标
如果 up 显示结果,则说明管道(集群 → Prometheus → AMP → Grafana)在正常运行。
部署用于 GPU 指标的 DCGM Exporter
kube-prometheus-stack 会收集节点级别的 CPU 和内存指标,但不会收集 GPU 指标。NVIDIA DCGM Exporter 会添加 GPU 利用率、内存使用情况、温度、功耗、NVLink、张量活动等指标。
helm repo add gpu-helm-charts https://nvidia.github.io/dcgm-exporter/helm-charts helm repo update
设置路径的 GPU 节点选择器键。EKS 自动模式和自行管理的 Karpenter 使用不同的标签键来指示 GPU 制造商。
创建 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
customMetrics 字段使用扩展指标集覆盖 DCGM Exporter 的默认指标集,该扩展指标集包括 NVLink 带宽、张量活动、PCIe 吞吐量、ECC 误差和热节流等指标。对于推理工作负载,这有助于您了解 GPU 计算单元是否已完全利用,GPU 是否由于批处理大小过小而在请求之间处于空闲状态,CPU 和 GPU 之间的数据传输是否存在瓶颈,热节流是否会导致延迟峰值,以及还有多少 GPU 内存余量可用于大型批处理。
安装 DCGM Exporter:
helm install dcgm-exporter gpu-helm-charts/dcgm-exporter \ --namespace monitoring \ -f /tmp/dcgm-exporter-values.yaml
tolerations 允许导出器在您于第 2 步中预调配的 GPU 污点节点上运行。带有 release: kube-prometheus-stack 标签的 serviceMonitor 可确保 Prometheus 会自动发现并抓取它。
验证 DCGM Exporter DaemonSet:
kubectl get daemonset dcgm-exporter -n monitoring
GPU 节点运行后,您应会看到一个处于就绪状态的容器组。要验证 DCGM 指标,请导航到 Grafana 中的 Drilldown > 指标并搜索 DCGM_。
在 Grafana 中验证 DCGM 指标
要查看控制面板,请导航至控制面板 > GPU 监控 > NVIDIA DCGM Exporter 控制面板。
Grafana 中的 NVIDIA DCGM Exporter 控制面板
模型权重 S3 存储桶
创建一个用于存储模型权重的 Amazon S3 存储桶,并配置 EKS 容器组身份关联,以便工作负载容器组可以对其进行读写。
如果您打开了新终端,请设置集群名称和区域:
export CLUSTER_NAME=ai-eks-docs export AWS_REGION=us-east-2
创建 S3 存储桶
使用随机后缀创建存储桶以避免名称冲突:
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}
2023 年 1 月之后创建的 S3 存储桶会默认启用服务器端加密(AES256)和屏蔽公共访问权限功能。
配置 EKS 容器组身份以访问 S3
在 default 命名空间中创建一个 model-storage-sa 服务账户、一个限定于该模型存储桶的 IAM 策略以及一个将两者关联起来的 EKS容器组身份关联。设置 serviceAccountName: model-storage-sa 的工作负载容器组将能够在该存储桶中读写。
kubectl create serviceaccount model-storage-sa
创建 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}"
注意
此策略将授予验证步骤所需的 s3:DeleteObject 和 s3:PutObject 权限。对于仅读取模型权重的生产推理容器组,请移除 s3:PutObject 和 s3:DeleteObject 以遵循最低权限原则。
创建 EKS 容器组身份关联。eksctl 会创建具有正确信任策略的 IAM 角色并将其关联到该服务账户:
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}
验证关联:
eksctl get podidentityassociation --cluster ${CLUSTER_NAME} --region ${AWS_REGION}
输出的 default 命名空间中应包含 model-storage-sa 关联。
使用 model-storage-sa 账户运行具有 AWS CLI 映像的一次性容器组,以确认 EKS 容器组身份已上线并且能够正常访问 S3:
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
等待容器组完成并检查日志:
kubectl wait --for=jsonpath='{.status.phase}'=Succeeded pod/s3-test --timeout=300s kubectl logs s3-test
预期输出:
=== 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调用方身份通过 EKS 容器组身份确认该容器组已代入了 ${CLUSTER_NAME}-model-storage-role 角色。S3 命令会确认读取和写入权限。
清理测试容器组:
kubectl delete pod s3-test
后续步骤
集群准备就绪后,您可以继续加载和服务模型,以部署大语言模型并与推理端点进行互动。
清理
提示
如果您计划继续完成本指南的后续章节,请跳过完整清理。请仅在操作完成后再运行完整清理。
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
如果您创建了 ODCR,请先将其取消:
INSTANCE_TYPE="g6e.4xlarge" CAPACITY_RESERVATION_ID=$(aws ec2 describe-capacity-reservations \ --filters "Name=state,Values=active" "Name=instance-type,Values=${INSTANCE_TYPE}" \ --query 'CapacityReservations[0].CapacityReservationId' \ --output text \ --region ${AWS_REGION}) aws ec2 cancel-capacity-reservation --capacity-reservation-id ${CAPACITY_RESERVATION_ID}
重要
取消预留不会终止正在运行的实例。在终止之前,这些实例将继续按标准的按需费率收费。请首先删除部署以耗尽预留节点,然后再将其取消。
查找 IAM 策略 ARN:
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}"
查找 AMP 工作区 ID:
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}"
卸载 DCGM Exporter Helm 发行版:
helm uninstall dcgm-exporter -n monitoring
卸载 kube-prometheus-stack Helm 发行版:
helm uninstall kube-prometheus-stack -n monitoring
删除 Prometheus 摄取服务账户的 EKS 容器组身份关联:
eksctl delete podidentityassociation \ --cluster ${CLUSTER_NAME} \ --namespace monitoring \ --service-account-name amp-iamproxy-ingest-service-account \ --region ${AWS_REGION}
删除 Grafana 服务账户的 EKS 容器组身份关联:
eksctl delete podidentityassociation \ --cluster ${CLUSTER_NAME} \ --namespace monitoring \ --service-account-name grafana-sa \ --region ${AWS_REGION}
删除 Prometheus 和 Grafana 使用的 IAM 策略:
aws iam delete-policy --policy-arn ${AMP_POLICY_ARN}
删除 AMP 工作区:
aws amp delete-workspace --workspace-id ${AMP_WORKSPACE_ID} --region ${AWS_REGION}
删除监控命名空间:
kubectl delete namespace monitoring
查找模型存储桶名称:
MODEL_BUCKET=$(aws s3api list-buckets \ --query "Buckets[?starts_with(Name, '${CLUSTER_NAME}-models-')].Name | [0]" \ --output text) echo "Model bucket: ${MODEL_BUCKET}"
查找 IAM 策略 ARN:
POLICY_ARN=$(aws iam list-policies \ --scope Local \ --query "Policies[?PolicyName=='${CLUSTER_NAME}-model-storage-policy'].Arn" \ --output text) echo "Policy ARN: ${POLICY_ARN}"
删除 S3 模型存储桶以及其中的所有对象:
aws s3 rb s3://${MODEL_BUCKET} --force
删除 EKS 容器组身份关联:
eksctl delete podidentityassociation \ --cluster ${CLUSTER_NAME} \ --namespace default \ --service-account-name model-storage-sa \ --region ${AWS_REGION}
删除 IAM 策略:
aws iam delete-policy --policy-arn ${POLICY_ARN}
删除 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