View a markdown version of this page

使用 CLIs 為 AI/ML 工作負載設定 Amazon EKS 叢集 - Amazon EKS

協助改進此頁面

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

若要為本使用者指南貢獻內容,請點選每個頁面右側面板中的在 GitHub 上編輯此頁面連結。

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

使用 CLIs 為 AI/ML 工作負載設定 Amazon EKS 叢集

提示

註冊即將舉行的 Amazon EKS AI/ML 研討會。

本節將逐步引導您建立透過 CLI 命令在 Amazon EKS 上執行訓練或推論工作負載所需的基礎設施。這些步驟包括建立 EKS 叢集、使用 EKS Auto Mode 或 Karpenter 啟用 GPU 的節點、使用 Prometheus 和 Grafana 的監控堆疊,以及用於模型權重的 Amazon S3 儲存。

如需這些功能如何在 EKS 叢集中佈建和自動擴展 EC2 執行個體的詳細資訊,請參閱 EKS Auto ModeKarpenter 的文件。 EC2

高階架構和工作流程

高階架構顯示具有 Karpenter NodeClass 和 NodePool 的 EKS 叢集、寫入 Amazon Managed Service for Prometheus 的 Grafana 和 Prometheus 監控堆疊、用於模型權重的 Amazon S3 儲存貯體,以及編號工作流程步驟

圖表顯示本節設定的 AWS 高階架構。右側的編號步驟指出您在以下步驟中完成組態的順序。

先決條件

重要

您在本教學課程中建立的資源,包括 EKS 叢集、GPU 執行個體、Application Load Balancer 和 Amazon Managed Service for Prometheus,都會產生費用。當您完成時刪除資源,以避免持續收費。

  • kubectl >= 1.36。如需設定說明,請參閱 設定 kubectl 和 eksctl

  • AWS CLI >= 2.27。如需設定說明,請參閱安裝

  • Helm >= 3.14。如需設定說明,請參閱設定 Helm

  • jq。 如需設定說明,請參閱下載 jq

  • eksctl >= 0.227.0。如需設定說明,請參閱 eksctl 文件中的安裝

驗證您的eksctl版本:

eksctl version

如果您使用的版本早於 0.227.0,請遵循 eksctl 安裝指南升級至最新版本。

設定環境變數

在這些步驟中保持以下叢集名稱和 AWS 區域一致。變更它可能會導致後續命令以錯誤 EKS 叢集為目標。

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

使用所有可用的可用 AZs 可改善容錯能力,並增加取得 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
重要

cac1-az3 排除可用區域 use1-az3、 和 usw1-az2,因為 Amazon EKS 不支援在這些區域中放置控制平面。在任何這些區域中建立具有子網路的叢集會導致 UnsupportedAvailabilityZoneException

預期的輸出結果:

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

輸出中的 AZs 會因區域而異。此範例顯示 us-east-2區域的可用 AZs。

建立叢集和 GPU NodePool

本節提供兩種建立 EKS 叢集和 GPU 節點的路徑,如下圖所示。在整個指南中僅選擇一個選項。

  • EKS Auto Mode — 除了核心聯網、儲存和負載平衡附加元件之外,EKS Auto Mode 還包含和管理訓練和推論工作負載的下列功能:EKS 節點監控代理程式、自動節點修復、快速容器提取的 SOCI 快照器,以及預設 NodeClass 的 GPU 準備程度。NVIDIA 裝置外掛程式包含在 Bottlerocket 加速 AMI 中,EKS Auto Mode 用於已啟用 GPU 的節點。

  • 自我管理 Karpenter:在沒有 EKS Auto Mode 的 EKS 叢集上,您必須負責安裝和設定訓練和推論工作負載所需的元件。這包括聯網附加元件 (VPC CNI、CoreDNS、kube-proxy)、Karpenter、EKS 節點監控代理程式、NVIDIA 裝置外掛程式,以及用於快速容器提取的 SOCI 快照器。

EKS 叢集選項:EKS Auto Mode 和自我管理 Karpenter

兩個叢集選項的Side-by-side比較:具有 NodePool 的 EKS Auto Mode 叢集,以及具有自我管理 Karpenter、CoreDNS、VPC CNI、NVIDIA 裝置外掛程式、EKS Pod Identity Agent、Node Monitoring Agent、kube-proxy 和 NodeClass 和 NodePool 的 EKS 標準叢集

在下列每個步驟中,選擇路徑 (EKS Auto Mode、Karpenter) 並完全遵循。完成所選路徑的步驟後,您將擁有具有 GPU NodePool 的 EKS 叢集,準備好排程 GPU 工作負載。

步驟 1:建立叢集

首先建立 EKS 叢集,並安裝 GPU 工作負載所需的叢集元件。

使用 EKS Auto Mode 時,單一eksctl create cluster --enable-auto-mode命令會佈建適用於 GPU 工作負載的 EKS 叢集。

使用自我管理的 Karpenter,eksctl create cluster命令會佈建核心聯網附加元件,然後需要額外的步驟,才能透過 Karpenter 功能閘道啟用自動節點修復、安裝 EKS 節點監控代理程式,以及安裝 NVIDIA 裝置外掛程式。

EKS Auto Mode

建立 EKS Auto Mode 叢集

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

此命令需要幾分鐘的時間才能完成。完成後, eksctl會自動更新您的 kubeconfig 檔案,以使用新佈建的叢集。驗證叢集是否正常運作:

kubectl get pods --all-namespaces

預期的輸出結果:

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

在 EKS Auto 模式中,VPC CNI、kube-proxy 和 CoreDNS 會以受管元件的形式執行,而不會在 中顯示為 Podkube-system

建立預設 StorageClass

GPU 工作負載通常需要持久性儲存,例如快取模型權重,因此 Kubernetes 不會在每次重新啟動 Pod 時重新下載它們。EKS Auto Mode 包含內建的區塊儲存功能,因此您不會安裝 Amazon EBS CSI 驅動程式。建立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.eks.amazonaws.com volumeBindingMode: WaitForFirstConsumer parameters: type: gp3 encrypted: "true" EOF

此命令會建立 gp3StorageClass,並使用 storageclass.kubernetes.io/is-default-class註釋將其標記為叢集預設值。省略的任何 PersistentVolumeClaim storageClassName都會使用此 StorageClassvolumeBindingMode: WaitForFirstConsumer 設定會延遲磁碟區建立,直到 Kubernetes 排程 Pod,因此 EBS 磁碟區會登陸與 Pod 相同的可用區域。

Self-managed Karpenter

將 Helm 驗證為公有 ECR

eksctl 從 Amazon Public ECR 提取 Karpenter Helm Chart。在建立叢集之前進行驗證,以避免 Helm 安裝步驟發生 403 錯誤:

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

Public ECR 是在 中託管的全域服務us-east-1。無論您的 EKS 叢集位於哪個區域,都可以--region us-east-1在此處使用 。

預期的輸出: Login Succeeded

使用 Karpenter 建立 EKS 叢集

將您的 Karpenter 版本存放在 環境變數中,以供日後使用。如需最新的 Karpenter 版本,請參閱 GitHub 上的 Karpenter 版本

export KARPENTER_VERSION=1.14.0
範例叢集組態 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

system 受管節點群組會列出數個相同大小的執行個體類型 (8 個 vCPU、32 GiB),而非單一類型。如果某個類型在可用區域中暫時無法使用,節點群組的 Auto Scaling 群組會回復為另一種類型,以避免InsufficientInstanceCapacity啟動失敗。對於隨需受管節點群組,所有列出的執行個體類型都必須具有相同的 vCPU 和記憶體,以便節點大小一致。

使用組態檔案建立叢集:

eksctl create cluster -f /tmp/cluster-karpenter.yaml

此命令大約需要 15 分鐘。它使用專用於託管附加元件和 Karpenter 控制器的受管節點群組來建立 EKS 叢集。Karpenter 安裝時已啟用 Spot 中斷佇列,因此可以處理 Spot 中斷和重新平衡建議。autoModeConfig.enabled: false 設定會明確表示此叢集不使用 EKS Auto 模式,因此在此路徑中安裝的 Karpenter 元件負責節點管理。

叢集也會取得 EKS Pod Identity AgentEKS 節點監控代理程式,以及安裝為 EKS 附加元件的 Amazon EBS CSI 驅動程式。本指南稍後會使用 EKS Pod Identity。EKS 節點監控代理程式會在每個節點上執行,並讀取核心日誌以設定節點條件,例如 AcceleratedHardwareReadyKernelReadyNetworkingReady,Karpenter 自動節點修復會使用這些條件來決定何時取代運作狀態不佳的節點。

驗證叢集是否正常運作:

kubectl get pods --all-namespaces

預期的輸出包括 Karpenter、CoreDNS、kube-proxy、aws-node (VPC CNI)、EKS Pod Identity Agent 和 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

啟用 Karpenter 功能閘道

EKS Auto Mode 預設會啟用自動節點修復和靜態容量。在自我管理的 Karpenter 上,您必須明確啟用NodeRepair特徵閘道,以及靜態 NodePools 的StaticCapacity閘道,其會維護透過 的固定節點計數,spec.replicas而不是擴展以回應待定的 Pod。在 Karpenter 中,這兩個閘道預設為 Alpha 和 off。下列命令會修補 Karpenter 部署以啟用兩個閘道。更新部署環境會觸發推出 Karpenter Pod:

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

預期的輸出結果:

deployment.apps/karpenter env updated

等待 Karpenter Pod 推出:

kubectl rollout status deployment/karpenter -n karpenter

安裝 NVIDIA 裝置外掛程式

EKS 最佳化 AL2023 AMI 不包含 NVIDIA 裝置外掛程式 (不同於 EKS Auto Mode 使用的 Bottlerocket AMI)。透過 Helm 安裝它,讓 GPU 資源可與叢集上的 Pod 搭配使用。

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:停用不使用的 Mellanox OFED (InfiniBand) 檢查 AWS

  • nodeSelector.amiFamily: al2023:僅將 DaemonSet 範圍限定為 AL2023 節點 (Bottlerocket 已內建外掛程式)

  • gfd.enabled: true:啟用 GPU Feature Discovery 標籤 (nvidia.com/gpu.productnvidia.com/gpu.memory等)

確認已安裝 NVIDIA 裝置外掛程式。預期在佈建具有相符標籤的 GPU NodePool 之前,沒有任何裝置外掛程式 Pod。

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

預期的輸出結果:

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

接著,建立一般用途 NodePool。system 受管節點群組會執行附加元件和控制器。新增一般用途 KarpenterNodePool,讓非 GPU 工作負載可以隨需擴展,而無需登陸system節點。GPU NodePool稍後會在步驟 2 中建立。

一般用途 EC2NodeClass 和 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

此 NodePool 沒有污點,因此任何不容忍 GPU 污點的 Pod 都可以在其上排程。

建立預設 StorageClass

GPU 工作負載通常需要持久性儲存,例如快取模型權重,因此 Kubernetes 不會在每次重新啟動 Pod 時重新下載它們。Amazon EBS CSI 驅動程式已在此步驟稍早的叢集組態中由 addons:區塊安裝,因此您只需要建立 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

此命令會建立 gp3StorageClass,並使用 storageclass.kubernetes.io/is-default-class註釋將其標記為叢集預設值。省略的任何 PersistentVolumeClaim storageClassName都會使用此 StorageClassvolumeBindingMode: WaitForFirstConsumer 設定會延遲磁碟區建立,直到 Kubernetes 排程 Pod,因此 EBS 磁碟區會登陸與 Pod 相同的可用區域。

警告

對於 EKS Auto Mode 和自我管理 Karpenter 路徑,自動節點修復的行為與 NodePools 佈建的節點相同。EKS Auto Mode 和 Karpenter 中的自動節點修復是一種強而有力的中斷方法,可略過 PodDisruptionBudgets、karpenter.sh/do-not-disrupt註釋和 terminationGracePeriod。自動節點修復會等待 10 分鐘,再將條件AcceleratedHardwareReady設為 的節點取代為 ,False其他修復條件取代為 30 分鐘。

設定負載平衡

本指南的後續步驟透過 an AWS Application Load Balancer (ALB) 公開 Grafana (以及推論演練中的模型端點)。立即設定負載平衡先決條件,讓這些區段無需進一步設定Ingress即可建立 。

ALB 會根據 AWS 資源標籤放置在 VPC 子網路中。用於面向網際網路的負載平衡器的公有子網路必須加上標籤 kubernetes.io/role/elb = 1,而用於內部負載平衡器的私有子網路必須加上標籤 kubernetes.io/role/internal-elb = 1。由於您使用 建立此叢集eksctl,因此這些標籤已存在於eksctl建立的子網路上。如果您使用自己的 VPC 或匯入的子網路,請手動標記它們。如需詳細資訊,請參閱標記 EKS 自動模式的子網路

建立負載平衡器 IngressClass

其餘設定會因路徑而有所不同。EKS Auto Mode 包含內建的 ALB 控制器,因此您可以IngressClass自行建立 。自我管理的 Karpenter 需要使用 Helm 安裝 AWS Load Balancer控制器,Helm Chart IngressClass會為您建立 。

EKS Auto Mode

EKS Auto Mode 包含內建的 ALB 控制器,因此您不會安裝任何其他元件。建立指向內建控制器albIngressClassIngress 您稍後建立的每個 都會依名稱參考此類別,並透過註釋設定自己的方案和其他選項。

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

AWS Load Balancer控制器不是 EKS 受管的附加元件,因此無法像 EBS CSI 驅動程式那樣進入eksctl叢集組態addons:區塊。使用 Helm 安裝它。

下載 IAM 政策

控制器需要 IAM 許可才能建立和管理 ALBs。下載官方 IAM 政策 JSON:

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

建立 IAM 政策:

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

建立 Pod Identity 關聯

叢集已在步驟 1 中安裝eks-pod-identity-agent附加元件,因此可使用 EKS Pod Identity。建立將 IAM 政策繫結至控制器服務帳戶的 Pod Identity 關聯:

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

使用 Helm 安裝

新增 EKS 圖表 Helm 儲存庫:

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

查詢叢集的 VPC ID。Helm 值需要它,以便控制器可以探索子網路:

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

安裝控制器。nodeSelector 和 容錯能力會將控制器與叢集關鍵基礎設施放在system受管節點群組上,而不是與 GPU 或一般用途 Karpenter 啟動的節點競爭容量:

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"

驗證控制器是否正在執行。它應該報告兩個可用的複本:

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

驗證 IngressClass

Helm Chart 會建立IngressClass名為 的 alb作為控制器安裝的一部分,並指向自我管理的控制器 ingress.k8s.aws/alb。您不需要手動建立它。確認它存在:

kubectl get ingressclass alb

預期的輸出結果:

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

這兩個路徑現在都具有 alb IngressClass。Grafana 和推論區段透過每個Ingress註釋參考ingressClassName: alb和設定 ALB 結構描述、source-IP 允許清單和其他行為。

步驟 2:建立動態 GPU NodePool

定義 NodePool,使用 Spot 容量搭配隨需做為備用,以動態方式佈建產生大於 4 且小於 7 的 G 系列 GPU 執行個體。EKS Auto Mode 和 Karpenter 路徑都使用相同的 NodePool API,唯一的區別在於其指向的 NodeClass。在 EKS Auto 模式中,綁定的 default NodeClass 已選取正確的 AMI 並設定 SOCI 平行提取,因此 NodePool 是您建立的唯一物件。在自我管理的 Karpenter 中,您也需要可EC2NodeClass固定 AMI 並調校 SOCI 的自訂。

重要

G7 EC2 執行個體類型需要 NVIDIA 驅動程式 595 版或更新版本。EKS 最佳化加速 AMIs 目前包含不支援 G7 執行個體的 NVIDIA 驅動程式 580 版。此步驟中的 NodePool 會將執行個體產生限制為小於 7,讓 Karpenter 不會選取 G7 執行個體。若要搭配 Amazon EKS 使用 G7 執行個體,您必須使用 NVIDIA 驅動程式 595 版建置自訂 AMI。如需詳細資訊,請參閱針對 GPU 執行個體使用 EKS 最佳化AMIs

EKS Auto Mode

在 EKS Auto 模式中,綁定的 default NodeClass 會自動選取 GPU 執行個體的 Bottlerocket AMI,其中包括預先安裝的 NVIDIA 驅動程式、NVIDIA 裝置外掛程式和 SOCI 平行提取。您只需要套用參考 NodeClass 的 default NodePool: 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

此 NodePool 會佈建產生大於 4 且小於 7 的 G 系列 GPU 執行個體 (G5G6e 等)。EKS Auto Mode 會在這些限制內選擇執行個體類型。

Self-managed Karpenter

自我管理的 Karpenter 不包含預設 NodeClass。您首先會建立 EC2NodeClass 來鎖定 EKS 最佳化 NVIDIA AL2023 AMI 別名、透過FastImagePull功能閘道啟用 SOCI,並設定 instanceStorePolicy: RAID0將容器化映像快取移至本機 NVMe。然後,您可以建立參考它的 NodePool。

建立 EC2NodeClass

範例
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: RAID0 將本機 NVMe 磁碟組合成 RAID-0 陣列。al2023@latest AMI 別名解析為 EKS 最佳化 AL2023 AMI。當 Karpenter 啟動 GPU 執行個體類型時,會自動選取 AL2023_x86_64_NVIDIA 加速變體,其中包含預先安裝的 NVIDIA 驅動程式。

FastImagePull 功能閘道會啟用 SOCI 快照器平行提取模式,同時下載和解壓縮映像層。這符合 G、P 和 Trn 執行個體系列中的 EKS 自動模式行為。

如需更多 SOCI 調校選項 (每個映像的並行下載、區塊大小等),請參閱 Karpenter SOCI 藍圖

驗證 EC2NodeClass:

kubectl get ec2nodeclass gpu-inf

預期的輸出:READY True。如果為 False,請執行 kubectl describe ec2nodeclass gpu-inf並檢查缺少子網路或安全群組標籤的條件。

建立 GPU NodePool

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

節點範本上的amiFamily: al2023標籤是 NVIDIA 裝置外掛程式 DaemonSet 用來選取這些節點的標籤。Karpenter 會在這些限制內選擇執行個體類型。nvidia.com/gpu:NoSchedule 污點可確保只會在這些節點上排程符合 GPU 資格的 Pod。

驗證已建立 NodePool:

kubectl get nodepool gpu-inf

預期的輸出結果:

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

在自我管理 Karpenter 路徑上,NODECLASS 欄會顯示 ,gpu-inf而非 default

步驟 3:使用範例 Pod 進行測試

使用 Pod 測試 GPU NodePool 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

確認 Pod 已排程並成功完成。

kubectl get pods

預期的輸出結果:

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

STATUS: 已完成表示 nvidia-smi 命令已執行並結束。檢查 Pod 日誌以查看節點偵測到的 GPU。

kubectl logs nvidia-smi

預期的輸出結果:

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

輸出會顯示 GPU 模型、驅動程式版本、CUDA 版本和可用的記憶體。在此範例中,Karpenter 佈建了具有 NVIDIA L4 GPU 和 24 GB 記憶體的 G6 執行個體。42C 是目前的 GPU 溫度,而 P8 是低功耗閒置狀態,這是預期的,因為沒有工作負載正在使用 GPU。16W / 72W 顯示相較於最大功率容量的目前耗電量,而 0MiB / 23034MiB 顯示相較於總可用容量使用的目前 GPU 記憶體。由於 Pod 剛執行 nvidia-smi 並結束,因此沒有工作負載使用 GPU,因此記憶體為 0,且電源處於閒置狀態。NVIDIA GPU 驅動程式版本 (580.159.03) 來自 Bottlerocket AMI,而 CUDA 版本 (13.0) 來自容器映像。GPU 模型和記憶體會根據 Karpenter 選取的執行個體類型而有所不同。G5 執行個體具有 NVIDIA A10G GPUs (24 GB)、G6 執行個體具有 NVIDIA L4 GPUs (24 GB),而 G6e 執行個體具有 NVIDIA L40S GPUs (48 GB)。

若要了解 Karpenter 和 Kubernetes 排程器如何協調以佈建節點並放置 Pod,請檢查 Pod 的生命週期事件:

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

這些事件會顯示 Pod 排程序列:Pod 一開始無法排程,因為沒有 GPU 節點 (FailedScheduling)、Karpenter 會指定新的 NodeClaim (Nominated)、排程器會在節點就緒時指派 Pod (排程),然後提取並啟動容器映像。EKS Auto Mode 在 G、P 和 Trn 執行個體上安裝並設定 SOCI (可擴展的 OCI) 平行提取。請注意,由於 SOCI 平行提取,容器映像在 2 秒 (1.237 秒) 內從 ECR 提取。

NodeClaim 是 Karpenter 建立來佈建特定節點的請求。它會顯示執行個體類型、容量類型、AZ,以及節點是否已就緒。

kubectl get nodeclaims

預期的 NodeClaim 輸出:

NAME            TYPE         CAPACITY   ZONE         NODE                  READY   AGE
gpu-inf-vxcnj   g6.4xlarge   spot       us-east-2c   i-0fb17a09bc4203164   True    51s

執行個體類型和 AZ 會有所不同。產生大於 4 且小於 7 的任何 G 系列執行個體都符合資格。

中的FailedCreatePodSandBox警告kubectl describe pod nvidia-smi是暫時性且預期的。VPC CNI 會在節點聯結後以非同步方式初始化,而 kubelet 會自動重試。如果 Pod 保留在 中ContainerCreating,請使用 檢查節點事件kubectl describe node <node-name>

提示

如果沒有出現節點,請檢查容量不足錯誤:

kubectl get events | grep InsufficientCapacityError

Karpenter 快取無法使用的方案 3 分鐘。擴大 NodePool 中允許的執行個體類型和可用AZs會增加登陸容量的機會。

注意

Karpenter 啟動的 Spot 執行個體不會出現在 EC2 Spot 請求主控台中。Karpenter 搭配 使用 EC2 CreateFleet APItype: instant。執行個體會以spot生命週期顯示在 EC2 執行個體主控台中。

步驟 4:將預留容量新增至 NodePool (選用)

若要先搭配 Spot/隨需備用使用預留容量,請建立隨需容量保留 (ODCR),並將其連接至 NodeClass,然後從步驟 2 更新動態 NodePool,以允許reserved容量。兩個路徑的保留 API 呼叫相同;NodeClass 連接不同,因為 EKS Auto Mode 和自我管理 Karpenter 使用不同的 NodeClass 類型。

警告

下列命令會產生預留執行個體類型的費用,直到您使用 將其取消為止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}"

然後為您的路徑套用 NodeClass 和 NodePool 變更:

EKS Auto Mode

在 EKS Auto 模式中,綁定的 default NodeClass 是唯讀的,因此請建立參考保留的自訂 NodeClass,然後更新 NodePool 以指向 NodeClass,並將reserved容量新增至capacity-type清單。

範例自訂 NodeClass YAML
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

kubernetes.io/role/internal-elb: "1" 標籤可確保節點僅在私有子網路中啟動。

更新 NodePool 以使用 ODCR 支援的 NodeClass,並包含 reserved做為容量類型:

範例已更新 NodePool YAML
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

對於自我管理的 Karpenter,重新套用EC2NodeClass您在步驟 2 中建立並capacityReservationSelectorTerms新增的 。欄位名稱和形狀符合其他索引標籤中NodeClass顯示的 EKS Auto 模式。

範例已更新 EC2NodeClass YAML
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

從步驟 2 的唯一變更是新capacityReservationSelectorTerms欄位。所有其他欄位保持不變。

更新 NodePool 以包含 reserved做為容量類型:

範例已更新 NodePool YAML
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 reserved將 視為最具成本效益的選項,並優先啟動。一旦保留已滿,就會回到 Spot 或隨需。

套用變更後,請驗證 Karpenter 是否排定保留容量的優先順序,並回到 Spot 或隨需。部署 2 個複本部署,每個 Pod 請求 1 個 GPU。ODCR 適用於 1 個執行個體,因此第一個 Pod 會觸發 Karpenter 啟動預留節點。第二個 Pod 無法容納在預留節點上,並觸發 Karpenter 從 Spot 或隨需容量啟動另一個節點。

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的測試 Pod 不同,此部署會讓 Pod 保持執行 (sleep infinity),以便保留 GPU 且不釋出節點。

驗證在不同節點上排程的 Pod:

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>

兩個 Pod 正在執行中,每個在不同的節點上。

檢查 NodeClaims 以查看容量類型:

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   g6e.2xlarge   spot        us-east-2b   i-00ccf7ce65cf3f6ca   True    112s

預留節點會先啟動,然後在保留已滿時,再啟動 Spot 或隨需節點。

清除測試部署:

kubectl delete deployment gpu-overflow-test

監控

將收集叢集、節點和 GPU 指標的監控堆疊安裝到 Amazon Managed Service for Prometheus (AMP),並使用 Grafana 將其視覺化。kube-prometheus-stack Helm Chart 會將 Prometheus 部署到 AMP 的湊集和遠端寫入指標,以及儀表板的自我管理 Grafana。NVIDIA DCGM Exporter 新增 GPU 特定的指標 (使用率、記憶體、溫度、功率、NVLink、張量活動)。

Prometheus、Grafana 和運算子預設會落在非 GPU 節點上,因為 GPU nvidia.com/gpu:NoSchedule 節點帶有污點。Node-exporter 和 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 Pod 身分關聯

建立允許 Prometheus 遠端寫入指標和 Grafana 查詢它們的 IAM 政策:

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 Pod 身分關聯,將服務帳戶連結至 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 Pod 身分關聯:

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

預期的輸出應在monitoring命名空間grafana-sa中同時包含 amp-iamproxy-ingest-service-account和 。

安裝 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 節點,因此預設會落在系統或一般用途集區上。Node-exporter 使用萬用字元公差,因此它在每個節點上執行,包括 GPU 節點,以在整個機群中收集指標。

值檔案也會設定 Grafana,Ingress因此圖表會使用albIngressClass您在設定負載平衡中建立的 ,為瀏覽器存取佈建面向網際網路的 ALB。alb.ingress.kubernetes.io/inbound-cidrs 註釋會將負載平衡器限制為您自己的 IP 地址,因此請在安裝之前進行設定。

Grafana 可透過 HTTP 使用預設登入資料公開存取

Grafana 包含預設的管理員登入資料,並提供監控資料的完整管理存取權。面向網際網路的負載平衡器會透過純文字 HTTP 將此界面放置在公有網際網路上。自動化掃描器會在幾分鐘內探索公有負載平衡器。您必須使用 alb.ingress.kubernetes.io/inbound-cidrs註釋限制存取,並將 source-IP 允許清單視為最低保護,而非完整保護。同時變更預設的 Grafana 管理員密碼。如需更強的姿勢,請將配置設定為 ,並新增 TLS 憑證internal,以使用內部配置 (只能在 VPC 或連線的 VPN 內存取)。

尋找您的公有 IP 地址,並將其儲存為 /32 CIDR。值檔案會從MY_CIDR環境變數讀取:

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

結果看起來像 203.0.113.4/32。如果您的網路動態指派地址,您的 IP 地址可能會隨著時間而變更,因此請考慮設定更廣泛的範圍,例如 203.0.113.0/24

建立值檔案:

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

驗證變數是否正確填入:

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

您應該會看到完整的 AMP 端點 URL (以 開頭https://aps-workspaces…​) 和您的區域。如果其中一個是空的,請重新匯出變數並重新建立檔案。

安裝圖表:

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

驗證 Pod 正在執行:

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 物件狀態 (Pod 狀態、資源請求/限制、NodeClaim 狀態) 的指標

  • node-exporter (DaemonSet,每個節點一個):收集主機層級指標 (CPU、記憶體、磁碟、網路)

  • 運算子:管理 Prometheus 和 Alertmanager 自訂資源

警示管理員在此設定中已停用。

存取 Grafana

您可以透過面向網際網路 AWS Application Load Balancer(ALB) 存取 Grafana。您不會在此處建立它。kube-prometheus-stack 圖表使用albIngressClass來自設定負載平衡的 ,從值檔案中grafana.ingress組態佈建。Grafana Helm Chart 具有內建Ingress支援,因此不需要單獨的資訊清單。ALB 名為 grafana-ai-eks-docs,帶有標籤 guide: ai-eks-docs,且僅限於您在MY_CIDR安裝時在 中設定的 IP 地址。

Grafana ALB 目標群組需要運作狀態檢查路徑

值檔案中的alb.ingress.kubernetes.io/healthcheck-path註釋會將負載平衡器的運作狀態檢查指向 Grafana /api/health端點,這會傳回 200。如果沒有它,ALB 運作狀態檢查預設為 /,Grafana 會以302重新導向至 的方式回答該檢查/login,導致目標群組將端點報告為運作狀態不佳。

列印負載平衡器 URL。負載平衡器是以非同步方式建立,因此請允許一兩分鐘:

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

在瀏覽器中開啟 URL。從admin下列命令使用使用者名稱和密碼登入:

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

若要驗證指標管道是否端對端運作:

  1. 導覽至連線 > 資料來源,並確認 Amazon-Managed-Prometheus 列為預設資料來源。

    驗證 Grafana 中的 AMP 資料來源

    Grafana Connections 頁面顯示列為預設資料來源的 Amazon-Managed-Prometheus
  2. 導覽至向下切入 > 指標並搜尋指標。 up您應該會看到叢集湊集目標的結果。

    驗證 up Grafana 中的指標

    Grafana 向下切入指標頁面顯示綠色狀態列的向上指標,指出作用中的抓取目標

如果 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 Auto Mode 和自我管理 Karpenter 為 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"

建立 DCGM 匯出工具值檔案:

範例 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 匯出者的預設指標集,其中包含 NVLink 頻寬、張量活動、PCIe 輸送量、ECC 錯誤和熱調節。對於推論工作負載,這有助於您了解 GPU 運算單位是否充分利用、GPU 是否因為批次大小低而在請求之間閒置、CPU 和 GPU 之間的資料傳輸是否為瓶頸、熱調節是否造成延遲峰值,以及大型批次的 GPU 記憶體空間剩餘多少。

安裝 DCGM 匯出工具:

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

允許匯出程式tolerations在您於步驟 2 佈建的 GPU 污點節點上執行。serviceMonitor 具有 release: kube-prometheus-stack標籤的 可確保 Prometheus 自動探索和抓取它。

驗證 DCGM 匯出工具 DaemonSet:

kubectl get daemonset dcgm-exporter -n monitoring

GPU 節點執行後,您應該會看到一個就緒的 Pod。若要驗證 DCGM 指標,請導覽至 Grafana 中的向下切入 > 指標,並搜尋 DCGM_

在 Grafana 中驗證 DCGM 指標

由 DCGM_ 篩選的 Grafana 向下切入指標頁面,顯示 GPU 指標,包括 DCGM_FI_DEV_ECC_SBE_VOL_TOTAL、DCGM_FI_DEV_ENC_UTIL、DCGM_FI_DEV_FB_FREE 和 DCGM_FI_DEV_FB_USED

若要檢視儀表板,請導覽至儀表板 > GPU 監控 > NVIDIA DCGM 匯出工具儀表板

Grafana 中的 NVIDIA DCGM 匯出工具儀表板

Grafana NVIDIA DCGM Exporter Dashboard 顯示 GPU 使用率、GPU 平均溫度、使用的 GPU Framebuffer Mem 和 GPU Power Total 面板

模型權重 S3 儲存貯體

建立 Amazon S3 儲存貯體來存放模型權重,並設定 EKS Pod Identity Association,以便工作負載 Pod 可以讀取和寫入模型權重。

如果您開啟新的終端機,請設定叢集名稱和區域:

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) 和公有存取封鎖。

設定 S3 存取的 EKS Pod 身分

default命名空間中建立 model-storage-sa ServiceAccount、範圍為模型儲存貯體的 IAM 政策,以及連結它們的 EKS Pod 身分關聯。設定的工作負載 Pod 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:PutObject會針對驗證步驟授予 s3:DeleteObject和 。對於只讀取模型權重的生產推論 Pod,請移除 s3:PutObjects3:DeleteObject遵循最低權限。

建立 EKS Pod Identity Association。 會eksctl建立具有正確信任政策的 IAM 角色,並將其連結至 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}

驗證關聯:

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

輸出應該包含 default 命名空間中的model-storage-sa關聯。

使用 model-storage-sa ServiceAccount 使用 AWS CLI 映像執行一次性 Pod,以確認 EKS Pod 身分已連線且 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

等待 Pod 完成並檢查日誌:

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

發起人身分會確認 Pod 透過 EKS Pod 身分擔任該${CLUSTER_NAME}-model-storage-role角色。S3 命令會確認讀取和寫入存取。

清除測試 Pod:

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,請先取消它。查詢保留 ID:

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

取消保留:

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 匯出工具 Helm 版本:

helm uninstall dcgm-exporter -n monitoring

解除安裝 kube-prometheus-stack Helm 版本:

helm uninstall kube-prometheus-stack -n monitoring

刪除 Prometheus 擷取服務帳戶的 EKS Pod 身分關聯:

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

刪除 Grafana 服務帳戶的 EKS Pod 身分關聯:

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 Pod 身分關聯:

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