

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

# 運算和自動擴展
<a name="aiml-compute"></a>

**提示**  
 透過 Amazon EKS 研討會[探索](https://aws-experience.com/emea/smb/events/series/get-hands-on-with-amazon-eks?trk=4a9b4147-2490-4c63-bc9f-f8a84b122c8c&sc_channel=el)最佳實務。

## GPU 資源最佳化和成本管理
<a name="_gpu_resource_optimization_and_cost_management"></a>

### 使用 Well-Known 標籤以 GPU 需求排程工作負載
<a name="_schedule_workloads_with_gpu_requirements_using_well_known_labels"></a>

對於對不同 GPU 特性 （例如 GPU、GPU 記憶體） 敏感的 AI/ML 工作負載，建議使用與 [Karpenter](https://karpenter.sh/v1.0/concepts/scheduling/#labels) 和[受管節點群組](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html)搭配使用的節點類型支援的[已知排程標籤](https://kubernetes.io/docs/reference/labels-annotations-taints/)來指定 GPU 需求。未定義這些項目可能會導致在 GPU 資源不足的執行個體上排程 Pod，進而導致故障或效能降低。我們建議使用 [nodeSelector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) 或 [Node 親和性](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity)來指定 Pod 應在哪個節點上執行，並在 Pod 的資源區段中設定運算[資源](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) (CPU、記憶體、GPUs 等）。

 **範例** 

例如，使用 Karpenter 時使用 GPU 名稱節點選擇器：

```
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod-example
spec:
  containers:
  - name: ml-workload
    image: <image>
    resources:
      limits:
        nvidia.com/gpu: 1  # Request one NVIDIA GPU
  nodeSelector:
    karpenter.k8s.aws/instance-gpu-name: "l40s"  # Run on nodes with NVIDIA L40S GPUs
```

### 使用 Kubernetes 裝置外掛程式公開 GPUs
<a name="_use_kubernetes_device_plugin_for_exposing_gpus"></a>

若要在節點上公開 GPUs，NVIDIA GPU 驅動程式必須安裝在節點的作業系統和容器執行時間上，設定成允許 Kubernetes 排程器將 Pod 指派給具有可用 GPUs 的節點。NVIDIA Kubernetes 裝置外掛程式的設定程序取決於您使用的 EKS 加速 AMI：
+  ** [Bottlerocket Accelerated AMI](https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami-bottlerocket.html)：**此 AMI 包含 NVIDIA GPU 驅動程式**，且**已預先安裝並可供使用的 [NVIDIA Kubernetes 裝置外掛程式](https://github.com/NVIDIA/k8s-device-plugin)，可立即支援 GPU。向 Kubernetes 排程器公開 GPUs 不需要額外的組態。
+  ** [AL2023 加速 AMI](https://aws.amazon.com/blogs/containers/amazon-eks-optimized-amazon-linux-2023-accelerated-amis-now-available/)：**此 AMI 包含 NVIDIA GPU 驅動程式，但未****預先安裝 [NVIDIA Kubernetes 裝置外掛程式](https://github.com/NVIDIA/k8s-device-plugin)。您必須分別安裝和設定裝置外掛程式，通常透過 DaemonSet。請注意，如果您使用 eksctl 在 ClusterConfig 中建立叢集並指定 GPU 執行個體類型 （例如 `g5.xlarge`)， `eksctl` 會自動選取適當的 AMI 並安裝 NVIDIA Kubernetes 裝置外掛程式。若要進一步了解，請參閱 eksctl 文件中的 [GPU 支援](https://eksctl.io/usage/gpu-support/)。

如果您決定改用 EKS 加速 AMIs和 [NVIDIA GPU 運算子](https://github.com/NVIDIA/gpu-operator)來管理 NVIDIA Kubernetes 裝置外掛程式等元件，請注意根據[預先安裝的 NVIDIA GPU 驅動程式和 NVIDIA 容器工具組 NVIDIA 文件，停用 NVIDIA GPU 驅動程式和 NVIDIA 容器](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/getting-started.html#pre-installed-nvidia-gpu-drivers-and-nvidia-container-toolkit)工具組的管理。

若要驗證 NVIDIA 裝置外掛程式是否作用中且 GPUs 已正確公開，請執行：

```
kubectl describe node | grep nvidia.com/gpu
```

此命令會檢查`nvidia.com/gpu`資源是否在節點的容量和可配置的資源中。例如，具有一個 GPU 的節點應該會顯示 `nvidia.com/gpu: 1`。如需詳細資訊，請參閱 [Kubernetes GPU 排程指南](https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/)。

### 使用許多不同的 EC2 執行個體類型
<a name="_use_many_different_ec2_instance_types"></a>

盡可能使用多種不同的 EC2 執行個體類型，是 Amazon EKS 上可擴展性的重要最佳實務，如 [Kubernetes 資料平面](scale-data-plane.md)一節所述。此建議也適用於具有加速硬體 （例如 GPUs) 的執行個體。如果您建立的叢集僅使用一種執行個體類型，並嘗試擴展超過該區域的容量的節點數量，您可能會收到容量不足錯誤 (ICE)，表示沒有可用的執行個體。在任意多樣化之前，請務必了解 AI/ML 工作負載的獨特特性。使用 [EC2 Instance Type Explorer](https://aws.amazon.com/ec2/instance-explorer/) 工具檢閱可用的執行個體類型，以產生符合您特定運算需求的執行個體類型清單，並避免任意限制可在叢集中使用的執行個體類型。

加速運算執行個體提供不同的購買模型，以符合短期、中期和穩定狀態工作負載。對於您想要避免進行保留的短期、彈性和容錯工作負載，請查看 Spot 執行個體。容量區塊、隨需執行個體和 Save Plans 可讓您佈建中長期工作負載持續時間的加速運算執行個體。為了增加成功存取您偏好購買選項中所需容量的機會，建議使用各種執行個體類型和可用區域清單。或者，如果您遇到特定購買模型ICEs，請使用不同的模型重試。

 **範例** 下列範例示範如何啟用 Karpenter NodePool 來佈建大於第 3 代的 G 和 P 執行個體 （例如 p3)。如需進一步了解，請參閱[EKS 可擴展性最佳實務](scalability.md)區段。

```
- key: karpenter.k8s.aws/instance-category
  operator: In
  values: ["g", "p"] # Diversifies across G-series and P-series
- key: karpenter.k8s.aws/instance-generation
  operator: Gt
  values: ["3"] # Selects instance generations greater than 3
```

如需針對 GPUs 使用 Spot 執行個體的詳細資訊，請參閱以下「考慮針對 GPU 使用 Amazon EC2 Spot 執行個體 GPUs 搭配 Karpenter」。

### 考慮將 Amazon EC2 Spot 執行個體與 Karpenter 搭配使用於 GPUs
<a name="_consider_using_amazon_ec2_spot_instances_for_gpus_with_karpenter"></a>

Amazon EC2 Spot 執行個體可讓您利用 AWS 雲端中未使用的 EC2 容量，並與隨需價格相比，提供高達 90% 的折扣。當 Amazon EC2 需要恢復容量時，Amazon EC2 Spot 執行個體可以透過兩分鐘的通知中斷。如需詳細資訊，請參閱《Amazon EC2 使用者指南》中的 [Spot 執行個體](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-spot-instances.html)。Amazon EC2 Spot 是容錯、無狀態和彈性 （時間和執行個體類型） 工作負載的理想選擇。若要進一步了解何時使用 Spot 執行個體，請參閱 [EC2 Spot 執行個體最佳實務](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-best-practices.html)。如果適用於 Spot 的 AI/ML 工作負載，您也可以使用 Spot 執行個體。

 **使用案例** 

適合 Spot 的工作負載可以是大數據、容器化工作負載、CI/CD、無狀態 Web 伺服器、高效能運算 (HPC) 和轉譯工作負載。Spot 執行個體不適用於無彈性、具狀態、不容錯或執行個體節點之間緊密耦合的工作負載 （例如，具有彼此高度依賴之平行程序的工作負載，以進行運算，需要持續的節點間通訊，例如以 MPI 為基礎的高效能運算應用程式，例如運算流體動態或具有複雜相互依存性的分散式資料庫）。以下是我們建議的特定使用案例 （無特定順序）：
+  **即時線上推論**：只要您的工作負載易於使用 Spot 執行個體，即可針對即時推論工作負載使用 Spot 執行個體進行成本最佳化擴展。換句話說，推論時間可能不到兩分鐘，應用程式對中斷具有容錯能力，並且可以在不同的執行個體類型上執行。透過執行個體多樣性 （例如跨多個執行個體類型和可用區域） 或保留來確保高可用性，同時實作應用程式層級容錯能力來處理潛在的 Spot 中斷。
+  **超參數調校**：使用 Spot 執行個體以機會方式執行探索性調校任務，因為可以容忍中斷而不會造成重大損失，尤其是短期實驗。
+  **資料擴增**：使用 Spot 執行個體執行資料預先處理和擴增任務，這些任務可以在中斷時從檢查點重新啟動，因此非常適合 Spot 的變數可用性。
+  **微調模型**：使用 Spot 執行個體搭配強大的檢查點機制進行微調，從上次儲存的狀態恢復，將執行個體中斷的影響降至最低。
+  **批次推論**：使用 Spot 執行個體以non-real-time的方式處理大量離線推論請求，其中任務可以暫停和恢復，提供與 Spot 節省成本的最佳一致性，並透過重試或多樣化處理潛在的中斷。
+  **機會性訓練子集**：將 Spot 執行個體用於邊緣或實驗訓練工作負載 （例如，低於 1，000 萬個參數的較小模型），其中可接受中斷，並可套用跨執行個體類型或區域多樣化等效率最佳化，但由於潛在中斷，不建議用於生產規模訓練。

 **考量** 

若要在 Amazon EKS 上使用 Spot 執行個體進行加速工作負載，有許多重要考量 （無特定順序）：
+  **使用 Karpenter 來管理已啟用進階整合的 Spot 執行個體**。透過在 Karpenter NodePool 中將 karpenter.sh/capacity-type 指定為「spot」，Karpenter 預設會佈建 Spot 執行個體，而不需要任何額外的組態。不過，若要啟用進階 Spot-to-Spot 整合，以低價 Spot 替代方案取代未充分利用的 Spot 節點，您需要透過設定 --feature-gates SpotToSpotConsolidation=true in Karpenter 控制器引數或透過 FEATURE\$1GATES 環境變數來啟用 SpotToSpotConsolidation [功能閘道](https://karpenter.sh/docs/reference/settings/)。Karpenter [price-capacity-optimized](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-allocation-strategy.html)配置策略來佈建 EC2 執行個體。根據 NodePool 要求和 Pod 限制，Karpenter bin-packs 無法排程的 Pod，並將各種執行個體類型傳送至 [Amazon EC2 機群 API](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-fleet-request-type.html)。您可以使用 [EC2 Instance Type Explorer](https://aws.amazon.com/ec2/instance-explorer/) 工具來產生符合您特定運算需求的執行個體類型清單。
+  **確保工作負載無狀態、容錯能力和彈性**。工作負載在執行個體/GPU 大小方面必須是無狀態、容錯且靈活的。這可在 Spot 中斷後無縫恢復，而執行個體彈性可讓您在 Spot 上停留更長的時間。使用 AWS SQS 佇列的名稱設定 settings.interruptionQueue Helm 值，以擷取 [Spot 中斷事件，在 Karpenter 中啟用 Spot 中斷處理](https://karpenter.sh/docs/concepts/disruption/#interruption)。例如，透過 Helm 安裝 時，請使用 --set "settings.interruptionQueue=\$1\$1CLUSTER\$1NAME\$1"。若要查看範例，請參閱 [Karpenter 入門](https://karpenter.sh/docs/getting-started/getting-started-with-karpenter/)指南。當 Karpenter 注意到 Spot 中斷事件時，它會在中斷事件之前自動封鎖、污點、耗盡和終止節點 （以最大化 Pod 的終止寬限期）。同時，Karpenter 會立即啟動新的節點，以便盡快準備就緒。
+  **避免過度限制執行個體類型選擇**。您應該盡可能避免限制執行個體類型。透過不限制執行個體類型，以較低的成本取得大規模 Spot 容量，並以較低的 Spot 執行個體中斷頻率取得的機會較高。例如，避免限制為特定類型 （例如 g5.xlarge)。考慮使用 karpenter.k8s.aws/instance-category 和 karpenter.k8s.aws/instance-generation 等金鑰來指定各種執行個體類別和世代。Karpenter 可簡化跨多個執行個體類型和可用區域 (AZs) 的隨需和 Spot 執行個體容量多樣化。此外，如果您的 AI/ML 工作負載需要特定或有限數量的加速器，但區域之間具有彈性，您可以使用 Spot Placement Score 在啟動之前動態識別部署工作負載的最佳區域。
+  **擴展 NodePool 需求，以包含更多類似的 EC2 執行個體系列**。每個 Spot 執行個體集區都包含特定可用區域 (AZ) 中特定執行個體類型的未使用 EC2 執行個體容量。當 Karpenter 嘗試佈建新節點時，會選取符合 NodePool 需求的執行個體類型。如果任何 AZ 中沒有相容的執行個體類型具有 Spot 容量，則佈建會失敗。為了避免此問題，請允許跨大小和可用區域 (AZs) 的 NVIDIA 更廣泛的 g 系列執行個體 （第 4 代或更高版本），同時考慮 GPU 記憶體或 Ray Tracing 等硬體需求。由於執行個體的類型可能不同，因此您需要確保工作負載能夠在每種類型上執行，以及您取得的效能符合您的需求。
+  **利用區域中的所有可用區域**。可用容量因可用區域 (AZ) 而異，特定執行個體類型可能無法在一個可用區域中使用，但在另一個可用區域中則有許多。執行個體類型和可用區域的每個唯一組合都會構成個別的 Spot 容量集區。透過請求 Karpenter NodePool 要求區域內所有AZs容量，您可以一次有效地搜尋更多集區。這可將 Spot 容量集區的數量最大化，因此會增加取得 Spot 容量的機率。為了達成此目的，請在 NodePool 組態中完全省略 topology.kubernetes.io/zone 金鑰，以允許 Karpenter 從區域中所有可用的可用 AZs 中選取，或使用運算子明確列出 AZs：在 中，並提供值 （例如 us-west-2a)。
+  **考慮使用 Spot Placement Score (SPS) 來了解使用 Spot 執行個體成功存取所需容量的可能性**。[Spot 配置分數 (SPS)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/work-with-spot-placement-score.html) 是一種工具，可提供分數，協助您評估 Spot 請求成功的可能性。當您使用 SPS 時，首先指定 Spot 執行個體的運算需求，然後 Amazon EC2 會傳回 Spot 請求可能成功的前 10 個區域或可用區域 (AZs)。區域和可用區域的分數範圍是從 1 到 10。分數為 10 表示您的 Spot 請求很有可能，但不保證成功。分數 1 表示您的 Spot 請求完全不可能成功。對於不同的區域或可用區域，可能會傳回相同的分數。若要進一步了解，請參閱[在 AWS 上建置 Spot 配置分數追蹤器儀表板的指引](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/work-with-spot-placement-score.html)。隨著 Spot 容量隨時波動，SPS 將協助您識別最適合工作負載限制 （即彈性、效能、大小等） AZs區域和區域的組合。如果您的 AI/ML 工作負載需要特定或有限數量的加速器，但區域之間具有彈性，您可以使用 Spot 置放分數，在啟動之前動態識別部署工作負載的最佳區域。為了協助您自動找出取得 Spot 容量的可能性，我們提供建置 SPS 追蹤器儀表板的指引。此解決方案使用 YAML 組態進行多樣化設定 （例如，包括 GPUs 的執行個體需求），在 CloudWatch 中存放指標，並提供儀表板來比較組態，以監控一段時間內的 SPS 分數。定義每個工作負載的儀表板，以評估 vCPU、記憶體和 GPU 需求，確保 EKS 叢集的最佳設定，包括考慮使用其他 AWS 區域。若要進一步了解，請參閱 [Spot 配置分數的運作方式](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/how-sps-works.html)。
+  **優雅地處理 Spot 中斷和測試**。對於終止期間超過兩分鐘的 Pod，舊節點會在重新排程這些 Pod 之前中斷，這可能會影響工作負載可用性。設計應用程式時，請考慮兩分鐘 Spot 中斷通知， 在長時間執行的應用程式中實作檢查點 （例如， 將進度儲存至 Amazon S3 等持久性儲存體），以在中斷後繼續， 在 Pod 規格中擴展 terminationGracePeriodSeconds （預設值為 30 秒），以允許更多時間正常關閉， 和 會在您的應用程式中使用preStop生命週期掛鉤和/或 SIGTERM 訊號來處理中斷，以進行正常的關機活動，例如清除、 狀態儲存、 和 連線關閉。對於即時工作負載，擴展時間很重要，且工作負載需要超過兩分鐘的時間才能準備好為流量提供服務，請考慮透過檢閱 和[應用程式擴展和效能](aiml-performance.md)最佳實務來最佳化容器啟動[儲存](aiml-storage.md)和 ML 模型載入時間。若要測試替代節點，請使用 [AWS Fault Injection Service](https://aws.amazon.com/fis/) (FIS) 來模擬 Spot 中斷。

除了這些核心 Spot 最佳實務之外，在 Amazon EKS 上管理 GPU 工作負載時，請考量這些因素。與 CPU 工作負載不同，GPU 工作負載對 GPU 功能和可用 GPU 記憶體等硬體詳細資訊特別敏感。GPU 工作負載可能受限於他們可以使用的執行個體類型，與 CPUs 相比，可用的選項較少。首先，評估工作負載是否具有執行個體彈性。如果您不知道工作負載可以使用多少執行個體類型，請個別進行測試，以確保相容性和功能。識別您可以多靈活地盡可能多樣化，同時確認多樣化可讓工作負載正常運作並了解任何效能影響 （例如輸送量或完成時間）。在分散工作負載時，請考慮下列事項：
+  **檢閱 CUDA 和架構相容性**。您的 GPU 工作負載可能針對特定硬體、GPU 類型 （例如，p3 中的 V100 和 p4 中的 A100) 進行最佳化，或針對 TensorFlow 等程式庫的特定 CUDA 版本進行寫入，因此請務必檢閱工作負載的相容性。此相容性對於防止 GPU 加速中的執行時間錯誤、當機、故障 （例如，與 PyTorch 或 TensorFlow 等架構不相符的 CUDA 版本可防止執行） 或利用 FP16/INT8 精確度等硬體功能至關重要。
+  **GPU 記憶體**。請務必評估模型的記憶體需求，並使用 [DCGM Exporter](https://docs.nvidia.com/datacenter/dcgm/latest/gpu-telemetry/dcgm-exporter.html) 等工具在執行時間分析模型的記憶體用量，並在 karpenter.k8s.aws/instance-gpu-memory 等知名標籤中設定執行個體類型所需的最低 GPU 記憶體。GPU VRAM 因執行個體類型而異 （例如，NVIDIA T4 有 16GB, A10G 有 24GB, V100 有 16-32GB)，而 ML 模型 （例如，大型語言模型） 可能會超過可用的記憶體，導致out-of-memory(OOM) 錯誤或當機。對於 EKS 中的 Spot 執行個體，這可能會限制多樣化。例如，如果您的模型不適合，則不能包含較低的 VRAM 類型，這可能會限制對容量集區的存取並提高中斷風險。請注意，對於單一 GPU、單一節點推論 （例如，在同一節點上排程多個 Pod 以利用其 GPU 資源），這可能會限制多樣化，因為您只能在 Spot 組態中包含具有足夠 VRAM 的執行個體類型。
+  **浮點精確度和效能**。並非所有 Nvidia GPU 架構都有相同的浮點精確度 （例如 FP16/INT8)。評估工作負載所需的核心類型 (CUDA/Tensor/RT) 效能和浮點精確度。在價格較低、效能較低的 GPU 上執行並不表示效能更好，因此請考慮在特定時間範圍內完成的工作評估效能，以了解多樣化的影響。

 **案例：即時推論工作負載的多樣化** 

對於 Spot 執行個體上的即時線上推論工作負載，您可以設定 Karpenter NodePool 以分散於相容的 GPU 執行個體系列和世代。這種方法透過從多個 Spot 集區提取來確保高可用性，同時透過 GPU 功能、記憶體和架構的限制來維持效能。它支援在限制執行個體容量時使用替代方案，將中斷降至最低，並最佳化推論延遲。此範例 NodePool 狀態使用大於 3 的 g 和 p 系列執行個體，這些執行個體具有超過 20GB 的 GPU 記憶體。

 **範例** 

```
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: gpu-inference-spot
spec:
  template:
    metadata:
      labels:
        role: gpu-spot-worker
    spec:
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot"] # Use Spot Instances
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["g", "p"] # Diversifies across G-series and P-series
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: ["3"] # Selects instance generations greater than 3
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"] # Specifies AMD64 architecture, compatible with NVIDIA GPUs
        - key: karpenter.k8s.aws/instance-gpu-memory
          operator: Gt
          values: ["20480"] # Ensures more than 20GB (20480 MiB) total GPU memory
      taints:
        - key: nvidia.com/gpu
          effect: NoSchedule
      nodeClassRef:
        name: gpu-inference-ec2
        group: karpenter.k8s.aws
        kind: EC2NodeClass
      expireAfter: 720h
  limits:
    cpu: 100
    memory: 100Gi
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 5m # Enables consolidation of underutilized nodes after 5 minutes
```

### 實作長時間執行訓練任務的檢查點
<a name="_implement_checkpointing_for_long_running_training_jobs"></a>

檢查點是一種容錯技術，涉及定期儲存程序的狀態，以便在中斷時從上次儲存的點恢復。在機器學習中，它通常與訓練相關，其中長時間執行的任務可以節省模型權重和最佳化工具狀態，以便在失敗後繼續訓練，例如硬體問題或 Spot 執行個體中斷。

您可以在訓練期間使用檢查點來儲存機器學習 (ML) 模型的狀態。檢查點是模型的快照，並且可以透過機器學習 (ML) 架構的回呼函式進行設定。您可以使用儲存的檢查點，從上次儲存的檢查點重新啟動訓練任務。使用檢查點，您可以儲存訓練中的模型快照，因為訓練任務或執行個體意外中斷。這可讓您在未來從檢查點繼續訓練模型。除了實作節點彈性系統之外，建議您實作檢查點，以減輕中斷的影響，包括硬體故障或 Amazon EC2 Spot 執行個體中斷所造成的中斷。

如果沒有檢查點，中斷可能會導致運算時間浪費和進度遺失，這對於長時間執行的訓練任務非常昂貴。檢查點可讓任務定期儲存其狀態 （例如模型權重和最佳化工具狀態），並在中斷後從最後一個檢查點 （上次處理的批次） 恢復。若要實作檢查點，請設計您的應用程式以處理大量資料，並在訓練任務進行時透過 Amazon S3 [CSI 驅動程式掛載點將中繼結果儲存到持久性儲存體，例如 Amazon S3 ](https://docs.aws.amazon.com/eks/latest/userguide/s3-csi.html) 儲存貯體。

 **使用案例** 

檢查點在特定案例中特別有用，以平衡容錯能力與效能額外負荷。在下列情況下，請考慮使用檢查點：
+  **任務持續時間超過數小時**：對於長時間執行的訓練任務 （例如，對於小型模型 >1-2 小時，對於具有數十億個參數的大型基礎模型，則為天數/週），其中中斷造成的進度損失成本很高。較短的任務可能不會證明 I/O 額外負荷。
+  **對於 Spot 執行個體或硬體故障**：在容易中斷的環境中，例如 EC2 Spot (2 分鐘通知） 或硬體故障 （例如 GPU 記憶體錯誤），檢查點可快速恢復，讓 Spot 能夠節省容錯工作負載的成本。
+  **大規模分散式訓練**：適用於具有數百/數千個加速器的設定 （例如 >100 GPUs)，其中故障之間的平均時間會隨規模線性減少。使用 進行模型/資料平行處理，以處理並行檢查點存取並避免完全重新啟動。
+  **具有高資源需求的大規模模型**：在 PB 級 LLM 訓練中，失敗是因叢集大小而不可避免的；分層方法 （暫時性方法為快速本機每 5-30 分鐘一次，主要故障為每小時耐用一次） 可最佳化復原時間與效率。

### 使用 ML 容量區塊來確保 P 和 Trainium 執行個體的容量
<a name="_use_ml_capacity_blocks_for_capacity_assurance_of_p_and_trainium_instances"></a>

 [ML 的容量區塊](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-blocks.html)可讓您保留熱門的 GPU 執行個體，特別是 P 執行個體 （例如 p6-b200、p5、p5e、p5en、p4d、p4de) 和 Trainium 執行個體 （例如 trn1、trn2)，以幾乎立即開始或在未來日期開始，以支援您的短期機器學習 (ML) 工作負載。這些保留非常適合用來確保運算密集型任務的容量，例如模型訓練和微調。EC2 容量區塊定價包含保留費和作業系統費用。若要進一步了解定價，請參閱適用於 [ML 定價的 EC2 容量區塊](https://aws.amazon.com/ec2/capacityblocks/pricing/)。

若要為 Amazon EKS 上的 AI/ML 工作負載預留 GPUs，以保證可預測的容量，我們建議您將 ML 容量區塊用於短期或[隨需容量預留 ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-reservations.html)(ODCRs)，以保證一般用途的容量。
+ ODCRs可讓您在特定可用區域中保留 EC2 執行個體容量 （例如，g5 或 p5 等 GPU 執行個體），即使在高需求期間也能確保可用性。ODCRs沒有長期承諾，但您要支付預留容量的隨需費率，無論是已使用或閒置。在 EKS 中，[Karpenter](https://karpenter.sh/) 和[受管節點群組等節點](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html)類型支援 ODCRs。若要排定 Karpenter 中的 ODCRs優先順序，請將 NodeClass 設定為使用 `capacityReservationSelectorTerms` 欄位。請參閱 [Karpenter NodePools 文件](https://karpenter.sh/docs/concepts/nodeclasses/#speccapacityreservationselectorterms)。
+ 容量區塊是 GPU （例如 p5、p4d) 或 Trainium (trn1、trn2) 執行個體的特殊保留機制，專為模型訓練、微調或實驗等短期 ML 工作負載而設計。您從未來日期開始為定義的期間 （通常為 24 小時至 182 天） 保留容量，僅支付預留時間的費用。它們是預付的，需要預先規劃容量需求，且不支援自動擴展，但會共置在 EC2 UltraClusters 中以進行低延遲聯網。它們只會在保留期間收費。若要進一步了解，請參閱[尋找和購買容量區塊](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/capacity-blocks-purchase.html)，或使用[建立具有 ML 容量區塊的受管節點群組中的指示來設定具有容量區塊的受管節點群組](https://docs.aws.amazon.com/eks/latest/userguide/capacity-blocks-mng.html)。

透過 AWS 管理主控台預留容量，並將節點設定為使用 ML 容量區塊。根據工作負載排程規劃保留，並在預備叢集中進行測試。如需詳細資訊，請參閱[容量區塊文件](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-blocks.html)。

### 考慮 G Amazon EC2 執行個體的隨需、Amazon EC2 Spot 或隨需容量保留 ODCRs)
<a name="_consider_on_demand_amazon_ec2_spot_or_on_demand_capacity_reservations_odcrs_for_g_amazon_ec2_instances"></a>

對於 G Amazon EC2 執行個體，請考慮與隨需、Amazon EC2 Spot 執行個體和隨需容量保留不同的購買選項。[ODCRs](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-reservations.html)可讓您在特定的可用區域中保留 EC2 執行個體容量一段時間，即使在高需求期間也能確保可用性。與僅適用於 P 和 Trainium 執行個體的 ML 容量區塊不同，ODCRs 可用於更廣泛的執行個體類型，包括 G 執行個體，使其適用於需要不同 GPU 功能的工作負載，例如推論或圖形。使用 Amazon EC2 Spot 執行個體時，能夠跨不同的執行個體類型、大小和可用區域進行多樣化，是能夠長時間停留在 Spot 上的關鍵。

ODCRs沒有長期承諾，但您要支付預留容量的隨需費率，無論是已使用或閒置。您可以建立 ODCRs以供立即使用，或排定未來日期使用，提供容量規劃的彈性。在 Amazon EKS 中，[Karpenter](https://karpenter.sh/) 和[受管節點群組等節點](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html)類型支援 ODCRs。若要排定 Karpenter 中的 ODCRs優先順序，請將 NodeClass 設定為使用 `capacityReservationSelectorTerms` 欄位。請參閱 [Karpenter NodePools 文件](https://karpenter.sh/docs/concepts/nodepools/)。如需建立 ODCRs 的詳細資訊，包括 CLI 命令，請參閱[隨需容量保留入門](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-reservations-getting-started.html)。

### 考慮其他加速執行個體類型和大小
<a name="_consider_other_accelerated_instance_types_and_sizes"></a>

選取適當的加速執行個體和大小對於在 Amazon EKS 上最佳化 ML 工作負載的效能和成本至關重要。例如，不同的 GPU 執行個體系列具有不同的效能和功能，例如 GPU 記憶體。為了協助您選擇價格效能最佳的選項，請檢閱**加速運算**下 [EC2 執行個體類型頁面中可用的 GPU 執行個體](https://aws.amazon.com/ec2/instance-types/)。評估多個執行個體類型和大小，找出最適合您特定工作負載需求的執行個體類型和大小。考慮 GPUs 數量、記憶體和網路效能等因素。透過仔細選擇正確的 GPU 執行個體類型和大小，您可以在 EKS 叢集中實現更好的資源使用率和成本效益。

如果您在 EKS 節點中使用 GPU 執行個體，則預設在`kube-system`命名空間中會有 `nvidia-device-plugin-daemonset` Pod。若要快速了解您是否充分利用執行個體中的 GPU ([https://docs.nvidia.com/deploy/nvidia-smi/index.html](https://docs.nvidia.com/deploy/nvidia-smi/index.html)如下所示）：

```
kubectl exec nvidia-device-plugin-daemonset-xxxxx \
  -n kube-system -- nvidia-smi \
  --query-gpu=index,power.draw,power.limit,temperature.gpu,utilization.gpu,utilization.memory,memory.free,memory.used \
  --format=csv -l 5
```
+ 如果 `utilization.memory` （接近 100%)，則您的程式碼可能已繫結記憶體。這表示 GPU （記憶體） 已充分利用，但可能表示應調查進一步的效能最佳化。
+ 如果 `utilization.gpu` 接近 100%，這不一定表示 GPU 已充分利用。更好的指標是 `power.draw`與 的比率`power.limit`。如果此比率為 100% 或以上，則您的程式碼會充分利用 GPU 的運算容量 （運算容量）。
+ `-l 5` 旗標指出 每 5 秒輸出一次指標。如果是單一 GPU 執行個體類型，則不需要索引查詢旗標。

若要進一步了解，請參閱 AWS 文件中的 [GPU 執行個體](https://docs.aws.amazon.com/dlami/latest/devguide/gpu.html)。

### 使用時間分割、MIG 和分量 GPU 配置來最佳化 GPU 資源配置
<a name="_optimize_gpu_resource_allocation_with_time_slicing_mig_and_fractional_gpu_allocation"></a>

Kubernetes 中的靜態資源限制 （例如 CPU、記憶體、GPU 計數） 可能會導致過度佈建或利用率不足，尤其是推論等動態 AI/ML 工作負載。選取正確的 GPU 非常重要。對於低容量或尖峰工作負載，時間分割允許多個工作負載透過共用其運算資源來共用單一 GPU，進而提高效率並減少浪費。GPU 共用可以透過不同的選項達成：
+  **利用節點選擇器/節點親和性來影響排程**：確保佈建的節點和 Pod 已排程在工作負載的適當 GPUs 上 （例如 `karpenter.k8s.aws/instance-gpu-name: "a100"`)
+  **時間分割**：排程工作負載以隨時間共用 GPU 的運算資源，允許並行執行，而無需實體分割。這非常適合具有可變運算需求的工作負載，但可能缺少記憶體隔離。
+  **多執行個體 GPU (MIG)**：MIG 允許單一 NVIDIA GPU 分割成多個隔離的執行個體，並支援 NVIDIA Ampere （例如 A100 GPU)、NVIDIA Hopper （例如 H100 GPU) 和 NVIDIA Blackwell （例如 Blackwell GPUs) GPUs。每個 MIG 執行個體都會接收專用運算和記憶體資源，在需要資源保證的多租用戶環境或工作負載中啟用資源共用，這可讓您最佳化 GPU 資源使用率，包括透過時間分割提供不同批次大小的多個模型。
+  **分數 GPU 分配**：使用軟體型排程，將部分 GPU 運算或記憶體分配給工作負載，為動態工作負載提供彈性。[NVIDIA KAI 排程器](https://github.com/NVIDIA/KAI-Scheduler)是 Run：ai 平台的一部分，透過允許 Pod 請求部分 GPU 資源來啟用此功能。

若要在 EKS 中啟用這些功能，您可以部署 NVIDIA 裝置外掛程式，將 GPUs 公開為可排程的資源，並支援時間分割和 MIG。若要進一步了解，請參閱 [Kubernetes 中的時間分割 GPUs ](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/gpu-sharing.html)和[使用 NVIDIA 時間分割和加速 EC2 執行個體的 Amazon EKS 上的 GPU 共用](https://aws.amazon.com/blogs/containers/gpu-sharing-on-amazon-eks-with-nvidia-time-slicing-and-accelerated-ec2-instances/)。

 **範例** 

例如，若要使用 NVIDIA 裝置外掛程式啟用時間分割：

```
apiVersion: v1
kind: ConfigMap
metadata:
  name: nvidia-device-plugin-config
  namespace: kube-system
data:
  config.yaml: |
    version: v1
    sharing:
      timeSlicing:
        resources:
        - name: nvidia.com/gpu
          replicas: 4  # Allow 4 pods to share each GPU
```

 **範例** 

例如，若要使用 KAI 排程器進行小數 GPU 配置，請將其與 NVIDIA GPU Operator 一起部署，並在 Pod 規格中指定小數 GPU 資源：

```
apiVersion: v1
kind: Pod
metadata:
  name: fractional-gpu-pod-example
  annotations:
    gpu-fraction: "0.5"  # Annotation for 50% GPU
  labels:
    runai/queue: "default"  # Required queue assignment
spec:
  containers:
  - name: ml-workload
    image: nvcr.io/nvidia/pytorch:25.04-py3
    resources:
      limits:
        nvidia.com/gpu: 1
  nodeSelector:
    nvidia.com/gpu: "true"
  schedulerName: kai-scheduler
```

## 節點彈性和訓練任務管理
<a name="_node_resiliency_and_training_job_management"></a>

### 使用自動復原實作節點運作狀態檢查
<a name="_implement_node_health_checks_with_automated_recovery"></a>

對於需要頻繁節點間通訊的 Amazon EKS 分散式訓練任務，例如跨多個節點的多 GPU 模型訓練，GPU 或 EFA 失敗等硬體問題可能會導致訓練任務中斷。這些中斷可能會導致訓練進度的損失和成本增加，尤其是依賴穩定硬體的長期執行 AI/ML 工作負載。

為了協助增加硬體故障的彈性，例如執行 GPU 工作負載的 EKS 叢集中的 GPU 失敗，我們建議您利用 **EKS 節點監控代理**程式搭配自動修復或 **Amazon SageMaker HyperPod**。雖然具有自動修復的 EKS 節點監控代理程式提供節點運作狀態監控和使用標準 Kubernetes 機制的自動修復等功能，但 SageMaker HyperPod 提供目標彈性和其他專為大規模 ML 訓練而設計的功能，例如深度運作狀態檢查和自動恢復任務。
+ [EKS Node Monitoring Agent](https://docs.aws.amazon.com/eks/latest/userguide/node-health.html) with Node Auto Repair 透過讀取日誌和套用 NodeConditions 來持續監控節點運作狀態，包括加速硬體的特定標準條件，例如 `Ready`和 條件，以識別 GPU 或聯網故障等問題。當節點視為運作狀態不佳時，Node Auto Repair 會將其封鎖，並將其取代為新的節點。重新排程 Pod 和重新啟動任務取決於標準 Kubernetes 機制和任務的重新啟動政策。
+ [SageMaker HyperPod](https://catalog.workshops.aws/sagemaker-hyperpod-eks/en-US) 深度運作狀態檢查和運作狀態監控代理程式會持續監控 GPU 和 Trainium 型執行個體的運作狀態。它專為 AI/ML 工作負載量身打造，使用標籤 （例如 node-health-status) 來管理節點運作狀態。當節點視為運作狀態不佳時，HyperPod 會觸發自動取代故障的硬體，例如 GPUs。它預設會透過 EFA 的基本運作狀態檢查來偵測網路相關的故障，並支援針對中斷的訓練任務自動恢復，允許任務從最後一個檢查點繼續，將大規模 ML 任務的中斷降至最低。

對於具有自動修復的 EKS 節點監控代理程式和使用 EFA 的 SageMaker HyperPod 叢集，若要監控 EFA 特定指標，例如遠端直接記憶體存取 (RDMA) 錯誤和封包捨棄，請確定已安裝 [AWS EFA](https://docs.aws.amazon.com/eks/latest/userguide/node-efa.html) 驅動程式。此外，我們建議部署 [CloudWatch 可觀測性附加元件](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-EKS-addon.html)或使用 DCGM Exporter 和 Prometheus 和 Grafana 等工具來監控 EFA、GPU，以及針對 SageMaker HyperPod，與其功能相關的特定指標。

### 針對中斷敏感工作負載停用 Karpenter 合併
<a name="_disable_karpenter_consolidation_for_interruption_sensitive_workloads"></a>

對於對中斷敏感的工作負載，例如處理、大規模 AI/ML 預測任務或訓練，我們建議調校 [Karpenter 整合政策](https://karpenter.sh/v1.0/concepts/disruption/#consolidation)，以防止任務執行期間中斷。Karpenter 的合併功能會自動最佳化叢集成本，方法是終止未充分利用的節點，或以價格較低的替代節點取代它們。不過，即使工作負載完全使用 GPU，如果 Karpenter 發現價格較低的適當執行個體類型符合 Pod 的需求，則可能會合併節點，導致任務中斷。

`WhenEmptyOrUnderutilized` 合併政策可能會提早終止節點，導致執行時間延長。例如，由於 Pod 重新排程、資料重新載入，中斷可能會延遲任務恢復，這對於長時間執行的批次推論任務可能非常昂貴。若要緩解這種情況，您可以將 `consolidationPolicy` 設定為 ，`WhenEmpty`並設定`consolidateAfter`持續時間，例如 1 小時，以在工作負載尖峰期間保留節點。例如：

```
disruption:
  consolidationPolicy: WhenEmpty
  consolidateAfter: 60m
```

此方法可改善尖峰批次推論工作負載和其他干擾敏感任務的 Pod 啟動延遲，例如即時線上推論資料處理或模型訓練，其中中斷成本高於運算成本節省。Karpenter [NodePool 中斷預算](https://karpenter.sh/docs/concepts/disruption/#nodepool-disruption-budgets)是管理 Karpenter 中斷的另一項功能。透過預算，您可以確保在所選的 NodePool 中，不超過特定數量的節點節點會在某個時間點中斷。您也可以使用中斷預算來防止在特定時間 （例如尖峰時間） 中斷所有節點。若要進一步了解，請參閱 [Karpenter 合併](https://karpenter.sh/docs/concepts/disruption/#consolidation)文件。

### 使用 ttlSecondsAfterFinished 自動清除 Kubernetes 任務
<a name="_use_ttlsecondsafterfinished_to_auto_clean_up_kubernetes_jobs"></a>

我們建議`ttlSecondsAfterFinished`在 Amazon EKS 中設定 Kubernetes 任務，以自動刪除已完成的任務物件。內嵌任務物件會耗用叢集資源，例如 API 伺服器記憶體，並透過雜亂儀表板 （例如 Grafana、Amazon CloudWatch) 來複雜化監控。例如，將 TTL 設定為 1 小時可確保任務會在完成後不久移除，讓您的叢集保持整齊。如需詳細資訊，請參閱[完成任務的自動清除](https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/)。

### 設定較高優先順序任務/工作負載的低優先順序任務先佔
<a name="_configure_low_priority_job_preemption_for_higher_priority_jobsworkloads"></a>

對於 Amazon EKS 上的混合優先順序 AI/ML 工作負載，您可以設定低優先順序任務先佔，以確保較高優先順序的任務 （例如即時推論） 可快速接收資源。如果沒有先佔，低優先順序工作負載，例如批次程序 （例如批次推論、資料處理）、非批次服務 （例如背景任務、cron 任務） 或 CPU/記憶體密集型任務 （例如 Web 服務），可以透過佔用節點來延遲關鍵 Pod。先佔允許 Kubernetes 在高優先順序 Pod 需要資源時移出低優先順序 Pod，確保在具有 GPUs、CPUs 或記憶體的節點上進行有效率的資源配置。建議使用 Kubernetes `PriorityClass`來指派優先順序`PodDisruptionBudget`並控制移出行為。

```
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: low-priority
value: 100
---
spec:
  priorityClassName: low-priority
```

如需詳細資訊，請參閱 [Kubernetes Priority and Preemption Documentation](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/)。

## 應用程式擴展和效能
<a name="_application_scaling_and_performance"></a>

### 使用 Karpenter 或靜態節點的 ML 工作負載量身訂做運算容量
<a name="_tailor_compute_capacity_for_ml_workloads_with_karpenter_or_static_nodes"></a>

為了確保 Amazon EKS 上機器學習 (ML) 工作流程的成本效益和回應性運算容量，我們建議您根據工作負載的特性和成本承諾量身打造節點佈建策略。以下是兩種考慮方法：使用 [Karpenter](https://karpenter.sh/docs/) 和靜態節點群組即時 just-in-time 擴展預留容量。
+  **Just-in-time資料平面縮放器，例如 Karpenter**：對於具有可變運算需求的動態 ML 工作流程 （例如，GPU 型推論，後面接著 CPU 型繪圖），我們建議您使用just-in-time資料平面縮放器，例如 Karpenter。
+  **將靜態節點群組用於可預測的工作負載**：對於可預測、穩定狀態的 ML 工作負載或使用預留執行個體時，[EKS 受管節點群組](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html)可協助確保預留容量已完全佈建和使用，從而最大限度地節省成本。此方法非常適合透過 RIs 或 ODCRs 遞交的特定執行個體類型。

 **範例** 

這是各種 Karpenter [NodePool](https://karpenter.sh/docs/concepts/nodepools/) 的範例，可啟動執行個體產生大於三個的 `g` Amazon EC2 執行個體。

```
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: gpu-inference
spec:
  template:
    spec:
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["on-demand"]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["g"]
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: ["3"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
      taints:
        - key: nvidia.com/gpu
          effect: NoSchedule
  limits:
    cpu: "1000"
    memory: "4000Gi"
    nvidia.com/gpu: "10"  *# Limit the total number of GPUs to 10 for the NodePool*
  disruption:
    consolidationPolicy: WhenEmpty
    consolidateAfter: 60m
    expireAfter: 720h
```

 **範例** 

使用靜態節點群組進行訓練工作負載的範例：

```
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: ml-cluster
  region: us-west-2
managedNodeGroups:
  - name: gpu-node-group
    instanceType: p4d.24xlarge
    minSize: 2
    maxSize: 2
    desiredCapacity: 2
    taints:
      - key: nvidia.com/gpu
        effect: NoSchedule
```

### 使用污點和容錯，防止在加速執行個體上排程非加速工作負載
<a name="_use_taints_and_tolerations_to_prevent_non_accelerated_workloads_from_being_scheduled_on_accelerated_instances"></a>

在 GPU 資源上排程非加速工作負載不具運算效率，我們建議您使用污點和容錯，以確保非加速工作負載 Pod 不會排程在不適當的節點上。如需詳細資訊，請參閱 [Kubernetes 文件](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/)。

### 根據模型效能擴展
<a name="_scale_based_on_model_performance"></a>

對於推論工作負載，我們建議您使用 Kubernetes Event-Driven Autoscaling (KEDA) 根據模型效能指標進行擴展，例如推論請求或字符輸送量，以及適當的冷卻時間。靜態擴展政策可能會過度佈建或佈建不足的資源，影響成本和延遲。如需進一步了解，請參閱 [KEDA 文件](https://keda.sh/)。

## 進階 GPU 管理的動態資源配置
<a name="aiml-dra"></a>

 [動態資源配置 (DRA)](https://kubernetes.io/docs/concepts/scheduling-eviction/dynamic-resource-allocation/#enabling-dynamic-resource-allocation) 代表 Kubernetes GPU 資源管理的基本進展。DRA 超越了傳統的裝置外掛程式限制，以啟用複雜的 GPU 共用、拓撲感知和跨節點資源協調。適用於 Amazon EKS [1.33 版](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions-standard.html#kubernetes-1-33)的 DRA 透過提供下列項目來解決 AI/ML 工作負載中的重大挑戰：
+ 精細的 GPU 配置
+ 進階共用機制，例如多程序服務 (MPS) 和多執行個體 GPU (MIG)
+ 支援新一代硬體架構，包括 NVIDIA GB200 UltraServers

傳統 GPU 配置會將 GPUs 視為不透明的整數資源，造成顯著的使用不足 （通常在生產叢集中為 30-40%)。這是因為即使只需要部分資源，工作負載也會取得整個 GPUs 的專屬存取權。DRA 透過引入結構化的宣告式配置來轉換此模型，讓 Kubernetes 排程器完全了解硬體特性和工作負載需求。這可實現智慧型配置決策和有效率的資源共用。

### 使用 DRA 而非 NVIDIA 裝置外掛程式的優點
<a name="_advantages_of_using_dra_instead_of_nvidia_device_plugin"></a>

NVIDIA 裝置外掛程式 （從版本 開始`0.12.0`) 支援 GPU 共用機制，包括時間分割、MPS 和 MIG。不過，該 DRA 地址存在架構限制。

 **NVIDIA 裝置外掛程式限制** 
+  **靜態組態：**GPU 共用組態 （時間分割複本和 MPS 設定） 需要透過 進行整個叢集的預先組態`ConfigMaps`。這使得為不同的工作負載提供不同的共用策略變得困難。
+  **有限精細選擇：**雖然裝置外掛程式透過節點標籤公開 GPU 特性，但在排程決策中，工作負載無法動態請求特定 GPU 組態 （記憶體大小和運算功能）。
+  **無跨節點資源協調：**無法管理跨多個節點的分散式 GPU 資源，或表達複雜的拓撲需求，例如 NVIDIA GB200 等系統的 NVLink 網域。
+  **排程器限制：**Kubernetes 排程器會將 GPU 資源視為不透明整數，限制其做出拓撲感知決策或處理複雜資源相依性的能力。
+  **組態複雜性：**設定不同的共用策略需要多個仔細`ConfigMaps`的節點標記，從而產生操作複雜性。

 **搭配 DRA 的解決方案** 
+  **動態資源選擇：**DRA 允許工作負載在透過 的請求時間指定詳細需求 (GPU 記憶體、驅動程式版本和特定屬性）`resourceclaims`。這可讓資源比對更具彈性。
+  **拓撲感知：**透過結構化參數和裝置選擇器，DRA 可處理複雜的需求，例如跨節點 GPU 通訊和記憶體一致性互連。
+  **跨節點資源管理：**`computeDomains`啟用跨多個節點的分散式 GPU 資源協調，對於具有 IMEX 通道的 GB200 等系統至關重要。
+  **工作負載特定的組態：**每個 `ResourceClaim` 指定不同的共用策略和組態，允許每個工作負載的精細控制，而不是整個叢集的設定。
+  **增強型排程器整合：**DRA 提供排程器詳細的裝置資訊，並根據硬體拓撲和資源特性進行更明智的置放決策。

重要：DRA 不會完全取代 NVIDIA 裝置外掛程式。NVIDIA DRA 驅動程式可與裝置外掛程式搭配使用，以提供增強功能。裝置外掛程式會繼續處理基本的 GPU 探索和管理，而 DRA 新增進階配置和排程功能。

### DRA 支援的執行個體及其功能
<a name="_instances_supported_by_dra_and_their_features"></a>

DRA 支援因 Amazon EC2 執行個體系列和 GPU 架構而異，如下表所示。


| 執行個體系列 | GPU 類型 | 時間分割 | MIG 支援 | MPS 支援 | IMEX 支援 | 使用案例 | 
| --- | --- | --- | --- | --- | --- | --- | 
|  G5  |  NVIDIA A10G  |  是  |  否  |  是  |  否  |  推論和圖形工作負載  | 
|  G6  |  NVIDIA L4  |  是  |  否  |  是  |  否  |  AI 推論和影片處理  | 
|  G6e  |  NVIDIA L40S  |  是  |  否  |  是  |  否  |  訓練、推論和圖形  | 
|  P4d/P4de  |  NVIDIA A100  |  是  |  是  |  是  |  否  |  大規模訓練和 HPC  | 
|  P5  |  NVIDIA H100  |  是  |  是  |  是  |  否  |  基礎模型訓練  | 
|  P6  |  NVIDIA B200  |  是  |  是  |  是  |  否  |  十億或兆參數模型、分散式訓練和推論  | 
|  P6e  |  NVIDIA GB200  |  是  |  是  |  是  |  是  |  十億或兆參數模型、分散式訓練和推論  | 

以下是 資料表中每個功能的描述：
+  **時間分割**：允許多個工作負載隨時間共用 GPU 運算資源。
+  **多執行個體 GPU (MIG)**：建立隔離 GPU 執行個體的硬體層級分割。
+  **多程序服務 (MPS)**：在單一 GPU 上啟用多個 CUDA 程序的並行執行。
+  **節點間記憶體交換 (IMEX)**：GB200 UltraServers 跨節點的記憶體一致性通訊。

### 其他資源
<a name="_additional_resources"></a>

如需 Kubernetes DRA 和 NVIDIA DRA 驅動程式的詳細資訊，請參閱 GitHub 上的下列資源：
+ Kubernetes [dynamic-resource-allocation](https://github.com/kubernetes/dynamic-resource-allocation) 
+  [DRA 的 Kubernetes 增強提案](https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/3063-dynamic-resource-allocation) 
+  [適用於 GPUs 的 NVIDIA DRA 驅動程式](https://github.com/NVIDIA/k8s-dra-driver-gpu) 
+  [NVIDIA DRA 範例和快速入門](https://github.com/NVIDIA/k8s-dra-driver-gpu/tree/main/demo/specs/quickstart) 

### 設定動態資源配置以進行進階 GPU 管理
<a name="aiml-dra-setup"></a>

下列主題說明如何設定動態資源配置 (DRA) 以進行進階 GPU 管理。

#### 先決條件
<a name="aiml-dra-prereqs"></a>

在 Amazon EKS 上實作 DRA 之前，請確定您的環境符合下列要求。

##### 叢集組態
<a name="aiml-dra-configuration"></a>
+ 執行版本 `1.33`或更新版本的 Amazon EKS 叢集
+ Amazon EKS 受管節點群組 (DRA 目前僅支援具有 AL2023 和 Bottlerocket NVIDIA 最佳化 AMIs受管節點群組，[不支援 Karpenter](https://github.com/kubernetes-sigs/karpenter/issues/1231))
+ 具有適當執行個體類型的 NVIDIA GPU 工作者節點

##### 必要元件
<a name="aiml-dra-components"></a>
+ NVIDIA 裝置外掛程式版本 `0.17.1` 或更新版本
+ NVIDIA DRA 驅動程式版本 `25.3.0` 或更新版本

#### 步驟 1：使用 eksctl 建立具有已啟用 DRA 之節點群組的叢集
<a name="aiml-dra-create-cluster"></a>

1. 建立名為 的叢集組態檔案`dra-eks-cluster.yaml`：

   ```
   ---
   apiVersion: eksctl.io/v1alpha5
   kind: ClusterConfig
   
   metadata:
     name: dra-eks-cluster
     region: us-west-2
     version: '1.33'
   
   managedNodeGroups:
   - name: gpu-dra-nodes
     amiFamily: AmazonLinux2023
     instanceType: g6.12xlarge
     desiredCapacity: 2
     minSize: 1
     maxSize: 3
   
     labels:
       node-type: "gpu-dra"
       nvidia.com/gpu.present: "true"
   
     taints:
     - key: nvidia.com/gpu
       value: "true"
       effect: NoSchedule
   ```

1. 建立叢集：

   ```
   eksctl create cluster -f dra-eks-cluster.yaml
   ```

#### 步驟 2：部署 NVIDIA 裝置外掛程式
<a name="aiml-dra-nvidia-plugin"></a>

部署 NVIDIA 裝置外掛程式以啟用基本 GPU 探索：

1. 新增 NVIDIA 裝置外掛程式 Helm 儲存庫：

   ```
   helm repo add nvidia https://nvidia.github.io/k8s-device-plugin
   helm repo update
   ```

1. 為裝置外掛程式建立自訂值：

   ```
   cat <<EOF > nvidia-device-plugin-values.yaml
   gfd:
     enabled: true
   nfd:
     enabled: true
   tolerations:
     - key: nvidia.com/gpu
       operator: Exists
       effect: NoSchedule
   EOF
   ```

1. 安裝 NVIDIA 裝置外掛程式：

   ```
   helm install nvidia-device-plugin nvidia/nvidia-device-plugin \
    --namespace nvidia-device-plugin \
    --create-namespace \
    --version v0.17.1 \
    --values nvidia-device-plugin-values.yaml
   ```

#### 步驟 3：部署 NVIDIA DRA 驅動程式 Helm Chart
<a name="aiml-dra-helm-chart"></a>

1. 建立 DRA 驅動程式`dra-driver-values.yaml`的值檔案：

   ```
   ---
   nvidiaDriverRoot: /
   
   gpuResourcesEnabledOverride: true
   
   resources:
     gpus:
       enabled: true
     computeDomains:
       enabled: true  # Enable for GB200 IMEX support
   
   controller:
     tolerations:
     - key: nvidia.com/gpu
       operator: Exists
       effect: NoSchedule
   
   kubeletPlugin:
     affinity:
       nodeAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
           nodeSelectorTerms:
           - matchExpressions:
             - key: "nvidia.com/gpu.present"
               operator: In
               values: ["true"]
     tolerations:
     - key: nvidia.com/gpu
       operator: Exists
       effect: NoSchedule
   ```

1. 新增 NVIDIA NGC Helm 儲存庫：

   ```
   helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
   helm repo update
   ```

1. 安裝 NVIDIA DRA 驅動程式：

   ```
   helm install nvidia-dra-driver nvidia/nvidia-dra-driver-gpu \
    --version="25.3.0-rc.2" \
    --namespace nvidia-dra-driver \
    --create-namespace \
    --values dra-driver-values.yaml
   ```

#### 步驟 4：驗證 DRA 安裝
<a name="aiml-dra-verify"></a>

1. 確認 DRA API 資源可用：

   ```
   kubectl api-resources | grep resource.k8s.io/v1beta1
   ```

   以下是預期的輸出：

   ```
   deviceclasses resource.k8s.io/v1beta1 false DeviceClass
   resourceclaims resource.k8s.io/v1beta1 true ResourceClaim
   resourceclaimtemplates resource.k8s.io/v1beta1 true ResourceClaimTemplate
   resourceslices resource.k8s.io/v1beta1 false ResourceSlice
   ```

1. 檢查可用的裝置類別：

   ```
   kubectl get deviceclasses
   ```

   以下是預期輸出的範例：

   ```
   NAME                                        AGE
   compute-domain-daemon.nvidia.com            4h39m
   compute-domain-default-channel.nvidia.com   4h39m
   gpu.nvidia.com                              4h39m
   mig.nvidia.com                              4h39m
   ```

   當新建立的 G6 GPU 執行個體加入已啟用 DRA 的 Amazon EKS 叢集時，會發生下列動作：
   + NVIDIA DRA 驅動程式會自動探索 A10G GPU，並在該節點`resourceslices`上建立兩個 GPU。
   + `gpu.nvidia.com` 配量會將實體 A10G GPU 裝置與其規格 （記憶體、運算功能等） 註冊。
   + 由於 A10G 不支援 MIG 分割，`compute-domain.nvidia.com`配量會建立代表 GPU 整個運算內容的單一運算網域。
   + 這些`resourceslices`接著會發佈至 Kubernetes API 伺服器，讓 GPU 資源可透過 進行排程`resourceclaims`。

     DRA 排程器現在可以智慧地將此 GPU 配置給透過 請求 GPU 資源的 Pod`resourceclaimtemplates`，相較於傳統的裝置外掛程式方法，提供更靈活的資源管理。這會自動發生，無需手動介入。一旦 DRA 驅動程式完成資源探索和註冊程序，節點即可直接用於 GPU 工作負載。

     當您執行下列命令時：

     ```
     kubectl get resourceslices
     ```

     以下是預期輸出的範例：

     ```
     NAME                                                          NODE                             DRIVER                       POOL                             AGE
     ip-100-64-129-47.ec2.internal-compute-domain.nvidia.com-rwsts ip-100-64-129-47.ec2.internal    compute-domain.nvidia.com    ip-100-64-129-47.ec2.internal    35m
     ip-100-64-129-47.ec2.internal-gpu.nvidia.com-6kndg            ip-100-64-129-47.ec2.internal    gpu.nvidia.com               ip-100-64-129-47.ec2.internal    35m
     ```

繼續進行[使用動態資源配置排程簡單的 GPU 工作負載](#aiml-dra-workload)。

### 使用動態資源配置排程簡單的 GPU 工作負載
<a name="aiml-dra-workload"></a>

若要使用動態資源配置 (DRA) 排程簡單的 GPU 工作負載，請執行下列步驟。在繼續之前，請確定您已遵循 [設定動態資源配置以進行進階 GPU 管理](#aiml-dra-setup)。

1. 使用名為 `ResourceClaimTemplate` 的檔案建立 GPU 配置的基本`basic-gpu-claim-template.yaml`：

   ```
   ---
   apiVersion: v1
   kind: Namespace
   metadata:
     name: gpu-test1
   
   ---
   apiVersion: resource.k8s.io/v1beta1
   kind: ResourceClaimTemplate
   metadata:
     namespace: gpu-test1
     name: single-gpu
   spec:
     spec:
       devices:
         requests:
         - name: gpu
           deviceClassName: gpu.nvidia.com
   ```

1. 套用範本：

   ```
   kubectl apply -f basic-gpu-claim-template.yaml
   ```

1. 驗證狀態：

   ```
   kubectl get resourceclaimtemplates -n gpu-test1
   ```

   下列為範例輸出：

   ```
   NAME         AGE
   single-gpu   9m16s
   ```

1. 建立使用 `ResourceClaimTemplate` 檔案名為 的 Pod`basic-gpu-pod.yaml`：

   ```
   ---
   apiVersion: v1
   kind: Pod
   metadata:
     namespace: gpu-test1
     name: gpu-pod
     labels:
       app: pod
   spec:
     containers:
     - name: ctr0
       image: ubuntu:22.04
       command: ["bash", "-c"]
       args: ["nvidia-smi -L; trap 'exit 0' TERM; sleep 9999 & wait"]
       resources:
         claims:
         - name: gpu0
     resourceClaims:
     - name: gpu0
       resourceClaimTemplateName: single-gpu
     nodeSelector:
       NodeGroupType: gpu-dra
       nvidia.com/gpu.present: "true"
     tolerations:
     - key: "nvidia.com/gpu"
       operator: "Exists"
       effect: "NoSchedule"
   ```

1. 套用和監控 Pod：

   ```
   kubectl apply -f basic-gpu-pod.yaml
   ```

1. 檢查 Pod 狀態：

   ```
   kubectl get pod -n gpu-test1
   ```

   以下是預期的輸出範例：

   ```
   NAME      READY   STATUS    RESTARTS   AGE
   gpu-pod   1/1     Running   0          13m
   ```

1. 檢查`ResourceClaim`狀態：

   ```
   kubectl get resourceclaims -n gpu-test1
   ```

   以下是預期的輸出範例：

   ```
   NAME                 STATE                AGE
   gpu-pod-gpu0-l76cg   allocated,reserved   9m6s
   ```

1. 檢視 Pod 日誌以查看 GPU 資訊：

   ```
   kubectl logs gpu-pod -n gpu-test1
   ```

   以下是預期的輸出範例：

   ```
   GPU 0: NVIDIA L4 (UUID: GPU-da7c24d7-c7e3-ed3b-418c-bcecc32af7c5)
   ```

繼續使用 DRA 繼續取得更進階[具有動態資源配置的 GPU 最佳化技術](#aiml-dra-optimization)的 GPU 最佳化技術。

### 具有動態資源配置的 GPU 最佳化技術
<a name="aiml-dra-optimization"></a>

現代 GPU 工作負載需要複雜的資源管理，才能達到最佳的使用率和成本效益。DRA 啟用多種進階最佳化技術，可解決不同的使用案例和硬體功能：
+  **時間分割**可讓多個工作負載隨時間共用 GPU 運算資源，因此非常適合偶爾使用 GPU 的推論工作負載。如需範例，請參閱 [使用時間分割最佳化 GPU 工作負載](#aiml-dra-timeslicing)。
+  **多程序服務 (MPS)** 可在單一 GPU 上並行執行多個 CUDA 程序，與時間分割相比具有更好的隔離能力。如需範例，請參閱 [使用 MPS 最佳化 GPU 工作負載](#aiml-dra-mps)。
+  **多執行個體 GPU (MIG)** 提供硬體層級分割，以專用運算和記憶體資源建立隔離的 GPU 執行個體。如需範例，請參閱 [使用多執行個體 GPU 最佳化 GPU 工作負載](#aiml-dra-mig)。
+  **Internode Memory Exchange (IMEX)** 可讓跨節點的記憶體一致性通訊，以便在 NVIDIA GB200 系統上進行分散式訓練。如需範例，請參閱 [使用 GB200 P6e 執行個體透過 IMEX 最佳化 GPU 工作負載](#aiml-dra-imex)。

這些技術可以大幅改善資源使用率。Organizations 報告 GPU 使用率從傳統配置的 30-40% 增加到最佳化共用策略的 80-90%。技術選擇取決於工作負載特性、隔離要求和硬體功能。

#### 使用時間分割最佳化 GPU 工作負載
<a name="aiml-dra-timeslicing"></a>

時間分割可讓多個工作負載透過排程在相同的實體 GPU 上循序執行，來共用 GPU 運算資源。它非常適合使用零星 GPU 的推論工作負載。

執行下列步驟。

1. 使用名為 的檔案定義時間分割`ResourceClaimTemplate`的 `timeslicing-claim-template.yaml`：

   ```
   ---
   apiVersion: v1
   kind: Namespace
   metadata:
     name: timeslicing-gpu
   
   ---
   apiVersion: resource.k8s.io/v1beta1
   kind: ResourceClaimTemplate
   metadata:
     name: timeslicing-gpu-template
     namespace: timeslicing-gpu
   spec:
     spec:
       devices:
         requests:
         - name: shared-gpu
           deviceClassName: gpu.nvidia.com
         config:
         - requests: ["shared-gpu"]
           opaque:
             driver: gpu.nvidia.com
             parameters:
               apiVersion: resource.nvidia.com/v1beta1
               kind: GpuConfig
               sharing:
                 strategy: TimeSlicing
   ```

1. 使用具有名為 的檔案的時間分割來定義 Pod`timeslicing-pod.yaml`：

   ```
   ---
   # Pod 1 - Inference workload
   apiVersion: v1
   kind: Pod
   metadata:
     name: inference-pod-1
     namespace: timeslicing-gpu
     labels:
       app: gpu-inference
   spec:
     restartPolicy: Never
     containers:
     - name: inference-container
       image: nvcr.io/nvidia/pytorch:25.04-py3
       command: ["python", "-c"]
       args:
       - |
         import torch
         import time
         import os
         print(f"=== POD 1 STARTING ===")
         print(f"GPU available: {torch.cuda.is_available()}")
         print(f"GPU count: {torch.cuda.device_count()}")
         if torch.cuda.is_available():
             device = torch.cuda.current_device()
             print(f"Current GPU: {torch.cuda.get_device_name(device)}")
             print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB")
             # Simulate inference workload
             for i in range(20):
                 x = torch.randn(1000, 1000).cuda()
                 y = torch.mm(x, x.t())
                 print(f"Pod 1 - Iteration {i+1} completed at {time.strftime('%H:%M:%S')}")
                 time.sleep(60)
         else:
             print("No GPU available!")
             time.sleep(5)
       resources:
         claims:
         - name: shared-gpu-claim
     resourceClaims:
     - name: shared-gpu-claim
       resourceClaimTemplateName: timeslicing-gpu-template
     nodeSelector:
       NodeGroupType: "gpu-dra"
       nvidia.com/gpu.present: "true"
     tolerations:
     - key: nvidia.com/gpu
       operator: Exists
       effect: NoSchedule
   
   
   ---
   # Pod 2 - Training workload
   apiVersion: v1
   kind: Pod
   metadata:
     name: training-pod-2
     namespace: timeslicing-gpu
     labels:
       app: gpu-training
   spec:
     restartPolicy: Never
     containers:
     - name: training-container
       image: nvcr.io/nvidia/pytorch:25.04-py3
       command: ["python", "-c"]
       args:
       - |
         import torch
         import time
         import os
         print(f"=== POD 2 STARTING ===")
         print(f"GPU available: {torch.cuda.is_available()}")
         print(f"GPU count: {torch.cuda.device_count()}")
         if torch.cuda.is_available():
             device = torch.cuda.current_device()
             print(f"Current GPU: {torch.cuda.get_device_name(device)}")
             print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB")
             # Simulate training workload with heavier compute
             for i in range(15):
                 x = torch.randn(2000, 2000).cuda()
                 y = torch.mm(x, x.t())
                 loss = torch.sum(y)
                 print(f"Pod 2 - Training step {i+1}, Loss: {loss.item():.2f} at {time.strftime('%H:%M:%S')}")
                 time.sleep(5)
         else:
             print("No GPU available!")
             time.sleep(60)
       resources:
         claims:
         - name: shared-gpu-claim-2
     resourceClaims:
     - name: shared-gpu-claim-2
       resourceClaimTemplateName: timeslicing-gpu-template
     nodeSelector:
       NodeGroupType: "gpu-dra"
       nvidia.com/gpu.present: "true"
     tolerations:
     - key: nvidia.com/gpu
       operator: Exists
       effect: NoSchedule
   ```

1. 套用範本和 Pod：

   ```
   kubectl apply -f timeslicing-claim-template.yaml
   kubectl apply -f timeslicing-pod.yaml
   ```

1. 監控資源宣告：

   ```
   kubectl get resourceclaims -n timeslicing-gpu -w
   ```

   下列為範例輸出：

   ```
   NAME                                      STATE                AGE
   inference-pod-1-shared-gpu-claim-9p97x    allocated,reserved   21s
   training-pod-2-shared-gpu-claim-2-qghnb   pending              21s
   inference-pod-1-shared-gpu-claim-9p97x    pending              105s
   training-pod-2-shared-gpu-claim-2-qghnb   pending              105s
   inference-pod-1-shared-gpu-claim-9p97x    pending              105s
   training-pod-2-shared-gpu-claim-2-qghnb   allocated,reserved   105s
   inference-pod-1-shared-gpu-claim-9p97x    pending              105s
   ```

第一個 Pod (`inference-pod-1`)
+  **狀態**： `allocated,reserved`
+  **意義**：DRA 找到可用的 GPU，並將其保留給此 Pod
+  **Pod 狀態**：立即開始執行

第二個 Pod (`training-pod-2`)
+  **狀態**： `pending`
+  **意義**：等待 DRA 在相同的 GPU 上設定時間分割
+  **Pod 狀態**：等待排程
+ 狀態將從 移至 `pending` `allocated,reserved`至 `running` 

#### 使用 MPS 最佳化 GPU 工作負載
<a name="aiml-dra-mps"></a>

多程序服務 (MPS) 可在單一 GPU 上並行執行多個 CUDA 內容，比時間分割具有更好的隔離能力。

執行下列步驟。

1. 使用名為 的檔案為 `ResourceClaimTemplate` MPS 定義 `mps-claim-template.yaml`：

   ```
   ---
   apiVersion: v1
   kind: Namespace
   metadata:
     name: mps-gpu
   
   ---
   apiVersion: resource.k8s.io/v1beta1
   kind: ResourceClaimTemplate
   metadata:
     name: mps-gpu-template
     namespace: mps-gpu
   spec:
     spec:
       devices:
         requests:
         - name: shared-gpu
           deviceClassName: gpu.nvidia.com
         config:
         - requests: ["shared-gpu"]
           opaque:
             driver: gpu.nvidia.com
             parameters:
               apiVersion: resource.nvidia.com/v1beta1
               kind: GpuConfig
               sharing:
                 strategy: MPS
   ```

1. 使用 MPS 搭配名為 的檔案來定義 Pod`mps-pod.yaml`：

   ```
   ---
   # Single Pod with Multiple Containers sharing GPU via MPS
   apiVersion: v1
   kind: Pod
   metadata:
     name: mps-multi-container-pod
     namespace: mps-gpu
     labels:
       app: mps-demo
   spec:
     restartPolicy: Never
     containers:
     # Container 1 - Inference workload
     - name: inference-container
       image: nvcr.io/nvidia/pytorch:25.04-py3
       command: ["python", "-c"]
       args:
       - |
         import torch
         import torch.nn as nn
         import time
         import os
   
         print(f"=== INFERENCE CONTAINER STARTING ===")
         print(f"Process ID: {os.getpid()}")
         print(f"GPU available: {torch.cuda.is_available()}")
         print(f"GPU count: {torch.cuda.device_count()}")
   
         if torch.cuda.is_available():
             device = torch.cuda.current_device()
             print(f"Current GPU: {torch.cuda.get_device_name(device)}")
             print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB")
   
             # Create inference model
             model = nn.Sequential(
                 nn.Linear(1000, 500),
                 nn.ReLU(),
                 nn.Linear(500, 100)
             ).cuda()
   
             # Run inference
             for i in range(1, 999999):
                 with torch.no_grad():
                     x = torch.randn(128, 1000).cuda()
                     output = model(x)
                     result = torch.sum(output)
                     print(f"Inference Container PID {os.getpid()}: Batch {i}, Result: {result.item():.2f} at {time.strftime('%H:%M:%S')}")
                 time.sleep(2)
         else:
             print("No GPU available!")
             time.sleep(60)
       resources:
         claims:
         - name: shared-gpu-claim
           request: shared-gpu
   
     # Container 2 - Training workload
     - name: training-container
       image: nvcr.io/nvidia/pytorch:25.04-py3
       command: ["python", "-c"]
       args:
       - |
         import torch
         import torch.nn as nn
         import time
         import os
   
         print(f"=== TRAINING CONTAINER STARTING ===")
         print(f"Process ID: {os.getpid()}")
         print(f"GPU available: {torch.cuda.is_available()}")
         print(f"GPU count: {torch.cuda.device_count()}")
   
         if torch.cuda.is_available():
             device = torch.cuda.current_device()
             print(f"Current GPU: {torch.cuda.get_device_name(device)}")
             print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB")
   
             # Create training model
             model = nn.Sequential(
                 nn.Linear(2000, 1000),
                 nn.ReLU(),
                 nn.Linear(1000, 500),
                 nn.ReLU(),
                 nn.Linear(500, 10)
             ).cuda()
   
             criterion = nn.MSELoss()
             optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
   
             # Run training
             for epoch in range(1, 999999):
                 x = torch.randn(64, 2000).cuda()
                 target = torch.randn(64, 10).cuda()
   
                 optimizer.zero_grad()
                 output = model(x)
                 loss = criterion(output, target)
                 loss.backward()
                 optimizer.step()
   
                 print(f"Training Container PID {os.getpid()}: Epoch {epoch}, Loss: {loss.item():.4f} at {time.strftime('%H:%M:%S')}")
                 time.sleep(3)
         else:
             print("No GPU available!")
             time.sleep(60)
       resources:
         claims:
         - name: shared-gpu-claim
           request: shared-gpu
   
     resourceClaims:
     - name: shared-gpu-claim
       resourceClaimTemplateName: mps-gpu-template
   
     nodeSelector:
       NodeGroupType: "gpu-dra"
       nvidia.com/gpu.present: "true"
     tolerations:
     - key: nvidia.com/gpu
       operator: Exists
       effect: NoSchedule
   ```

1. 套用範本並建立多個 MPS Pod：

   ```
   kubectl apply -f mps-claim-template.yaml
   kubectl apply -f mps-pod.yaml
   ```

1. 監控資源宣告：

   ```
   kubectl get resourceclaims -n mps-gpu -w
   ```

   下列為範例輸出：

   ```
   NAME                                             STATE                AGE
   mps-multi-container-pod-shared-gpu-claim-2p9kx   allocated,reserved   86s
   ```

此組態透過動態資源分配 (DRA) 使用 NVIDIA Multi-Process Service (MPS) 示範真正的 GPU 共用。與使用 GPU 依序輪換工作負載的時間分割不同，MPS 可讓兩個容器同時在相同的實體 GPU 上執行。關鍵洞見是 DRA MPS 共用需要單一 Pod 中的多個容器，而不是多個單獨的 Pod。部署時，DRA 驅動程式會將一個配置`ResourceClaim`給 Pod，並自動設定 MPS，以允許推論和訓練容器同時執行。

每個容器都有自己的隔離 GPU 記憶體空間和運算資源，搭配 MPS 協助程式來協調基礎硬體的存取。您可以執行下列動作來驗證是否正常運作：
+ 檢查 `nvidia-smi`，這會將兩個容器顯示為共用相同 GPU 裝置的 M\$1C (`MPS + Compute`) 程序。
+ 從兩個容器監控日誌，這會顯示可同時執行的交錯時間戳記。

這種方法允許互補工作負載有效地共用昂貴的 GPU 硬體，而不是讓單一程序未充分利用 GPU 使用率，從而最大限度地提高 GPU 使用率。

##### Container1： `inference-container`
<a name="_container1_inference_container"></a>

```
root@mps-multi-container-pod:/workspace# nvidia-smi
Wed Jul 16 21:09:30 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 570.158.01             Driver Version: 570.158.01     CUDA Version: 12.9     |
|-----------------------------------------+------------------------+----------------------+
| 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   48C    P0             28W /   72W |     597MiB /  23034MiB |      0%   E. Process |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|    0   N/A  N/A               1    M+C   python                                  246MiB |
+-----------------------------------------------------------------------------------------+
```

##### Container2： `training-container`
<a name="_container2_training_container"></a>

```
root@mps-multi-container-pod:/workspace# nvidia-smi
Wed Jul 16 21:16:00 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 570.158.01             Driver Version: 570.158.01     CUDA Version: 12.9     |
|-----------------------------------------+------------------------+----------------------+
| 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   51C    P0             28W /   72W |     597MiB /  23034MiB |      0%   E. Process |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|    0   N/A  N/A               1    M+C   python                                  314MiB |
+-----------------------------------------------------------------------------------------+
```

#### 使用多執行個體 GPU 最佳化 GPU 工作負載
<a name="aiml-dra-mig"></a>

多執行個體 GPU (MIG) 提供硬體層級分割，建立具有專用運算和記憶體資源的隔離 GPU 執行個體。

搭配各種設定檔使用動態 MIG 分割需要 [NVIDIA GPU Operator](https://github.com/NVIDIA/gpu-operator)。NVIDIA GPU Operator 使用 [MIG Manager](https://github.com/NVIDIA/gpu-operator/blob/47fea81ac752a68745300b5ec77f3bd8ee69d059/deployments/gpu-operator/values.yaml#L374) 建立 MIG 設定檔，並重新啟動 P4D, P4De, P5, P6 等 GPU 執行個體，以套用組態變更。GPU Operator 透過 MIG Manager 元件包含完整的 MIG 管理功能，可監控節點標籤變更，並自動套用適當的 MIG 組態。請求 MIG 設定檔變更時，運算子會正常關閉所有 GPU 用戶端、套用新的分割區幾何，並重新啟動受影響的服務。此程序需要為 GPU 執行個體重新開機節點，以確保 GPU 狀態轉移乾淨。這就是為什麼在 MIG Manager 組態`WITH0REBOOT=true`中啟用 對成功的 MIG 部署至關重要。

您需要 [NVIDIA DRA 驅動程式](https://github.com/NVIDIA/k8s-dra-driver-gpu)和 NVIDIA GPU Operator 才能在 Amazon EKS 中使用 MIG。此外，您不需要 NVIDIA 裝置外掛程式和 DCGM Exporter，因為這些是 NVIDIA GPU Operator 的一部分。由於 EKS NVIDIA AMIs 隨附預先安裝的 NVIDIA 驅動程式，因此我們停用 GPU Operator 部署驅動程式，以避免衝突並利用執行個體上已存在的最佳化驅動程式。NVIDIA DRA 驅動程式會處理 MIG 執行個體的動態資源配置，而 GPU Operator 會管理整個 GPU 生命週期。這包括 MIG 組態、裝置外掛程式功能、透過 DCGM 監控，以及節點功能探索。這種整合方法為企業 GPU 管理提供了完整的解決方案，具有硬體層級隔離和動態資源配置功能。

##### 步驟 1：部署 NVIDIA GPU Operator
<a name="_step_1_deploy_nvidia_gpu_operator"></a>

1. 新增 NVIDIA GPU Operator 儲存庫：

   ```
   helm repo add nvidia https://nvidia.github.io/gpu-operator
   helm repo update
   ```

1. 建立`gpu-operator-values.yaml`檔案：

   ```
   driver:
     enabled: false
   
   mig:
     strategy: mixed
   
   migManager:
     enabled: true
     env:
       - name: WITH_REBOOT
         value: "true"
     config:
       create: true
       name: custom-mig-parted-configs
       default: "all-disabled"
       data:
         config.yaml: |-
           version: v1
           mig-configs:
             all-disabled:
               - devices: all
                 mig-enabled: false
   
             # P4D profiles (A100 40GB)
             p4d-half-balanced:
               - devices: [0, 1, 2, 3]
                 mig-enabled: true
                 mig-devices:
                   "1g.5gb": 2
                   "2g.10gb": 1
                   "3g.20gb": 1
               - devices: [4, 5, 6, 7]
                 mig-enabled: false
   
             # P4DE profiles (A100 80GB)
             p4de-half-balanced:
               - devices: [0, 1, 2, 3]
                 mig-enabled: true
                 mig-devices:
                   "1g.10gb": 2
                   "2g.20gb": 1
                   "3g.40gb": 1
               - devices: [4, 5, 6, 7]
                 mig-enabled: false
   
   devicePlugin:
     enabled: true
     config:
       name: ""
       create: false
       default: ""
   
   toolkit:
     enabled: true
   
   nfd:
     enabled: true
   
   gfd:
     enabled: true
   
   dcgmExporter:
     enabled: true
     serviceMonitor:
       enabled: true
       interval: 15s
       honorLabels: false
       additionalLabels:
         release: kube-prometheus-stack
   
   nodeStatusExporter:
     enabled: false
   
   operator:
     defaultRuntime: containerd
     runtimeClass: nvidia
     resources:
       limits:
         cpu: 500m
         memory: 350Mi
       requests:
         cpu: 200m
         memory: 100Mi
   
   daemonsets:
     tolerations:
       - key: "nvidia.com/gpu"
         operator: "Exists"
         effect: "NoSchedule"
     nodeSelector:
       accelerator: nvidia
     priorityClassName: system-node-critical
   ```

1. 使用 `gpu-operator-values.yaml` 檔案安裝 GPU Operator：

   ```
   helm install gpu-operator nvidia/gpu-operator \
     --namespace gpu-operator \
     --create-namespace \
     --version v25.3.1 \
     --values gpu-operator-values.yaml
   ```

   此 Helm Chart 部署下列元件和多個 MIG 設定檔：
   + 裝置外掛程式 (GPU 資源排程）
   + DCGM Exporter (GPU 指標和監控）
   + 節點功能探索 (NFD - 硬體標籤）
   + GPU 功能探索 (GFD - GPU 特定標籤）
   + MIG Manager （多執行個體 GPU 分割）
   + Container Toolkit (GPU 容器執行時間）
   + Operator Controller （生命週期管理）

1. 驗證部署 Pod：

   ```
   kubectl get pods -n gpu-operator
   ```

   下列為範例輸出：

   ```
   NAME                                                              READY   STATUS      RESTARTS        AGE
   gpu-feature-discovery-27rdq                                       1/1     Running     0               3h31m
   gpu-operator-555774698d-48brn                                     1/1     Running     0               4h8m
   nvidia-container-toolkit-daemonset-sxmh9                          1/1     Running     1 (3h32m ago)   4h1m
   nvidia-cuda-validator-qb77g                                       0/1     Completed   0               3h31m
   nvidia-dcgm-exporter-cvzd7                                        1/1     Running     0               3h31m
   nvidia-device-plugin-daemonset-5ljm5                              1/1     Running     0               3h31m
   nvidia-gpu-operator-node-feature-discovery-gc-67f66fc557-q5wkt    1/1     Running     0               4h8m
   nvidia-gpu-operator-node-feature-discovery-master-5d8ffddcsl6s6   1/1     Running     0               4h8m
   nvidia-gpu-operator-node-feature-discovery-worker-6t4w7           1/1     Running     1 (3h32m ago)   4h1m
   nvidia-gpu-operator-node-feature-discovery-worker-9w7g8           1/1     Running     0               4h8m
   nvidia-gpu-operator-node-feature-discovery-worker-k5fgs           1/1     Running     0               4h8m
   nvidia-mig-manager-zvf54                                          1/1     Running     1 (3h32m ago)   3h35m
   ```

1. 使用 p4De 受管節點群組建立 Amazon EKS 叢集，以測試 MIG 範例：

   ```
   apiVersion: eksctl.io/v1alpha5
   kind: ClusterConfig
   
   metadata:
     name: dra-eks-cluster
     region: us-east-1
     version: '1.33'
   
   managedNodeGroups:
   # P4DE MIG Node Group with Capacity Block Reservation
   - name: p4de-mig-nodes
     amiFamily: AmazonLinux2023
     instanceType: p4de.24xlarge
   
     # Capacity settings
     desiredCapacity: 0
     minSize: 0
     maxSize: 1
   
     # Use specific subnet in us-east-1b for capacity reservation
     subnets:
       - us-east-1b
   
     # AL2023 NodeConfig for RAID0 local storage only
     nodeadmConfig:
       apiVersion: node.eks.aws/v1alpha1
       kind: NodeConfig
       spec:
         instance:
           localStorage:
             strategy: RAID0
   
     # Node labels for MIG configuration
     labels:
       nvidia.com/gpu.present: "true"
       nvidia.com/gpu.product: "A100-SXM4-80GB"
       nvidia.com/mig.config: "p4de-half-balanced"
       node-type: "p4de"
       vpc.amazonaws.com/efa.present: "true"
       accelerator: "nvidia"
   
     # Node taints
     taints:
       - key: nvidia.com/gpu
         value: "true"
         effect: NoSchedule
   
     # EFA support
     efaEnabled: true
   
     # Placement group for high-performance networking
     placementGroup:
       groupName: p4de-placement-group
       strategy: cluster
   
     # Capacity Block Reservation (CBR)
     # Ensure CBR ID matches the subnet AZ with the Nodegroup subnet
     spot: false
     capacityReservation:
       capacityReservationTarget:
         capacityReservationId: "cr-abcdefghij"  # Replace with your capacity reservation ID
   ```

   NVIDIA GPU Operator 使用新增至節點的標籤，`nvidia.com/mig.config: "p4de-half-balanced"`並以指定的設定檔分割 GPU。

1. 登入`p4de`執行個體。

1. 執行以下命令：

   ```
   nvidia-smi -L
   ```

   您應該會看到下列範例輸出：

   ```
   [root@ip-100-64-173-145 bin]# nvidia-smi -L
   GPU 0: NVIDIA A100-SXM4-80GB (UUID: GPU-ab52e33c-be48-38f2-119e-b62b9935925a)
     MIG 3g.40gb     Device  0: (UUID: MIG-da972af8-a20a-5f51-849f-bc0439f7970e)
     MIG 2g.20gb     Device  1: (UUID: MIG-7f9768b7-11a6-5de9-a8aa-e9c424400da4)
     MIG 1g.10gb     Device  2: (UUID: MIG-498adad6-6cf7-53af-9d1a-10cfd1fa53b2)
     MIG 1g.10gb     Device  3: (UUID: MIG-3f55ef65-1991-571a-ac50-0dbf50d80c5a)
   GPU 1: NVIDIA A100-SXM4-80GB (UUID: GPU-0eabeccc-7498-c282-0ac7-d3c09f6af0c8)
     MIG 3g.40gb     Device  0: (UUID: MIG-80543849-ea3b-595b-b162-847568fe6e0e)
     MIG 2g.20gb     Device  1: (UUID: MIG-3af1958f-fac4-59f1-8477-9f8d08c55029)
     MIG 1g.10gb     Device  2: (UUID: MIG-401088d2-716f-527b-a970-b1fc7a4ac6b2)
     MIG 1g.10gb     Device  3: (UUID: MIG-8c56c75e-5141-501c-8f43-8cf22f422569)
   GPU 2: NVIDIA A100-SXM4-80GB (UUID: GPU-1c7a1289-243f-7872-a35c-1d2d8af22dd0)
     MIG 3g.40gb     Device  0: (UUID: MIG-e9b44486-09fc-591a-b904-0d378caf2276)
     MIG 2g.20gb     Device  1: (UUID: MIG-ded93941-9f64-56a3-a9b1-a129c6edf6e4)
     MIG 1g.10gb     Device  2: (UUID: MIG-6c317d83-a078-5c25-9fa3-c8308b379aa1)
     MIG 1g.10gb     Device  3: (UUID: MIG-2b070d39-d4e9-5b11-bda6-e903372e3d08)
   GPU 3: NVIDIA A100-SXM4-80GB (UUID: GPU-9a6250e2-5c59-10b7-2da8-b61d8a937233)
     MIG 3g.40gb     Device  0: (UUID: MIG-20e3cd87-7a57-5f1b-82e7-97b14ab1a5aa)
     MIG 2g.20gb     Device  1: (UUID: MIG-04430354-1575-5b42-95f4-bda6901f1ace)
     MIG 1g.10gb     Device  2: (UUID: MIG-d62ec8b6-e097-5e99-a60c-abf8eb906f91)
     MIG 1g.10gb     Device  3: (UUID: MIG-fce20069-2baa-5dd4-988a-cead08348ada)
   GPU 4: NVIDIA A100-SXM4-80GB (UUID: GPU-5d09daf0-c2eb-75fd-3919-7ad8fafa5f86)
   GPU 5: NVIDIA A100-SXM4-80GB (UUID: GPU-99194e04-ab2a-b519-4793-81cb2e8e9179)
   GPU 6: NVIDIA A100-SXM4-80GB (UUID: GPU-c1a1910f-465a-e16f-5af1-c6aafe499cd6)
   GPU 7: NVIDIA A100-SXM4-80GB (UUID: GPU-c2cfafbc-fd6e-2679-e955-2a9e09377f78)
   ```

NVIDIA GPU Operator 已成功將 `p4de-half-balanced` MIG 設定檔套用至 P4DE 執行個體，並依設定建立硬體層級 GPU 分割區。以下是分割的運作方式：

GPU Operator 從您的內嵌 MIG 設定檔套用此組態：

```
p4de-half-balanced:
  - devices: [0, 1, 2, 3]        # First 4 GPUs: MIG enabled
    mig-enabled: true
    mig-devices:
      "1g.10gb": 2               # 2x small instances (10GB each)
      "2g.20gb": 1               # 1x medium instance (20GB)
      "3g.40gb": 1               # 1x large instance (40GB)
  - devices: [4, 5, 6, 7]        # Last 4 GPUs: Full GPUs
    mig-enabled: false
```

從您的`nvidia-smi -L`輸出中，GPU Operator 建立的內容如下：
+ 啟用 MIG 的 GPUs (0-3)：硬體分割
  + GPU 0：NVIDIA A100-SXM4-80GB
    + MIG 3g.40gb 裝置 0 – 大型工作負載 (40GB 記憶體、42 個 SMs)
    + MIG 2g.20gb 裝置 1 – 中型工作負載 (20GB 記憶體、28 個 SMs)
    + MIG 1g.10gb 裝置 2 – 小型工作負載 (10GB 記憶體、14 個 SMs)
    + MIG 1g.10gb 裝置 3 – 小型工作負載 (10GB 記憶體、14 個 SMs)
  + GPU 1：NVIDIA A100-SXM4-80GB
    + MIG 3g.40gb 裝置 0 – 相同的分割區配置
    + MIG 2g.20gb 裝置 1
    + MIG 1g.10gb 裝置 2
    + MIG 1g.10gb 裝置 3
  + GPU 2 和 GPU 3 – 與 GPU 0 和 GPU 1 相同的模式
+ 完整 GPUs (4-7)：無 MIG 分割
  + GPU 4：NVIDIA A100-SXM4-80GB – 完整 80GB GPU
  + GPU 5：NVIDIA A100-SXM4-80GB – 完整 80GB GPU
  + GPU 6：NVIDIA A100-SXM4-80GB – 完整 80GB GPU
  + GPU 7：NVIDIA A100-SXM4-80GB – 完整 80GB GPU

NVIDIA GPU Operator 建立 MIG 分割區後，NVIDIA DRA 驅動程式會自動偵測這些硬體隔離的執行個體，並將其用於 Kubernetes 中的動態資源配置。DRA 驅動程式會使用其特定設定檔 (1g.10gb、2g.20gb、3g.40gb) 探索每個 MIG 執行個體，並透過`mig.nvidia.com`裝置類別將它們公開為可排程的資源。

DRA 驅動程式會持續監控 MIG 拓撲，並維護所有 GPUs 中可用執行個體的庫存。當 Pod 透過 請求特定 MIG 設定檔時`ResourceClaimTemplate`，DRA 驅動程式會智慧地從任何可用的 GPU 選取適當的 MIG 執行個體，從而實現真正的硬體層級多租用戶。此動態配置可讓多個隔離的工作負載同時在相同的實體 GPU 上執行，同時維持嚴格的資源界限和效能保證。

##### 步驟 2：測試 MIG 資源配置
<a name="_step_2_test_mig_resource_allocation"></a>

現在，讓我們執行一些範例，示範 DRA 如何將 MIG 執行個體動態分配給不同的工作負載。部署 `resourceclaimtemplates`和 測試 Pod，以查看 DRA 驅動程式如何將工作負載跨可用的 MIG 分割區放置，允許多個容器與硬體層級隔離共用 GPU 資源。

1. 建立 `mig-claim-template.yaml`以包含 MIG`resourceclaimtemplates`：

   ```
   apiVersion: v1
   kind: Namespace
   metadata:
     name: mig-gpu
   
   ---
   # Template for 3g.40gb MIG instance (Large training)
   apiVersion: resource.k8s.io/v1beta1
   kind: ResourceClaimTemplate
   metadata:
     name: mig-large-template
     namespace: mig-gpu
   spec:
     spec:
       devices:
         requests:
         - name: mig-large
           deviceClassName: mig.nvidia.com
           selectors:
           - cel:
               expression: |
                 device.attributes['gpu.nvidia.com'].profile == '3g.40gb'
   
   ---
   # Template for 2g.20gb MIG instance (Medium training)
   apiVersion: resource.k8s.io/v1beta1
   kind: ResourceClaimTemplate
   metadata:
     name: mig-medium-template
     namespace: mig-gpu
   spec:
     spec:
       devices:
         requests:
         - name: mig-medium
           deviceClassName: mig.nvidia.com
           selectors:
           - cel:
               expression: |
                 device.attributes['gpu.nvidia.com'].profile == '2g.20gb'
   
   ---
   # Template for 1g.10gb MIG instance (Small inference)
   apiVersion: resource.k8s.io/v1beta1
   kind: ResourceClaimTemplate
   metadata:
     name: mig-small-template
     namespace: mig-gpu
   spec:
     spec:
       devices:
         requests:
         - name: mig-small
           deviceClassName: mig.nvidia.com
           selectors:
           - cel:
               expression: |
                 device.attributes['gpu.nvidia.com'].profile == '1g.10gb'
   ```

1. 套用三個範本：

   ```
   kubectl apply -f mig-claim-template.yaml
   ```

1. 執行以下命令：

   ```
   kubectl get resourceclaimtemplates -n mig-gpu
   ```

   下列為範例輸出：

   ```
   NAME                  AGE
   mig-large-template    71m
   mig-medium-template   71m
   mig-small-template    71m
   ```

1. 建立 `mig-pod.yaml` 以排程多個任務，以利用此 `resourceclaimtemplates`：

   ```
   ---
   # ConfigMap containing Python scripts for MIG pods
   apiVersion: v1
   kind: ConfigMap
   metadata:
     name: mig-scripts-configmap
     namespace: mig-gpu
   data:
     large-training-script.py: |
       import torch
       import torch.nn as nn
       import torch.optim as optim
       import time
       import os
   
       print(f"=== LARGE TRAINING POD (3g.40gb) ===")
       print(f"Process ID: {os.getpid()}")
       print(f"GPU available: {torch.cuda.is_available()}")
       print(f"GPU count: {torch.cuda.device_count()}")
   
       if torch.cuda.is_available():
           device = torch.cuda.current_device()
           print(f"Using GPU: {torch.cuda.get_device_name(device)}")
           print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1e9:.1f} GB")
   
           # Large model for 3g.40gb instance
           model = nn.Sequential(
               nn.Linear(2048, 1024),
               nn.ReLU(),
               nn.Linear(1024, 512),
               nn.ReLU(),
               nn.Linear(512, 256),
               nn.ReLU(),
               nn.Linear(256, 10)
           ).cuda()
   
           optimizer = optim.Adam(model.parameters())
           criterion = nn.CrossEntropyLoss()
   
           print(f"Model parameters: {sum(p.numel() for p in model.parameters())}")
   
           # Training loop
           for epoch in range(100):
               # Large batch for 3g.40gb
               x = torch.randn(256, 2048).cuda()
               y = torch.randint(0, 10, (256,)).cuda()
   
               optimizer.zero_grad()
               output = model(x)
               loss = criterion(output, y)
               loss.backward()
               optimizer.step()
   
               if epoch % 10 == 0:
                   print(f"Large Training - Epoch {epoch}, Loss: {loss.item():.4f}, GPU Memory: {torch.cuda.memory_allocated()/1e9:.2f}GB")
               time.sleep(3)
   
           print("Large training completed on 3g.40gb MIG instance")
   
     medium-training-script.py: |
       import torch
       import torch.nn as nn
       import torch.optim as optim
       import time
       import os
   
       print(f"=== MEDIUM TRAINING POD (2g.20gb) ===")
       print(f"Process ID: {os.getpid()}")
       print(f"GPU available: {torch.cuda.is_available()}")
       print(f"GPU count: {torch.cuda.device_count()}")
   
       if torch.cuda.is_available():
           device = torch.cuda.current_device()
           print(f"Using GPU: {torch.cuda.get_device_name(device)}")
           print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1e9:.1f} GB")
   
           # Medium model for 2g.20gb instance
           model = nn.Sequential(
               nn.Linear(1024, 512),
               nn.ReLU(),
               nn.Linear(512, 256),
               nn.ReLU(),
               nn.Linear(256, 10)
           ).cuda()
   
           optimizer = optim.Adam(model.parameters())
           criterion = nn.CrossEntropyLoss()
   
           print(f"Model parameters: {sum(p.numel() for p in model.parameters())}")
   
           # Training loop
           for epoch in range(100):
               # Medium batch for 2g.20gb
               x = torch.randn(128, 1024).cuda()
               y = torch.randint(0, 10, (128,)).cuda()
   
               optimizer.zero_grad()
               output = model(x)
               loss = criterion(output, y)
               loss.backward()
               optimizer.step()
   
               if epoch % 10 == 0:
                   print(f"Medium Training - Epoch {epoch}, Loss: {loss.item():.4f}, GPU Memory: {torch.cuda.memory_allocated()/1e9:.2f}GB")
               time.sleep(4)
   
           print("Medium training completed on 2g.20gb MIG instance")
   
     small-inference-script.py: |
       import torch
       import torch.nn as nn
       import time
       import os
   
       print(f"=== SMALL INFERENCE POD (1g.10gb) ===")
       print(f"Process ID: {os.getpid()}")
       print(f"GPU available: {torch.cuda.is_available()}")
       print(f"GPU count: {torch.cuda.device_count()}")
   
       if torch.cuda.is_available():
           device = torch.cuda.current_device()
           print(f"Using GPU: {torch.cuda.get_device_name(device)}")
           print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1e9:.1f} GB")
   
           # Small model for 1g.10gb instance
           model = nn.Sequential(
               nn.Linear(512, 256),
               nn.ReLU(),
               nn.Linear(256, 10)
           ).cuda()
   
           print(f"Model parameters: {sum(p.numel() for p in model.parameters())}")
   
           # Inference loop
           for i in range(200):
               with torch.no_grad():
                   # Small batch for 1g.10gb
                   x = torch.randn(32, 512).cuda()
                   output = model(x)
                   prediction = torch.argmax(output, dim=1)
   
                   if i % 20 == 0:
                       print(f"Small Inference - Batch {i}, Predictions: {prediction[:5].tolist()}, GPU Memory: {torch.cuda.memory_allocated()/1e9:.2f}GB")
               time.sleep(2)
   
           print("Small inference completed on 1g.10gb MIG instance")
   
   ---
   # Pod 1: Large training workload (3g.40gb)
   apiVersion: v1
   kind: Pod
   metadata:
     name: mig-large-training-pod
     namespace: mig-gpu
     labels:
       app: mig-large-training
       workload-type: training
   spec:
     restartPolicy: Never
     containers:
     - name: large-training-container
       image: nvcr.io/nvidia/pytorch:25.04-py3
       command: ["python", "/scripts/large-training-script.py"]
       volumeMounts:
       - name: script-volume
         mountPath: /scripts
         readOnly: true
       resources:
         claims:
         - name: mig-large-claim
     resourceClaims:
     - name: mig-large-claim
       resourceClaimTemplateName: mig-large-template
     nodeSelector:
       node.kubernetes.io/instance-type: p4de.24xlarge
       nvidia.com/gpu.present: "true"
     tolerations:
     - key: nvidia.com/gpu
       operator: Exists
       effect: NoSchedule
     volumes:
     - name: script-volume
       configMap:
         name: mig-scripts-configmap
         defaultMode: 0755
   
   ---
   # Pod 2: Medium training workload (2g.20gb) - can run on SAME GPU as Pod 1
   apiVersion: v1
   kind: Pod
   metadata:
     name: mig-medium-training-pod
     namespace: mig-gpu
     labels:
       app: mig-medium-training
       workload-type: training
   spec:
     restartPolicy: Never
     containers:
     - name: medium-training-container
       image: nvcr.io/nvidia/pytorch:25.04-py3
       command: ["python", "/scripts/medium-training-script.py"]
       volumeMounts:
       - name: script-volume
         mountPath: /scripts
         readOnly: true
       resources:
         claims:
         - name: mig-medium-claim
     resourceClaims:
     - name: mig-medium-claim
       resourceClaimTemplateName: mig-medium-template
     nodeSelector:
       node.kubernetes.io/instance-type: p4de.24xlarge
       nvidia.com/gpu.present: "true"
     tolerations:
     - key: nvidia.com/gpu
       operator: Exists
       effect: NoSchedule
     volumes:
     - name: script-volume
       configMap:
         name: mig-scripts-configmap
         defaultMode: 0755
   
   ---
   # Pod 3: Small inference workload (1g.10gb) - can run on SAME GPU as Pod 1 & 2
   apiVersion: v1
   kind: Pod
   metadata:
     name: mig-small-inference-pod
     namespace: mig-gpu
     labels:
       app: mig-small-inference
       workload-type: inference
   spec:
     restartPolicy: Never
     containers:
     - name: small-inference-container
       image: nvcr.io/nvidia/pytorch:25.04-py3
       command: ["python", "/scripts/small-inference-script.py"]
       volumeMounts:
       - name: script-volume
         mountPath: /scripts
         readOnly: true
       resources:
         claims:
         - name: mig-small-claim
     resourceClaims:
     - name: mig-small-claim
       resourceClaimTemplateName: mig-small-template
     nodeSelector:
       node.kubernetes.io/instance-type: p4de.24xlarge
       nvidia.com/gpu.present: "true"
     tolerations:
     - key: nvidia.com/gpu
       operator: Exists
       effect: NoSchedule
     volumes:
     - name: script-volume
       configMap:
         name: mig-scripts-configmap
         defaultMode: 0755
   ```

1. 套用此規格，應部署三個 Pod：

   ```
   kubctl apply -f mig-pod.yaml
   ```

   這些 Pod 應由 DRA 驅動程式排程。

1. 檢查 DRA 驅動程式 Pod 日誌，您會看到類似以下的輸出：

   ```
   I0717 21:50:22.925811 1 driver.go:87] NodePrepareResource is called: number of claims: 1
   I0717 21:50:22.932499 1 driver.go:129] Returning newly prepared devices for claim '933e9c72-6fd6-49c5-933c-a896407dc6d1': [&Device{RequestNames:[mig-large],PoolName:ip-100-64-173-145.ec2.internal,DeviceName:gpu-0-mig-9-4-4,CDIDeviceIDs:[k8s.gpu.nvidia.com/device=**gpu-0-mig-9-4-4**],}]
   I0717 21:50:23.186472 1 driver.go:87] NodePrepareResource is called: number of claims: 1
   I0717 21:50:23.191226 1 driver.go:129] Returning newly prepared devices for claim '61e5ddd2-8c2e-4c19-93ae-d317fecb44a4': [&Device{RequestNames:[mig-medium],PoolName:ip-100-64-173-145.ec2.internal,DeviceName:gpu-2-mig-14-0-2,CDIDeviceIDs:[k8s.gpu.nvidia.com/device=**gpu-2-mig-14-0-2**],}]
   I0717 21:50:23.450024 1 driver.go:87] NodePrepareResource is called: number of claims: 1
   I0717 21:50:23.455991 1 driver.go:129] Returning newly prepared devices for claim '1eda9b2c-2ea6-401e-96d0-90e9b3c111b5': [&Device{RequestNames:[mig-small],PoolName:ip-100-64-173-145.ec2.internal,DeviceName:gpu-1-mig-19-2-1,CDIDeviceIDs:[k8s.gpu.nvidia.com/device=**gpu-1-mig-19-2-1**],}]
   ```

1. 驗證 `resourceclaims` 以查看 Pod 狀態：

   ```
   kubectl get resourceclaims -n mig-gpu -w
   ```

   下列為範例輸出：

   ```
   NAME                                             STATE                AGE
   mig-large-training-pod-mig-large-claim-6dpn8     pending              0s
   mig-large-training-pod-mig-large-claim-6dpn8     pending              0s
   mig-large-training-pod-mig-large-claim-6dpn8     allocated,reserved   0s
   mig-medium-training-pod-mig-medium-claim-bk596   pending              0s
   mig-medium-training-pod-mig-medium-claim-bk596   pending              0s
   mig-medium-training-pod-mig-medium-claim-bk596   allocated,reserved   0s
   mig-small-inference-pod-mig-small-claim-d2t58    pending              0s
   mig-small-inference-pod-mig-small-claim-d2t58    pending              0s
   mig-small-inference-pod-mig-small-claim-d2t58    allocated,reserved   0s
   ```

   如您所見，所有 Pod 都會由 DRA 驅動程式`allocated,reserved`從待定移至 。

1. `nvidia-smi` 從節點執行 。您會注意到有三個 Python 處理器正在執行：

   ```
   root@ip-100-64-173-145 bin]# nvidia-smi
   +-----------------------------------------------------------------------------------------+
   | NVIDIA-SMI 570.158.01 Driver Version: 570.158.01 CUDA Version: 12.8 |
   |-----------------------------------------+------------------------+----------------------+
   | 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 A100-SXM4-80GB On | 00000000:10:1C.0 Off | On |
   | N/A 63C P0 127W / 400W | 569MiB / 81920MiB | N/A Default |
   | | | Enabled |
   +-----------------------------------------+------------------------+----------------------+
   | 1 NVIDIA A100-SXM4-80GB On | 00000000:10:1D.0 Off | On |
   | N/A 56C P0 121W / 400W | 374MiB / 81920MiB | N/A Default |
   | | | Enabled |
   +-----------------------------------------+------------------------+----------------------+
   | 2 NVIDIA A100-SXM4-80GB On | 00000000:20:1C.0 Off | On |
   | N/A 63C P0 128W / 400W | 467MiB / 81920MiB | N/A Default |
   | | | Enabled |
   +-----------------------------------------+------------------------+----------------------+
   | 3 NVIDIA A100-SXM4-80GB On | 00000000:20:1D.0 Off | On |
   | N/A 57C P0 118W / 400W | 249MiB / 81920MiB | N/A Default |
   | | | Enabled |
   +-----------------------------------------+------------------------+----------------------+
   | 4 NVIDIA A100-SXM4-80GB On | 00000000:90:1C.0 Off | 0 |
   | N/A 51C P0 77W / 400W | 0MiB / 81920MiB | 0% Default |
   | | | Disabled |
   +-----------------------------------------+------------------------+----------------------+
   | 5 NVIDIA A100-SXM4-80GB On | 00000000:90:1D.0 Off | 0 |
   | N/A 46C P0 69W / 400W | 0MiB / 81920MiB | 0% Default |
   | | | Disabled |
   +-----------------------------------------+------------------------+----------------------+
   | 6 NVIDIA A100-SXM4-80GB On | 00000000:A0:1C.0 Off | 0 |
   | N/A 52C P0 74W / 400W | 0MiB / 81920MiB | 0% Default |
   | | | Disabled |
   +-----------------------------------------+------------------------+----------------------+
   | 7 NVIDIA A100-SXM4-80GB On | 00000000:A0:1D.0 Off | 0 |
   | N/A 47C P0 72W / 400W | 0MiB / 81920MiB | 0% Default |
   | | | Disabled |
   +-----------------------------------------+------------------------+----------------------+
   
   
   +-----------------------------------------------------------------------------------------+
   | MIG devices: |
   +------------------+----------------------------------+-----------+-----------------------+
   | GPU GI CI MIG | Memory-Usage | Vol| Shared |
   | ID ID Dev | BAR1-Usage | SM Unc| CE ENC DEC OFA JPG |
   | | | ECC| |
   |==================+==================================+===========+=======================|
   | 0 2 0 0 | 428MiB / 40192MiB | 42 0 | 3 0 2 0 0 |
   | | 2MiB / 32767MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 0 3 0 1 | 71MiB / 19968MiB | 28 0 | 2 0 1 0 0 |
   | | 0MiB / 16383MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 0 9 0 2 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 |
   | | 0MiB / 8191MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 0 10 0 3 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 |
   | | 0MiB / 8191MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 1 1 0 0 | 107MiB / 40192MiB | 42 0 | 3 0 2 0 0 |
   | | 0MiB / 32767MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 1 5 0 1 | 71MiB / 19968MiB | 28 0 | 2 0 1 0 0 |
   | | 0MiB / 16383MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 1 13 0 2 | 161MiB / 9728MiB | 14 0 | 1 0 0 0 0 |
   | | 2MiB / 8191MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 1 14 0 3 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 |
   | | 0MiB / 8191MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 2 1 0 0 | 107MiB / 40192MiB | 42 0 | 3 0 2 0 0 |
   | | 0MiB / 32767MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 2 5 0 1 | 289MiB / 19968MiB | 28 0 | 2 0 1 0 0 |
   | | 2MiB / 16383MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 2 13 0 2 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 |
   | | 0MiB / 8191MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 2 14 0 3 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 |
   | | 0MiB / 8191MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 3 1 0 0 | 107MiB / 40192MiB | 42 0 | 3 0 2 0 0 |
   | | 0MiB / 32767MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 3 5 0 1 | 71MiB / 19968MiB | 28 0 | 2 0 1 0 0 |
   | | 0MiB / 16383MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 3 13 0 2 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 |
   | | 0MiB / 8191MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   | 3 14 0 3 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 |
   | | 0MiB / 8191MiB | | |
   +------------------+----------------------------------+-----------+-----------------------+
   
   
   +-----------------------------------------------------------------------------------------+
   | Processes: |
   | GPU GI CI PID Type Process name GPU Memory |
   | ID ID Usage |
   |=========================================================================================|
   **| 0 2 0 64080 C python 312MiB |
   | 1 13 0 64085 C python 118MiB |
   | 2 5 0 64073 C python 210MiB |**
   +-----------------------------------------------------------------------------------------+
   ```

#### 使用 GB200 P6e 執行個體透過 IMEX 最佳化 GPU 工作負載
<a name="aiml-dra-imex"></a>

IMEX (Internode Memory Exchange) 可讓跨節點的記憶體一致性通訊，以便在 NVIDIA GB200 UltraServers 上進行分散式訓練。

執行下列步驟。

1. 使用名為 的檔案為`ComputeDomain`多節點訓練定義 `imex-compute-domain.yaml`：

   ```
   apiVersion: resource.nvidia.com/v1beta1
   kind: ComputeDomain
   metadata:
     name: distributed-training-domain
     namespace: default
   spec:
     numNodes: 2
     channel:
       resourceClaimTemplate:
         name: imex-channel-template
   ```

1. 使用 IMEX 頻道搭配名為 的檔案來定義 Pod`imex-pod.yaml`：

   ```
   apiVersion: v1
   kind: Pod
   metadata:
     name: imex-distributed-training
     namespace: default
     labels:
       app: imex-training
   spec:
     affinity:
       nodeAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
           nodeSelectorTerms:
           - matchExpressions:
             - key: nvidia.com/gpu.clique
               operator: Exists
     containers:
     - name: distributed-training
       image: nvcr.io/nvidia/pytorch:25.04-py3
       command: ["bash", "-c"]
       args:
       - |
         echo "=== IMEX Channel Verification ==="
         ls -la /dev/nvidia-caps-imex-channels/
         echo ""
   
         echo "=== GPU Information ==="
         nvidia-smi
         echo ""
   
         echo "=== NCCL Test (if available) ==="
         python -c "
         import torch
         import torch.distributed as dist
         import os
   
         print(f'CUDA available: {torch.cuda.is_available()}')
         print(f'CUDA device count: {torch.cuda.device_count()}')
   
         if torch.cuda.is_available():
             for i in range(torch.cuda.device_count()):
                 print(f'GPU {i}: {torch.cuda.get_device_name(i)}')
   
         # Check for IMEX environment variables
         imex_vars = [k for k in os.environ.keys() if 'IMEX' in k or 'NVLINK' in k]
         if imex_vars:
             print('IMEX Environment Variables:')
             for var in imex_vars:
                 print(f'  {var}={os.environ[var]}')
   
         print('IMEX channel verification completed')
         "
   
         # Keep container running for inspection
         sleep 3600
       resources:
         claims:
         - name: imex-channel-0
         - name: imex-channel-1
     resourceClaims:
     - name: imex-channel-0
       resourceClaimTemplateName: imex-channel-template
     - name: imex-channel-1
       resourceClaimTemplateName: imex-channel-template
     tolerations:
     - key: nvidia.com/gpu
       operator: Exists
       effect: NoSchedule
   ```
**注意**  
這需要 P6e GB200 執行個體。

1. 透過套用 `ComputeDomain`和 範本來部署 IMEX：

   ```
   kubectl apply -f imex-claim-template.yaml
   kubectl apply -f imex-compute-domain.yaml
   kubectl apply -f imex-pod.yaml
   ```

1. 檢查`ComputeDomain`狀態。

   ```
   kubectl get computedomain distributed-training-domain
   ```

1. 監控 IMEX 協助程式部署。

   ```
   kubectl get pods -n nvidia-dra-driver -l resource.nvidia.com/computeDomain
   ```

1. 檢查 Pod 中的 IMEX 頻道：

   ```
   kubectl exec imex-distributed-training -- ls -la /dev/nvidia-caps-imex-channels/
   ```

1. 檢視 Pod 日誌：

   ```
   kubectl logs imex-distributed-training
   ```

   以下是預期輸出的範例：

   ```
   === IMEX Channel Verification ===
   total 0
   drwxr-xr-x. 2 root root 80 Jul 8 10:45 .
   drwxr-xr-x. 6 root root 380 Jul 8 10:45 ..
   crw-rw-rw-. 1 root root 241, 0 Jul 8 10:45 channel0
   crw-rw-rw-. 1 root root 241, 1 Jul 8 10:45 channel1
   ```

如需詳細資訊，請參閱 GitHub 上的 [NVIDIA 範例](https://github.com/NVIDIA/k8s-dra-driver-gpu/discussions/249)。