View a markdown version of this page

CLI を使用して AI/ML ワークロード用の Amazon EKS クラスターを設定する - Amazon EKS

このページの改善にご協力ください

このユーザーガイドに貢献するには、すべてのページの右側のペインにある「GitHub でこのページを編集する」リンクを選択してください。

CLI を使用して 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 のドキュメントを参照してください。

高レベルアーキテクチャとワークフロー

Karpenter NodeClass および NodePool を使用した EKS クラスター、Amazon Managed Service for Prometheus への Grafana および Prometheus モニタリングスタックの書き込み、モデルの重み付け用の Amazon S3 バケット、および番号付きワークフローステップを示す高レベルアーキテクチャ

この図は、このセクションのセットアップの AWS 高レベルアーキテクチャを示しています。右側の番号付きステップは、以下のステップで設定を完了する順序を示しています。

前提条件

eksctl バージョンを確認します。

eksctl version

0.227.0 より前のバージョンを使用している場合は、eksctl インストールガイドに従って最新のリリースにアップグレードします。

環境変数を設定する

これらのステップ全体で、以下のクラスター名と AWS リージョンの一貫性を維持します。変更すると、後続のコマンドが間違った EKS クラスターをターゲットにする可能性があります。

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

利用可能なすべての AZ を使用すると、耐障害性が向上し、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
重要

Amazon EKS はこれらのゾーンでのコントロールプレーン配置をサポートしていないため、アベイラビリティーゾーン use1-az3usw1-az2、および cac1-az3 は除外されます。これらのゾーンのいずれかにサブネットを持つクラスターを作成すると、UnsupportedAvailabilityZoneException が発生します。

正常な出力:

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

出力に表示される AZ はリージョンによって異なります。この例では、us-east-2 リージョンで利用可能な AZ を示しています。

クラスターと GPU NodePool を作成する

このセクションでは、EKS クラスターと GPU 対応ノードを作成するための 2 つのパスを以下の図に示します。ガイド全体で 1 つのオプションのみを選択してください。

  • EKS Auto Mode — EKS Auto Mode には、コアネットワーク、ストレージ、ロードバランシングアドオンに加えて、EKS ノードモニタリングエージェント、自動ノード修復、高速コンテナプル用の SOCI スナップショッター、デフォルトの NodeClass の GPU 準備などのトレーニングおよび推論ワークロードの機能が含まれています。NVIDIA デバイスプラグインは、EKS Auto Mode が GPU 対応ノードに使用する Bottlerocket 高速 AMI に含まれています。

  • セルフマネージド Karpenter — EKS Auto Mode のない EKS クラスターでは、トレーニングおよび推論ワークロードに必要なコンポーネントのインストールおよび設定を自分で行う必要があります。これには、ネットワーキングアドオン (VPC CNI、CoreDNS、kube-proxy)、Karpenter、EKS ノードモニタリングエージェント、NVIDIA デバイスプラグイン、高速コンテナプル用の SOCI スナップショットターが含まれます。

EKS クラスターオプション: EKS Auto Mode とセルフマネージド Karpenter

NodePool を備えた EKS Auto Mode クラスターと、セルフマネージド Karpenter、CoreDNS、VPC CNI、NVIDIA デバイスプラグイン、EKS Pod Identity エージェント、Node Monitoring Agent、kube-proxy、NodeClass および NodePool を備えた EKS 標準クラスターの 2 つのクラスターオプションを並べて比較したもの

以下の各ステップで、パス (EKS Auto Mode、Karpenter) を選択し、一貫してそのパスに従います。選択したパスのステップを完了すると、GPU NodePool を備えた EKS クラスターが GPU ワークロードをスケジュールできるようになります。

ステップ 1: クラスターを作成する

まず、EKS クラスターを作成し、GPU ワークロードに必要なクラスターコンポーネントをインストールします。

EKS Auto Mode では、1 つの 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.35 \ --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 Mode では、VPC CNI、kube-proxy、および CoreDNS はマネージドコンポーネントとして実行され、kube-system ではポッドとして表示されません。

Self-managed Karpenter

Helm をパブリック ECR に認証する

eksctl は、Amazon Public ECR から Karpenter Helm チャートをプルします。Helm のインストールステップで 403 エラーが発生しないように、クラスターを作成する前に認証します。

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

パブリック ECR は、us-east-1 でホストされているグローバルサービスです。EKS クラスターがどのリージョンにあるかに関係なく、ここで --region us-east-1 を使用します。

正常な出力: Login Succeeded

Karpenter で EKS クラスターを作成する

Karpenter バージョンは、後で使用するために環境変数に保存します。最新の Karpenter バージョンについては、GitHub の Karpenter リリースを参照してください。

export KARPENTER_VERSION=1.12.0
cat << EOF > /tmp/cluster-karpenter.yaml apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: ${CLUSTER_NAME} region: ${AWS_REGION} version: "1.35" 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 instanceType: m6i.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 EOF eksctl create cluster -f /tmp/cluster-karpenter.yaml

このコマンドの実行には約 15 分かかります。アドオンと Karpenter コントローラーのホスティング専用のマネージドノードグループを持つ EKS クラスターを作成します。Karpenter は、スポット中断キューを有効にしてインストールされるため、スポット中断と再調整の推奨事項を処理できます。autoModeConfig.enabled: false 設定により、このクラスターが EKS Auto Mode を使用しないことが明示的になるため、このパスにインストールされた Karpenter コンポーネントがノード管理を担当します。

また、クラスターは EKS Pod Identity AgentEKS ノードモニタリングエージェントを EKS アドオンとしてインストールします。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

自動ノード修復を有効にする

EKS Auto Mode は、デフォルトで自動ノード修復を有効にします。セルフマネージド Karpenter では、自動ノード修復は NodeRepair=true 機能ゲートの背後でゲートされるため、明示的に有効にする必要があります。以下のコマンドは、Karpenter デプロイにパッチを適用して NodeRepair=true 機能ゲートを追加します。デプロイ環境を更新すると、Karpenter ポッドのロールアウトがトリガーされます。

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

正常な出力:

deployment.apps/karpenter env updated

Karpenter ポッドがロールアウトするのを待ちます。

kubectl rollout status deployment/karpenter -n karpenter

NVIDIA デバイスプラグインをインストールする

EKS 最適化 AL2023 AMI には NVIDIA デバイスプラグインは含まれていません (EKS Auto Mode で使用される Bottlerocket AMI とは異なります)。Helm 経由でインストールして、クラスターのポッドで GPU リソースを使用できるようにします。

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: AWS が使用しない Mellanox OFED (InfiniBand) のチェックを無効にします

  • nodeSelector.amiFamily: al2023: DaemonSet を AL2023 ノードのみにスコープします (Bottlerocket には既にプラグインが組み込まれています)

  • gfd.enabled: true: GPU Feature Discovery ラベルを有効にします (nvidia.com/gpu.productnvidia.com/gpu.memory など)

NVIDIA デバイスプラグインがインストールされていることを確認します。一致するラベルを持つ GPU NodePool がプロビジョニングされるまで、デバイスプラグインポッドはゼロであることが想定されています。

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

EKS Auto Mode パスとセルフマネージド Karpenter パスの両方において、ノードの自動修復は NodePools によってプロビジョニングされたノードでも同じように動作します。EKS Auto Mode と Karpenter の自動ノード修復は、PodDisruptionBudgets、karpenter.sh/do-not-disrupt 注釈、および terminationGracePeriod をバイパスする強力な中断方法です。自動ノード修復は、AcceleratedHardwareReady 条件が False に設定されたノードについては置き換えまで 10 分待機し、他の修復条件については 30 分待機します。

ステップ 2: 動的 GPU NodePool を作成する

オンデマンドのスポットキャパシティをフォールバックとして使用して、生成が 4 を超える G ファミリー GPU インスタンスを動的にプロビジョニングする NodePool を定義します。EKS Auto Mode パスと Karpenter パスはどちらも同じ NodePool API を使用しますが、唯一の違いはそれが指す NodeClass です。EKS Auto Mode では、バンドルされた default NodeClass は既に適切な AMI を選択し、SOCI 並列プルを設定しているため、NodePool は作成する唯一のオブジェクトです。セルフマネージド Karpenter では、AMI を固定して SOCI を調整するカスタム EC2NodeClass も必要です。

EKS Auto Mode

EKS Auto Mode では、バンドルされた default NodeClass は GPU インスタンスの Bottlerocket AMI を自動的に選択します。これには、プリインストールされた NVIDIA ドライバー、NVIDIA デバイスプラグイン、SOCI 並列プルが含まれます。default NodeClass を参照する NodePool を適用するだけです。

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: kubernetes.io/arch operator: In values: ["amd64"] limits: cpu: 1000 memory: 5000Gi EOF

この NodePool は、生成が 4 より大きい G ファミリー GPU インスタンス (G5G6eG7e など) をプロビジョニングします。nvidia.com/gpu:NoSchedule テイントにより、GPU 対応ポッドのみがこれらのノードでスケジュールされます。

Self-managed Karpenter

セルフマネージド Karpenter には、デフォルトの NodeClass は含まれません。まず、EKS 最適化 NVIDIA AL2023 AMI エイリアスを固定し、FastImagePull 機能ゲートを介して SOCI を有効にし、コンテナ化されたイメージキャッシュをローカル NVMe に移動するように instanceStorePolicy: RAID0 を設定する EC2NodeClass を作成します。次に、それを参照する 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: | MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="BOUNDARY" --BOUNDARY Content-Type: application/node.eks.aws --- apiVersion: node.eks.aws/v1alpha1 kind: NodeConfig spec: featureGates: FastImagePull: true containerd: config: | [plugins."io.containerd.snapshotter.v1.soci"] [plugins."io.containerd.snapshotter.v1.soci".blob] max_concurrent_downloads_per_image = 20 concurrent_download_chunk_size = "16mb" max_concurrent_unpacks_per_image = 12 discard_unpacked_layers = true --BOUNDARY-- EOF

instanceStorePolicy: RAID0 はローカル NVMe ディスクを RAID-0 アレイにアセンブルします。al2023@latest AMI エイリアスは EKS 最適化 AL2023 AMI に解決されます。Karpenter が GPU インスタンスタイプを起動すると、プリインストールされている NVIDIA ドライバーを含む AL2023_x86_64_NVIDIA 高速バリアントが自動的に選択されます。

FastImagePull 機能ゲートは、イメージレイヤーを同時にダウンロードおよび解凍する SOCI スナップショッター並列プルモードを有効にします。これは、G、P、および Trn インスタンスファミリーの EKS Auto Mode の動作と一致します。containerd.config ブロックは、ECR がホストするイメージの SOCI スナップショッターをチューニングします。

  • max_concurrent_downloads_per_image: 20 は、イメージごとに最大 20 個のレイヤーを並行してダウンロードできるようにします。デフォルトは Bottlerocket では 3、AL2023 では 20 です。これは ECR での推奨値です。

  • concurrent_download_chunk_size: "16mb" は、HTTP 範囲リクエストを介して並列にダウンロードされた 16 MB のチャンクに各レイヤーを分割します。レンジ GET をサポートするレジストリ (ECR はサポートしています) に推奨されます。

  • max_concurrent_unpacks_per_image: 12 は一度に最大 12 個のレイヤーを解凍します。デフォルトは Bottlerocket では 1、AL2023 では 12 です。

  • discard_unpacked_layers: true は、解凍後に圧縮レイヤーの BLOB を削除してディスク容量を節約します。

その他の SOCI チューニングオプション (イメージあたりの同時ダウンロード数、チャンクサイズなど) については、Karpenter SOCI 設計図を参照してください。

EC2NodeClass を検証します。

kubectl get ec2nodeclass gpu-inf

正常な出力: READY TrueFalse の場合は、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: kubernetes.io/arch operator: In values: ["amd64"] limits: cpu: 1000 memory: 5000Gi EOF

ノードテンプレートの amiFamily: al2023 ラベルは、NVIDIA デバイスプラグイン DaemonSet がこれらのノードを選択するために使用するものです。

NodePool が作成されたことを確認します。

kubectl get nodepool gpu-inf

正常な出力:

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

セルフマネージド Karpenter パスでは、NODECLASS 列に default ではなく gpu-inf が表示されます。

ステップ 3: サンプルポッドでテストする

nvidia-smi ポッドを使用して GPU NodePool のセットアップをテストします。

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

STATUS: Completed は、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 は 96 GB のメモリを持つ NVIDIA RTX PRO 6000 Blackwell GPU を持つ G7e インスタンスをプロビジョニングしました。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 Auto Mode には、SOCI (Seekable OCI) 並列プルが最初からインストールされ、G、P、および Trn インスタンスでそのまま使用できるように設定されています。SOCI 並列プルのため、コンテナイメージは 2 秒未満 (1.237 秒) で ECR からプルされたことに注意してください。

NodeClaim は、Karpenter が特定のノードをプロビジョニングするために作成するリクエストです。インスタンスタイプ、キャパシティタイプ、AZ、ノードの準備が整っているかどうかが表示されます。

kubectl get nodeclaims

予想される NodeClaim 出力:

NAME            TYPE          CAPACITY    ZONE         NODE                  READY   AGE
gpu-inf-xxxxx   g7e.2xlarge   spot        us-east-2a   i-0xxxxxxxxxxxx       True    2m

インスタンスタイプと AZ は異なります。第 4 世代より新しい G ファミリーのインスタンスはすべて対象となります。

kubectl describe pod nvidia-smi における FailedCreatePodSandBox 警告は一時的なものであり、想定された動作です。VPC CNI はノードの結合後に非同期的に初期化し、kubelet は自動的に再試行します。ポッドが ContainerCreating の状態のままである場合は、kubectl describe node <node-name> でノードイベントを確認します。

ヒント

ノードが表示されない場合は、容量不足エラーを確認します。

kubectl get events | grep InsufficientCapacityError

Karpenter は、使用できないサービスを 3 分間キャッシュします。NodePool で許可されたインスタンスタイプと AZ を拡張すると、ランディングキャパシティの可能性が高まります。

注記

Karpenter によって起動されたスポットインスタンスは EC2 スポットリクエストコンソールに表示されません。Karpenter は type: instant で EC2 CreateFleet API を使用します。インスタンスは、spot ライフサイクルとともに EC2 インスタンスコンソールに表示されます。

ステップ 4: NodePool にリザーブドキャパシティを追加する (オプション)

スポット/オンデマンドフォールバックで最初にリザーブドキャパシティを使用するには、ODCR を作成して NodeClass にアタッチし、ステップ 2 の動的 NodePool を更新して reserved キャパシティも許可します。予約 API コールは両方のパスで同じです。EKS Auto Mode とセルフマネージド Karpenter は異なる NodeClass タイプを使用するため、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 を別の AZ に変更して再試行します。

キャパシティ予約 ID を検索し、以下のステップでシェル変数に保存します。

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 Mode では、バンドルされた default NodeClass は読み取り専用であるため、予約を参照するカスタム NodeClass を作成し、NodeClass を指すように NodePool を更新して、capacity-type リストに reserved キャパシティを追加します。

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-backed NodeClass を使用し、キャパシティタイプとして reserved を含めます。

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: kubernetes.io/arch operator: In values: ["amd64"] limits: cpu: 1000 memory: 5000Gi EOF
Self-managed Karpenter

セルフマネージド Karpenter の場合は、ステップ 2 で作成した EC2NodeClasscapacityReservationSelectorTerms を追加して再適用します。フィールド名と構造は、もう一方のタブに表示されている EKS Auto Mode NodeClass と一致します。

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: | MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="BOUNDARY" --BOUNDARY Content-Type: application/node.eks.aws --- apiVersion: node.eks.aws/v1alpha1 kind: NodeConfig spec: featureGates: FastImagePull: true containerd: config: | [plugins."io.containerd.snapshotter.v1.soci"] [plugins."io.containerd.snapshotter.v1.soci".blob] max_concurrent_downloads_per_image = 20 concurrent_download_chunk_size = "16mb" max_concurrent_unpacks_per_image = 12 discard_unpacked_layers = true --BOUNDARY-- EOF

ステップ 2 からの変更点は、新しい capacityReservationSelectorTerms フィールドのみです。他のすべてのフィールドは同じままです。

NodePool を更新して、キャパシティタイプとして reserved を含めます。

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: kubernetes.io/arch operator: In values: ["amd64"] limits: cpu: 1000 memory: 5000Gi EOF

Karpenter は、reserved を最もコスト効率の高いオプションとして扱い、最初に起動します。予約がいっぱいになると、スポットまたはオンデマンドにフォールバックします。

変更を適用したら、Karpenter がリザーブドキャパシティを優先し、スポットまたはオンデマンドにフォールバックすることを確認します。ポッドごとに 1 GPU をリクエストする 2 レプリカデプロイをデプロイします。ODCR は 1 インスタンス用であるため、最初のポッドは Karpenter をトリガーしてリザーブドノードを起動します。2 番目のポッドはリザーブドノードに収まらず、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>

2 つのポッドがそれぞれ異なるノードで実行されています。

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   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 ノードに nvidia.com/gpu:NoSchedule テイントがあるため、デフォルトで非 GPU ノードに配置されます。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 Identity の関連付けを作成する

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 Identity の関連付けを作成して、サービスアカウントを 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 Identity の関連付けが作成されていることを確認します。

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

予想される出力には、monitoring 名前空間に amp-iamproxy-ingest-service-accountgrafana-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 ノードからそれらを保持するため、デフォルトでシステムまたは汎用プールに配置されます。Node-exporter はワイルドカード許容範囲を使用するため、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…​ で始まる)、リージョン、および node-exporter の 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 オブジェクトの状態 (ポッドのステータス、リソースリクエスト/制限、NodeClaim の状態) に関するメトリクスを生成します

  • node-exporter (DaemonSet、ノードごとに 1 つ): ホストレベルのメトリクス (CPU、メモリ、ディスク、ネットワーク) を収集します

  • オペレーター: Prometheus とアラートマネージャーのカスタムリソースを管理します

この設定ではアラートマネージャーが無効になっています。

Grafana にアクセスする

別のターミナルを開き、ポートフォワードして Grafana にアクセスします。

kubectl port-forward svc/kube-prometheus-stack-grafana 3000:80 -n monitoring

ブラウザで http://localhost:3000 を開きます。以下のコマンドからユーザー名 admin とパスワードを使用してログインします。

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

メトリクスパイプラインがエンドツーエンドで機能していることを確認するには:

  1. [接続] > [データソース] に移動し、Amazon-Managed-Prometheus がデフォルトのデータソースとしてリストされていることを確認します。

    Grafana で AMP データソースを検証する

    Amazon-Managed-Prometheus がデフォルトのデータソースとしてリストされている Grafana Connections ページ
  2. [ドリルダウン] > [メトリクス] に移動し、up メトリクスを検索します。クラスターのスクレイプターゲットの結果が表示されます。

    Grafana で up メトリクスを検証する

    アクティブなスクレイプターゲットを示す緑色のステータスバーが付いたアップメトリクスが表示された 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 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 ノードが実行されると、準備完了状態のポッドが 1 つ表示されます。DCGM メトリクスを検証するには、Grafana で [ドリルダウン] > [メトリクス] に移動し、DCGM_ を検索します。

Grafana で DCGM メトリクスを検証する

DCGM_FI_DEV_ECC_SBE_VOL_TOTAL、DCGM_FI_DEV_ENC_UTIL、DCGM_FI_DEV_FB_FREE、DCGM_FI_DEV_FB_USED などの GPU メトリクスを示す DCGM_ でフィルタリングされた Grafana ドリルダウンメトリクスページ

ダッシュボードを表示するには、[ダッシュボード] > [GPU モニタリング] > [NVIDIA DCGM Exporter ダッシュボード] に移動します。

Grafana の NVIDIA DCGM Exporter ダッシュボード

GPU 使用率、GPU 平均温度、GPU Framebuffer Mem Used、GPU Power Total パネルを示す Grafana NVIDIA DCGM Exporter ダッシュボード

モデルの重み S3 バケット

モデルの重みを保存するための Amazon S3 バケットを作成し、ワークロードポッドがそのバケットに対して読み書きできるように EKS Pod Identity の関連付けを設定します。

新しいターミナルを開いた場合は、クラスター名とリージョンを設定します。

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 Identity を設定する

default 名前空間に model-storage-sa ServiceAccount、モデルバケットを対象とする IAM ポリシー、およびそれらをリンクする EKS Pod Identity の関連付けを作成します。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:DeleteObjects3:PutObject を付与します。モデルの重みのみを読み取る本番推論ポッドの場合は、s3:PutObjects3:DeleteObject を削除して最小特権に従います。

EKS Pod Identity の関連付けを作成します。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 イメージで 1 回限りのポッドを実行し、EKS Pod Identity が正しく設定され、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

発信者 ID は、EKS Pod Identity を介してポッドが ${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 Pod Identity の関連付けを削除します。

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

Grafana サービスアカウントの EKS Pod Identity の関連付けを削除します。

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 Identity の関連付けを削除します。

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