

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

# 執行 AI/ML 工作負載的最佳實務
<a name="aiml"></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)最佳實務。

在 EKS 上執行 AI/ML 工作負載時實作最佳實務，可確保這些工作負載具有效能、成本效益、彈性和適當資源。最佳實務分為下列一般區段：運算、聯網、儲存、可觀測性和效能。

## 意見回饋
<a name="_feedback"></a>

本指南已在 GitHub 上發佈，以便收集更廣泛的 EKS/Kubernetes 社群的直接意見回饋和建議。如果您有最佳實務，認為我們應該包含在指南中，請在 GitHub 儲存庫中提出問題或提交 PR。我們的目的是在新功能新增至服務或新的最佳實務演進時，定期更新指南。

# 運算和自動擴展
<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)。

# 聯網
<a name="aiml-networking"></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)最佳實務。

## 對於具有高節點間通訊的應用程式，請考慮較高的網路頻寬或彈性布料轉接器
<a name="_consider_higher_network_bandwidth_or_elastic_fabric_adapter_for_applications_with_high_inter_node_communication"></a>

對於 Amazon EKS 上具有高節點間通訊需求的分散式訓練工作負載，請考慮選取具有較高網路頻寬或 [Elastic Fabric Adapter ](https://docs.aws.amazon.com/eks/latest/userguide/node-efa.html)(EFA) 的執行個體。網路效能不足會造成資料傳輸的瓶頸，進而減緩分散式多 GPU 訓練等機器學習任務。請注意，推論工作負載通常不會有高節點間通訊。

 **範例** 

例如，使用 Karpenter：

```
apiVersion: v1
kind: Pod
metadata:
  name: ml-workload
spec:
  nodeSelector:
    karpenter.k8s.aws/instance-network-bandwidth: "100000"  # 100 Gbps in Mbps
    node.kubernetes.io/instance-type: p5.48xlarge  # EFA-enabled instance
  containers:
  - name: training-job
    image: `763104351884.dkr.ecr.us-west-2.amazonaws.com/pytorch-inference:2.6.0-gpu-py312-cu124-ubuntu22.04-ec2-v1.6`
    resources:
      limits:
        vpc.amazonaws.com/efa: 1  # Requires EFA device plugin
```

確保 MPI 和 NCCL 等工具已安裝在您的容器映像中，以利用 EFA 進行訓練任務。

## 增加可用的 IP 地址數量，以啟用更快的 Pod 啟動時間
<a name="_increase_the_number_of_ip_addresses_available_to_enable_faster_pod_launch_times"></a>

在 EKS 中，每個 Pod 都需要 VPC CIDR 區塊的 IP 地址。隨著叢集擴展更多節點和 Pod，您會面臨 IP 地址耗盡或效能較慢的風險，但啟用字首委派可以透過預先配置 IP 範圍和減少 EC2 API 呼叫來緩解這些問題，從而縮短 Pod 啟動時間並改善可擴展性。

建立叢集後啟用字首委派可讓 VPC 容器網路界面 (CNI) 將 IP 字首 (/28，每個字首提供 16 個 IP 地址） 指派給 EC2 執行個體上的網路界面。這表示每個節點可以支援更多 Pod，降低 IP 不足的風險。例如，在`c5.4xlarge`執行個體上，您最多可以支援 110 個具有字首委派的 Pod。

雖然字首委派對於在具有許多小型 Pod 的環境中最佳化 IP 使用量至關重要，但 AI/ML 工作負載通常會使用較少、較大的 Pod （例如，每個 GPU 一個 Pod)。啟用字首委派可讓 VPC CNI 透過維護暖集區來預先配置字首，以加快 Pod 啟動速度。這表示 IP 地址隨時可用，相較於非字首模式的隨需配置，可縮短 Pod 初始化所需的時間。在這種情況下，啟用字首委派節省的 IP 可為 AI/ML 工作負載提供效能優勢。透過減少 IP 地址組態和預先配置 IP 範圍所需的 EC2 API 呼叫數量，使用字首委派可加快 Pod 啟動時間，這對於快速擴展 AI/ML 工作負載特別有用。

若要啟用字首委派：

```
kubectl set env daemonset/aws-node -n kube-system ENABLE_PREFIX_DELEGATION=true
```

確保適當規劃 VPC 子網路以避免 IP 地址耗盡，尤其是在大型部署中，並管理 CIDR 區塊以避免跨 VPCs 重疊。若要進一步了解，請參閱[最佳化 IP 地址使用率](ip-opt.md)和[使用字首將更多 IP 地址指派給 Amazon EKS 節點](https://docs.aws.amazon.com/eks/latest/best-practices/ip-opt.html#_plan_for_growth)。

# 安全
<a name="aiml-security"></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)最佳實務。

## 安全與合規
<a name="_security_and_compliance"></a>

### 考慮使用 KMS 的 S3 進行加密合規儲存
<a name="_consider_s3_with_kms_for_encryption_compliant_storage"></a>

除非您另有指定，否則所有 S3 儲存貯體預設都會使用 [SSE-S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingServerSideEncryption.html) 來加密靜態物件。不過，您可以選擇設定儲存貯體，改為使用伺服器端加密搭配 AWS Key Management Service (AWS KMS) 金鑰 (SSE-KMS)。AWS KMS 中的安全控制可以協助您符合加密相關合規要求。您可以使用這些 KMS 金鑰來保護 Amazon S3 儲存貯體中的資料。當您搭配 S3 儲存貯體使用 SSE-KMS 加密時，AWS KMS 金鑰必須與儲存貯體位於相同的區域。

將[一般用途儲存貯](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html)體設定為使用 [S3-KMS 的 S3 儲存貯體金鑰](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html#sse-kms-bucket-keys)，透過減少從 Amazon S3 到 AWS KMS 的請求流量，將 AWS KMS 請求成本降低高達 99%。目錄儲存貯體中的 `GET`和 `PUT`操作[一律會啟用](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-express-UsingKMSEncryption.html#s3-express-sse-kms-bucket-keys) S3 儲存貯體金鑰，且無法停用。

請注意，[Amazon S3 Express One Zone ](https://aws.amazon.com/s3/storage-classes/express-one-zone/)使用稱為 *S3 目錄儲存貯體的特定儲存貯體*類型。目錄儲存貯體僅適用於 S3 Express One Zone 儲存類別，並啟用高效能、低延遲的存取。若要[在 S3 目錄儲存貯體上設定預設儲存貯體加密](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-express-specifying-kms-encryption.html)，請使用 AWS CLI，並指定 KMS 金鑰 ID 或 ARN，而非別名，如下列範例所示：

**Example**  

```
aws s3api put-bucket-encryption --bucket my-directory-bucket --server-side-encryption-configuration \
   '{"Rules": [{"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "aws:kms", "KMSMasterKeyID": "1234abcd-12ab-34cd-56ef-1234567890ab"}}]}'
```
確保您的 EKS Pod 的 IAM 角色具有存取加密物件的 KMS 許可 （例如 `kms:Decrypt`)。在預備環境中進行測試，方法是將範例模型上傳到儲存貯體、將其掛載到 Pod 中 （例如，透過掛載點 S3 CSI 驅動程式），並確認 Pod 可以讀取加密的資料而不會發生錯誤。透過 AWS CloudTrail 稽核日誌，以確認是否符合加密要求。如需設定詳細資訊和金鑰管理，請參閱 [KMS 文件](https://docs.aws.amazon.com/kms/latest/developerguide/)。

# 儲存
<a name="aiml-storage"></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)最佳實務。

## 資料管理和儲存
<a name="_data_management_and_storage"></a>

### 使用 CSI 驅動程式將 AI 模型部署至 Pod
<a name="_deploy_ai_models_to_pods_using_a_csi_driver"></a>

AI/ML 工作負載通常需要存取大型模型成品 （例如，訓練的權重、組態），而 Pod 需要可靠、可擴展的方式來存取這些成品，而無需將其內嵌在容器映像中，這可以增加影像大小和容器登錄提取時間。為了降低管理磁碟區掛載的操作開銷，我們建議您使用各自的 CSI 驅動程式，將 Amazon 儲存服務 （例如 S3、FSx for Lustre、FSx for OpenZFS、EFS) 掛載為持久性磁碟區 (PVs)，以將 AI 模型部署至 Pod。如需實作詳細資訊，請參閱本節中的後續主題。

### 在 EKS 上最佳化 ML 模型快取的儲存體
<a name="_optimize_storage_for_ml_model_caches_on_eks"></a>

利用最佳儲存解決方案對於將 Pod 和應用程式啟動延遲降至最低、減少記憶體使用量、取得所需的效能層級以加速工作負載，以及確保 ML 工作負載的可擴展性至關重要。ML 工作負載通常依賴模型檔案 （權重），可能很大，需要跨 Pod 或節點共用存取資料。選取最佳儲存解決方案取決於工作負載的特性，例如單一節點效率、多節點存取、延遲要求、成本限制，以及資料整合要求 （例如使用 Amazon S3 資料儲存庫）。我們建議您使用工作負載對不同的儲存解決方案進行基準測試，以了解哪個解決方案符合您的需求，而且我們提供了下列選項，協助您根據您的工作負載需求進行評估。

EKS CSI 驅動程式支援下列 AWS Storage 服務，每個服務都有自己的 CSI 驅動程式，並為 AI 和 ML 工作流程提供自己的優勢：
+  [Amazon S3 掛載點](https://docs.aws.amazon.com/eks/latest/userguide/s3-csi.html) 
+  [Amazon FSx for Lustre](https://docs.aws.amazon.com/eks/latest/userguide/fsx-csi.html) 
+  [Amazon FSx for OpenZFS](https://docs.aws.amazon.com/eks/latest/userguide/fsx-openzfs-csi.html) 
+  [Amazon EFS](https://docs.aws.amazon.com/eks/latest/userguide/efs-csi.html) 
+  [Amazon EBS](https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html) 

AWS Storage 服務的選擇取決於您的部署架構、規模、效能需求和成本策略。儲存 CSI 驅動程式需要安裝在 EKS 叢集上，這可讓 CSI 驅動程式在 Pod 生命週期外建立和管理持久性磁碟區 (PV)。使用 CSI 驅動程式，您可以將支援的 AWS Storage 服務的 PV 定義建立為 EKS 叢集資源。然後，Pod 可以透過為 PV 建立持久性磁碟區宣告 (PVC) 來存取其資料磁碟區的這些儲存磁碟區。視 AWS 儲存服務和您的部署案例而定，單一 PVC （及其相關聯的 PV) 可以連接到工作負載的多個 Pod。例如，對於 ML 訓練，共用訓練資料存放在 PV 上，並由多個 Pod 存取；對於即時線上推論，LLM 模型會快取在 PV 上，並由多個 Pod 存取。AWS Storage 服務的範例 PV 和 PVC YAML 檔案提供如下，以協助您開始使用。

 **監控效能** 磁碟效能不佳可能會延遲容器映像讀取、增加 Pod 啟動延遲，以及降低推論或訓練輸送量。使用 [Amazon CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html) 監控 AWS 儲存服務的效能指標。當您發現效能瓶頸時，請修改儲存組態參數以最佳化效能。

 **案例：多個 GPU 執行個體工作負載** 

 **Amazon FSx for Lustre**：如果您有**多個 EC2 GPU 運算執行個體**環境具有延遲敏感和高頻寬輸送量動態工作負載，例如分散式訓練和模型服務，而且您需要原生 Amazon S3 資料儲存庫整合，我們建議您使用 [Amazon FSx for Lustre](https://docs.aws.amazon.com/fsx/latest/LustreGuide/what-is.html)。FSx for Lustre 提供全受管的高效能平行檔案系統，專為高效能運算 (HPC)、Machine Learning等運算密集型工作負載而設計。

您可以[安裝 FSx for Lustre CSI 驅動程式](https://docs.aws.amazon.com/eks/latest/userguide/fsx-csi.html)，將 FSx 檔案系統掛載為持久性磁碟區 (PV)，然後將 FSx for Lustre 檔案系統部署為獨立高效能快取，或部署為 S3-linked檔案系統，做為 S3 資料的高效能快取，為 GPU 運算執行個體的資料存取提供快速 I/O 和高輸送量。FSx for Lustre 可以使用 Scratch-SSD 或 Persistent-SSD 儲存選項進行部署：
+  **Scratch-SSD 儲存**：建議用於暫時性或短期 （小時） 的工作負載，並佈建每個 TiB 的固定輸送量容量。
+  **持久性 SSD 儲存**：建議用於需要最高水準可用性的任務關鍵型、長時間執行的工作負載，例如 HPC 模擬、大數據分析或Machine Learning訓練。使用持久性 SSD 儲存，您可以設定所需的儲存容量和輸送量容量 （每 TiB)。

 **效能考量：**
+  **管理 Pod 以管理 FSx for Lustre 檔案系統**：設定已安裝 lustre 用戶端並掛載 FSx 檔案系統的「管理」Pod。這將使存取點能夠對 FSx 檔案系統進行微調，以及在您需要在啟動 GPU 運算執行個體之前，使用 ML 訓練資料或 LLM 模型預熱 FSx 檔案系統的情況下。如果您的架構使用 Spot 型 Amazon EC2 GPU/運算執行個體，其中您可以使用管理 Pod 將所需的資料「暖」或「預先載入」到 FSx 檔案系統，以便在執行 Spot 型 Amazon EC2 執行個體時準備好處理資料，這一點尤其重要。
+  **Elastic Fabric Adapter (EFA)**：持久性 SSD 儲存體部署類型支援 [Elastic Fabric Adapter (EFA)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/efa.html)，其中使用 EFA 非常適合高效能和輸送量型 GPU 工作負載。請注意，FSx for Lustre 支援 NVIDIA GPUDirect 儲存 (GDS)，其中，GDS 是一種技術，可在本機或遠端儲存體與 GPU 記憶體之間建立直接資料路徑，以加快資料存取速度。
+  **壓縮**：如果您有可以壓縮的檔案類型，請在檔案系統上啟用資料壓縮。這有助於提高效能，因為資料壓縮可減少 FSx for Lustre 檔案伺服器和儲存體之間傳輸的資料量。
+  **Lustre 檔案系統分割組態**：
  +  **資料分割**：允許 FSx for Luster 將檔案的資料分散到 Lustre 檔案系統中的多個物件儲存目標 (OSTs)，將平行存取和輸送量最大化，尤其是針對大規模 ML 訓練任務。
  +  **獨立檔案系統分割**：根據預設，會透過 FSx for Lustre 的[漸進式檔案配置 (PFL)](https://docs.aws.amazon.com/fsx/latest/LustreGuide/performance.html#striping-pfl) 功能為您建立 4 元件 Lustre 分割組態。在大多數情況下，您不需要更新預設 PFL Lustre 條紋計數/大小。如果您需要調整 Lustre 資料分割，您可以參考 [FSx for Lustre 檔案系統的分割參數，手動調整 Lustre 分割](https://docs.aws.amazon.com/fsx/latest/LustreGuide/performance.html#striping-data)。
  +  **S3-Linked檔案系統**：使用原生 Amazon S3 整合 （資料儲存庫關聯或 DRA) 匯入 FSx 檔案系統的檔案不使用預設 PFL 配置，而是在檔案系統的 `ImportedFileChunkSize` 參數中使用配置。大於 S3-imported檔案`ImportedFileChunkSize`將存放在多個 OSTs 上，並根據`ImportedFileChunkSize`定義的值 （預設 1GiB) 具有條紋計數。如果您有大型檔案，建議您將此參數調校為較高的值。
  +  **配置**：將 FSx for Lustre 檔案系統部署在與運算或 GPU 節點相同的可用區域中，以啟用資料的最低延遲存取，避免跨可用區域存取模式。如果您的多個 GPU 節點位於不同的可用區域，建議您在每個可用區域中部署 FSx 檔案系統，以實現低延遲的資料存取。

 **範例** 

FSx for Lustre 檔案系統的持久性磁碟區 (PV) 定義，使用靜態佈建 （其中已佈建 FSx 執行個體）。

```
apiVersion: v1
kind: PersistentVolume
metadata:
  name: fsx-pv
spec:
  capacity:
    storage: 1200Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  mountOptions:
    - flock
  persistentVolumeReclaimPolicy: Recycle
  csi:
    driver: fsx.csi.aws.com
    volumeHandle: [FileSystemId of FSx instance]
    volumeAttributes:
      dnsname: [DNSName of FSx instance]
      mountname: [MountName of FSx instance]
```

 **範例** 

稱為 之 PV 的持久性磁碟區宣告定義`fsx-pv`：

```
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: fsx-claim
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: ""
  resources:
    requests:
      storage: 1200Gi
  volumeName: fsx-pv
```

 **範例** 

設定 Pod 以使用 的持久性磁碟區宣告`fsx-claim`：

```
apiVersion: v1
kind: Pod
metadata:
  name: fsx-app
spec:
  containers:
  - name: app
    image: amazonlinux:2023
    command: ["/bin/sh"]
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: fsx-claim
```

如需完整範例，請參閱 [ GitHub 中的 FSx for Lustre 驅動程式範例](https://github.com/kubernetes-sigs/aws-fsx-csi-driver/tree/master/examples/kubernetes)。使用 [Amazon CloudWatch 監控 Amazon FSx for Lustre 效能指標](https://docs.aws.amazon.com/fsx/latest/LustreGuide/monitoring-cloudwatch.html)。 Amazon CloudWatch 發現效能瓶頸時，請視需要調整您的組態參數。

 **案例：單一 GPU 執行個體工作負載** 

 **搭配 CSI 驅動程式的 Amazon S3 掛載點：**您可以使用適用於 Amazon S3 [CSI 驅動程式的掛載點，將 Amazon S3 ](https://docs.aws.amazon.com/eks/latest/userguide/s3-csi.html)儲存貯體掛載為 Pod 中的磁碟區。此方法允許精細存取控制 Pod 可以存取特定 S3 儲存貯體。每個 Pod 都有自己的掛載點執行個體和本機快取 (5-10GB)，在 Pod 之間隔離模型載入和讀取效能。此設定支援使用 IAM Roles for Service Accounts (IRSA) 進行 Pod 層級身分驗證，並支援不同模型或客戶的獨立模型版本控制。權衡是記憶體用量和 API 流量的增加，因為每個 Pod 都會發出 S3 API 呼叫並維護自己的快取。

 Pod 部署 YAML 搭配 CSI 驅動程式的部分****範例：

```
# CSI driver dynamically mounts the S3 bucket for each pod

volumes:
  - name: s3-mount
    csi:
      driver: s3.csi.aws.com
      volumeAttributes:
        bucketName: your-s3-bucket-name
        mountOptions: "--allow-delete"  # Optional
        region: us-west-2

containers:
  - name: inference
    image: your-inference-image
    volumeMounts:
      - mountPath: /models
        name: s3-mount
volumeMounts:
  - name: model-cache
    mountPath: /models
volumes:
  - name: model-cache
    hostPath:
      path: /mnt/s3-model-cache
```

 **效能考量：**
+  **資料快取**：S3 的掛載點可以快取內容，以降低成本並改善對相同檔案重複讀取的效能。如需[快取選項和參數，請參閱快取組態](https://github.com/awslabs/mountpoint-s3/blob/main/doc/CONFIGURATION.md#caching-configuration)。
+  **物件部分大小**：存放和存取大小超過 72GB 的檔案時，請參閱[設定掛載點效能](https://github.com/awslabs/mountpoint-s3/blob/main/doc/CONFIGURATION.md#configuring-mountpoint-performance)，了解如何設定 `--read-part-size`和 `--write-part-size`命令列參數以符合您的資料設定檔和工作負載需求。
+  ** [Shared-cache](https://github.com/awslabs/mountpoint-s3/blob/main/doc/CONFIGURATION.md#shared-cache) ** 專為大小上限為 1MB 的物件而設計。它不支援大型物件。使用[本機快取](https://github.com/awslabs/mountpoint-s3/blob/main/doc/CONFIGURATION.md#local-cache)選項，在 NVMe 或 EKS 節點的 EBS 磁碟區中快取物件。
+  **API 請求費用**：使用 S3 掛載點執行大量檔案操作時，API 請求費用可能會成為儲存成本的一部分。若要緩解這種情況，如果不需要強式一致性，請一律啟用中繼資料快取，並將 `metadata-ttl` API 操作次數設定為 S3。

如需詳細資訊，請參閱 [Amazon EKS 官方文件中的 Amazon S3 CSI 驅動程式掛載點](https://docs.aws.amazon.com/eks/latest/userguide/s3-csi.html)。如果發生瓶頸，我們建議您[使用 Amazon CloudWatch 指標監控 Amazon S3 的效能指標 Amazon CloudWatch](https://docs.aws.amazon.com/AmazonS3/latest/userguide/cloudwatch-monitoring.html)，並視需要調整您的組態。

### Amazon FSx for OpenZFS 持久共用儲存
<a name="_amazon_fsx_for_openzfs_persistent_shared_storage"></a>

對於涉及多個 EC2 GPU 運算執行個體的案例，以及需要不同應用程式的高可用性、高效能、成本敏感度和多個 Pod 部署的延遲敏感工作負載，我們建議使用 Amazon FSx for OpenZFS。某些工作負載範例包括即時推論、強化學習和訓練生成對手網路。FSx for OpenZFS 特別適用於需要高效能存取聚焦目錄結構的工作負載，以及使用小型 IO 資料存取模式的小型檔案。此外，FSx for OpenZFS 提供獨立於儲存容量的彈性擴展效能，透過將儲存大小與實際需求配對，同時維持所需的效能等級，協助您達成最佳的成本效益

原生 [FSx for OpenZFS CSI 驅動程式](https://github.com/kubernetes-sigs/aws-fsx-openzfs-csi-driver/tree/main)允許透過建立多個磁碟區，將多個 PVCs 建立到單一檔案系統。這可減少管理開銷，並透過單一檔案系統上的合併應用程式 Pod 部署，最大化檔案系統的輸送量和 IOPS 使用率。此外，它還包含企業功能，例如零複本快照、零複本複製，以及使用者和群組配額，可透過 CSI 驅動程式動態佈建。

FSx for OpenZFS 在建立時支援三種不同的[部署類型](https://docs.aws.amazon.com/fsx/latest/OpenZFSGuide/availability-durability.html#choosing-single-or-multi)：
+  **單一可用區：**具有低於毫秒延遲的最低成本選項，但檔案系統或可用區域層級不提供高可用性。建議用於開發和測試工作負載或在應用程式層具有高可用性的工作負載。
+  **單一可用區 (HA)：**在檔案系統層級以低於毫秒的延遲提供高可用性。建議用於需要高可用性的最高效能工作負載。
+  **異地同步備份：**在檔案系統層級以及跨可用區域提供高可用性。建議用於需要跨可用區域額外可用性的高效能工作負載。

效能考量：
+  **部署類型：**如果不需要跨可用區域的其他可用性，請考慮使用單一可用區域 (HA) 部署類型。此部署類型提供高達 100% 的寫入輸送量、維持低於毫秒的延遲，而且 Gen2 檔案系統具有額外的 NVMe 快取，可儲存高達 TB 的經常存取資料。多可用區域檔案系統提供高達 75% 的寫入輸送量，延遲增加，以容納跨可用區域流量。
+  **輸送量和 IOPS：**為檔案系統設定的[輸送量](https://docs.aws.amazon.com/fsx/latest/OpenZFSGuide/managing-throughput-capacity.html)和 [IOPS](https://docs.aws.amazon.com/fsx/latest/OpenZFSGuide/managing-storage-capacity.html) 都可以在部署後向上或向下擴展。您可以佈建高達 10GB/s 的磁碟輸送量，提供高達 21GB/s 的快取資料存取。IOPS 可以從磁碟擴展到 400，000 個，快取可提供超過 100 萬個 IOPS。請注意，單一可用區檔案系統的輸送量擴展確實會導致檔案系統短暫中斷，因為沒有高可用性。單一可用區 (HA) 或多可用區檔案系統的輸送量擴展可以不中斷地完成。SSD IOPS 可以每六小時擴展一次。
+  **儲存類別：**FSx for OpenZFS 同時支援 [SSD 儲存](https://docs.aws.amazon.com/fsx/latest/OpenZFSGuide/performance-ssd.html)類別和 [Intelligent-Tiering](https://docs.aws.amazon.com/fsx/latest/OpenZFSGuide/performance-intelligent-tiering.html) 儲存類別。對於 AI/ML 工作負載，建議您使用 SSD 儲存類別，為 CPU/GPU 盡可能保持忙碌的工作負載提供一致的效能。
+  **壓縮：**如果您的工作負載可以壓縮，請啟用 [LZ4 ](https://docs.aws.amazon.com/fsx/latest/OpenZFSGuide/performance.html#perf-data-compression) 壓縮演算法。這可減少每個檔案在快取中耗用的資料量，允許直接從快取提供更多資料做為網路輸送量，並降低 SSD 磁碟上的負載 IOPS。
+  **記錄大小：**大多數 AI/ML 工作負載將受益於保留預設的 128KiB [記錄大小](https://docs.aws.amazon.com/fsx/latest/OpenZFSGuide/performance.html#record-size-performance)。只有在資料集由大型檔案 (10GiB 以上） 組成，且應用程式的一致性小區塊存取低於 128KiB 時，才應降低此值。

建立檔案系統後，服務會自動建立相關聯的根磁碟區。最佳實務是將資料存放在檔案系統根磁碟區的子磁碟區中。使用 [FSx for OpenZFS CSI 驅動程式](https://github.com/kubernetes-sigs/aws-fsx-openzfs-csi-driver/tree/main)，您可以建立相關聯的持久性磁碟區宣告，以動態建立子磁碟區。

範例：

FSx for OpenZFS 磁碟區的儲存類別 (SC) 定義，用於在現有檔案系統上建立根磁碟區的子磁碟區 (\$1ROOT\$1VOL\$1ID)，並使用 NFS v4.2 通訊協定將磁碟區匯出至 VPC CIDR (\$1VPC\$1CIDR)。

```
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fsxz-vol-sc
provisioner: fsx.openzfs.csi.aws.com
parameters:
  ResourceType: "volume"
  ParentVolumeId: '"$ROOT_VOL_ID"'
  CopyTagsToSnapshots: 'false'
  DataCompressionType: '"LZ4"'
  NfsExports: '[{"ClientConfigurations": [{"Clients": "$VPC_CIDR", "Options": ["rw","crossmnt","no_root_squash"]}]}]'
  ReadOnly: 'false'
  RecordSizeKiB: '128'
  Tags: '[{"Key": "Name", "Value": "AI-ML"}]'
  OptionsOnDeletion: '["DELETE_CHILD_VOLUMES_AND_SNAPSHOTS"]'
reclaimPolicy: Delete
allowVolumeExpansion: false
mountOptions:
  - nfsvers=4.2
  - rsize=1048576
  - wsize=1048576
  - timeo=600
  - nconnect=16
  - async
```

針對上述建立的 fsxz-vol-sc 動態建立持久性磁碟區宣告 (PVC)。**請注意**，配置的儲存容量為 1Gi，FSx for OpenZFS 磁碟區為必要項目，如 [CSI 驅動程式常見問答集](https://github.com/kubernetes-sigs/aws-fsx-openzfs-csi-driver/blob/main/docs/FAQ.md)中所述。磁碟區將獲提供使用此組態佈建至檔案系統的完整容量。如果需要限制磁碟區容量，您可以使用使用者或群組配額來執行此操作。

```
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: dynamic-vol-pvc
  namespace: example
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: fsxz-vol-sc
  resources:
    requests:
      storage: 1Gi
```

設定 Pod 以使用 dynamic-vol-pvc 的持久性磁碟區宣告 (PVC) 掛載磁碟區：

```
kind: Pod
apiVersion: v1
metadata:
  name: fsx-app
  namespace: example
spec:
  volumes:
    - name: dynamic-vol-pv
      persistentVolumeClaim:
        claimName: dynamic-vol-pvc
  containers:
    - name: app
      image: amazonlinux:2023
      command: ["/bin/sh"]
      volumeMounts:
        - mountPath: "/mnt/fsxz"
          name: dynamic-vol-pv
```

### 共用模型快取的 Amazon EFS
<a name="_amazon_efs_for_shared_model_caches"></a>

當您有**多個 EC2 GPU 運算執行個體環境**，且動態工作負載需要跨多個節點和可用區域共用模型存取 （例如，使用 Karpenter 進行即時線上推論） 且具有中等效能和可擴展性需求時，我們建議您透過 EFS CSI 驅動程式使用 Amazon Elastic File System (EFS) 檔案系統做為持久性磁碟區。[Amazon EFS](https://docs.aws.amazon.com/efs/latest/ug/whatisefs.html) 是全受管、高可用性和可擴展的雲端型 NFS 檔案系統，可讓 EC2 執行個體和容器具有共用檔案儲存，並具有一致的效能，而且不需要預先佈建儲存體。使用 EFS 做為模型磁碟區，並透過在 EKS 叢集上定義持久性磁碟區，將磁碟區掛載為共用檔案系統。每個由 EFS 檔案系統支援的持久性磁碟區宣告 (PVC) 都會建立為 [EFS 檔案系統的 EFS 存取點](https://docs.aws.amazon.com/efs/latest/ug/efs-access-points.html)。EFS 允許多個節點和 Pod 存取相同的模型檔案，無需將資料同步到每個節點的檔案系統。[安裝 EFS CSI 驅動程式](https://docs.aws.amazon.com/eks/latest/userguide/efs-csi.html)，將 EFS 與 EKS 整合。

您可以使用下列輸送量模式部署 Amazon EFS 檔案系統：
+  **爆量輸送量**：擴展檔案系統大小的輸送量，適用於偶爾爆量的各種工作負載。
+  **佈建輸送量**：專用輸送量，非常適合具有可預測效能需求的一致 ML 訓練任務。
+  **彈性輸送量 （建議 ML 使用）**：根據工作負載、不同 ML 工作負載的成本效益自動擴展。

若要檢視效能規格，請參閱 [Amazon EFS 效能規格](https://docs.aws.amazon.com/efs/latest/ug/performance.html)。

 **效能考量**：
+ 將彈性輸送量用於不同的工作負載。
+ 針對作用中 ML 工作負載使用標準儲存類別。

如需在 EKS 叢集和 Pod 中使用 Amazon EFS 檔案系統作為持久性磁碟區的完整範例，請參閱 [ GitHub 中的 EFS CSI 驅動程式範例](https://github.com/kubernetes-sigs/aws-efs-csi-driver/tree/master/examples/kubernetes)。使用 [Amazon CloudWatch 監控 Amazon EFS 效能指標](https://docs.aws.amazon.com/efs/latest/ug/accessingmetrics.html)。 Amazon CloudWatch 發現效能瓶頸時，請視需要調整您的組態參數。

### 將 S3 Express One Zone 用於延遲敏感的物件導向工作流程
<a name="_use_s3_express_one_zone_for_latency_sensitive_object_oriented_workflows"></a>

對於 Amazon EKS 上的延遲敏感 AI/ML 工作負載，例如大規模模型訓練、推論或高效能分析，建議使用 [S3 Express One Zone](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-express-getting-started.html) 進行高效能模型儲存和擷取。S3 Express One Zone 提供階層式命名空間，例如檔案系統，您只需上傳到目錄儲存貯體，適合「卡入所有內容」，同時維持高速。如果您熟悉物件導向工作流程，此功能特別有用。或者，如果您更習慣檔案系統 （例如 POSIX 相容），您可能偏好 Amazon FSx for Lustre 或 OpenZFS。Amazon S3 Express One Zone 使用目錄儲存貯體將資料存放在單一可用區域 (AZ)，並提供比標準 S3 儲存貯體更低的延遲，該儲存貯體會將資料分散到多個AZs。為了獲得最佳結果，請務必將 EKS 運算與 Express One Zone 儲存貯體位於相同的可用區域中。若要進一步了解 S3 Express One Zone 的差異，請參閱[目錄儲存貯體的差異](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-express-differences.html)。

若要使用檔案系統語意存取 S3 Express One Zone，建議使用[掛載點 S3 CSI 驅動程式](https://github.com/awslabs/mountpoint-s3-csi-driver/tree/main)，該驅動程式會將 S3 儲存貯體 （包括 Express One Zone) 掛載為本機檔案系統。這會將檔案操作 （例如，開啟、讀取、寫入） 轉換為 S3 API 呼叫，提供針對多個用戶端的大量讀取工作負載和循序寫入新物件進行最佳化的高輸送量存取。如需支援的操作和限制的詳細資訊 （例如，沒有完整的 POSIX 合規，但附加和重新命名 Express One Zone 中支援），請參閱[掛載點語意文件](https://github.com/awslabs/mountpoint-s3/blob/main/doc/SEMANTICS.md)。

 **效能優勢** 
+ 提供比 S3 Standard 快 10 倍的資料存取，具有一致的單一位數毫秒延遲和高達 80% 的請求成本。
+ 擴展以處理[每個目錄儲存貯體每秒數十萬到數百萬個請求](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-express-optimizing-performance-design-patterns.html#s3-express-how-directory-buckets-work)，避免在極端載入期間在標準 S3 中看到限流或中斷 （例如，從具有數十到數十萬GPUs/CPUs 飽和網路的叢集）。
+ 使用工作階段型身分驗證機制。驗證一次以取得工作階段字符，然後以高速執行重複操作，而不會產生每次請求身分驗證的額外負荷。這針對頻繁檢查點或資料載入等工作負載進行了最佳化。

 **建議的使用案例** 
+  **快取**：搭配 S3 Express One Zone 使用掛載點 S3 CSI 驅動程式的其中一個主要使用案例是快取。第一個執行個體會從 S3 Standard （一般用途） 讀取資料，並在低延遲的 Express One Zone 中快取資料。其他用戶端後續讀取會更快地存取快取的資料，這非常適合多個 EKS 節點讀取相同資料 （例如，共用訓練資料集） 的多節點案例。這可以為重複存取提升效能高達 7 倍，並降低運算成本。對於需要完全 POSIX 合規的工作負載 （例如檔案鎖定和就地修改），請考慮使用 Amazon FSx for Lustre 或 OpenZFS 作為替代方案。
+  **大規模 AI/ML 訓練和推論**：非常適合具有數百個或數千個運算節點 （例如 EKS 叢集中的 GPUs) 的工作負載，其中一般用途 S3 限流可能會導致延遲，浪費昂貴的運算資源。例如，執行每日模型測試/檢查點的 LLM 研究人員或組織受益於快速、可靠的存取，而不會破壞區域 S3。對於較小的工作負載 （例如 10 個節點），S3 Standard 或其他儲存類別可能已足夠。
+  **資料管道**：載入/準備模型、封存訓練資料或串流檢查點。如果您的團隊偏好物件儲存，而非傳統檔案系統 （例如，由於熟悉 S3)，請針對 FSx for Lustre 等 POSIX 相容選項，使用此選項而非工程變更。

 **考量** 
+  **彈性**：單一可用區設計提供 99.999999999% 的耐用性 （與標準 S3 相同，透過 AZ 中的備援），但相較於多可用區類別 (99.99% 的可用性），可用性較低 (99.95% 的設計、99.9% 的 SLA)。它對 AZ 故障的彈性較低。用於可重新建立或快取的資料。考慮對關鍵工作負載進行多可用區複寫或備份。
+  **API 和功能支援**：支援 S3 API 的子集 （例如，沒有生命週期政策或複寫）；可能需要對工作階段身分驗證或物件處理進行次要應用程式變更。 APIs 
+  **EKS 整合**：將 EKS Pod/節點與目錄儲存貯體位於相同的可用區域中，以將網路延遲降至最低。使用適用於 Amazon S3 或 CSI 驅動程式的掛載點進行 Kubernetes 原生存取。
+  **測試：**在非生產環境中測試擷取延遲，以驗證效能提升。在標準 S3 案例中監控限流 （例如高 GPU 飽和度） 並比較。

S3 Express One Zone 儲存類別可在多個區域中使用，並針對需要物件存取的工作負載與 EKS 整合，而無需等待儲存。若要進一步了解，請參閱 [ S3 Express One Zone 入門](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-express-getting-started.html)。

# 可觀測性
<a name="aiml-observability"></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)最佳實務。

## 監控與可觀測性
<a name="_monitoring_and_observability"></a>

### GPU 指標說明
<a name="gpu-metrics-explained"></a>

GPU 使用率指標會顯示 GPU 在範例時段內是否執行任何工作。此指標會擷取 GPU 執行至少一個指令的時間百分比，但不會顯示 GPU 使用其硬體的效率。GPU 包含多個串流多處理器 (SMs)，這是執行指示的平行處理單元。100% 使用率讀數可能表示 GPU 在其所有 SMs 中執行繁重的平行工作負載，也可能表示在範例期間內啟動 GPU 的單一小型指令。若要了解實際使用率，您需要在硬體架構的多個層級檢查 GPU 指標。每個串流多處理器都是由不同的核心類型所建置，而且每個 layer 都會公開不同的效能特性。最上層指標 (GPU 使用率、記憶體使用率、GPU Power 和 GPU 溫度，透過 nvidia-smi 可見） 會顯示裝置是否處於作用中狀態。更深入的指標 (SM 使用率、SM 活動和張量核心使用量） 會顯示 GPU 使用其資源的效率。

### 以高 GPU 用電量為目標
<a name="target-high-gpu-power-usage"></a>

未充分利用的 GPUs 會浪費運算容量並增加成本，因為工作負載無法同時參與所有 GPU 元件。對於 Amazon EKS 上的 AI/ML 工作負載，請將 GPU 用電量追蹤為代理，以識別實際的 GPU 活動。GPU 使用率會報告 GPU 執行任何核心的時間百分比，但不會顯示串流多處理器、記憶體控制器和張量核心是否同時處於作用中狀態。電力使用會公開此差距，因為完全參與的硬體比執行輕量型核心或任務之間閒置的硬體消耗更多電力。將耗電量與 GPU 的熱設計能力 (TDP) 進行比較，以發現使用率不足，然後調查您的工作負載是否因 CPU 預先處理、網路 I/O 或效率不佳的批次大小而遇到瓶頸。

在 Amazon EKS 上設定 CloudWatch Container Insights，以識別 GPU 耗電量低的 Pod、節點或工作負載。此工具直接與 Amazon EKS 整合，可讓您監控 GPU 耗電量，並在耗電量低於目標層級時調整 Pod 排程或執行個體類型。如果您需要進階視覺化或自訂儀表板，請使用 NVIDIA 的 DCGM-Exporter 搭配 Prometheus 和 Grafana 進行 Kubernetes 原生監控。兩者都接近表面金鑰 NVIDIA 指標，例如 `nvidia_smi_power_draw`(GPU 耗電量） 和 `nvidia_smi_temperature_gpu`(GPU 溫度）。如需指標清單，請瀏覽 https：//https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Agent-NVIDIA-GPU.htm。尋找模式，例如在特定時間或特定任務中持續保持低功耗。這些趨勢可協助您識別合併工作負載或調整資源配置的位置。

Kubernetes 中的靜態資源限制 （例如 CPU、記憶體和 GPU 計數） 通常會導致過度佈建或利用率不足，尤其是在需求波動的推論等動態 AI/ML 工作負載。分析您的使用率趨勢，並將工作負載合併到較少的 GPUs。在配置其他 GPU 之前，請確定每個 GPU 都達到完整的使用率。此方法可減少浪費並降低成本。如需最佳化排程和共用策略的詳細指引，請參閱 [EKS Compute and Autoscaling 最佳實務](https://docs.aws.amazon.com/eks/latest/best-practices/aiml-compute.html) 

## 可觀測性和指標
<a name="_observability_and_metrics"></a>

### 使用 AI/ML 工作負載的監控和可觀測性工具
<a name="using-monitoring-and-observability-tools-for-your-ai-ml"></a>

現代 AI/ML 服務需要跨基礎設施、建模和應用程式邏輯進行協調。平台工程師管理基礎設施和可觀測性堆疊。它們收集、存放和視覺化指標。AI/ML 工程師定義模型特定的指標，並在不同的負載和資料分佈下監控效能。應用程式開發人員會使用 APIs、路由請求，以及追蹤服務層級指標和使用者互動。如果沒有統一的可觀測性實務，這些團隊會在孤島中工作，並錯過有關系統運作狀態和效能的關鍵訊號。建立跨環境的共用可見性，可確保所有利益相關者都能及早偵測問題並維持可靠的服務。

最佳化 AI/ML 工作負載的 Amazon EKS 叢集帶來獨特的監控挑戰，尤其是 GPU 記憶體管理。如果沒有適當的監控，組織會面臨out-of-memory(OOM) 錯誤、資源效率低下和不必要的成本。有效的監控可確保 EKS 客戶有更好的效能、彈性並降低成本。使用結合三個監控層的整體方法。首先，使用 [NVIDIA DCGM Exporter](https://docs.nvidia.com/datacenter/dcgm/latest/gpu-telemetry/dcgm-exporter.html) 監控精細的 GPU 指標，以追蹤 GPU 用電量、GPU 溫度、SM 活動、SM 佔用率和 XID 錯誤。其次，監控 [Ray](https://docs.ray.io/en/latest/serve/monitoring.html) 和 [vLLM](https://docs.vllm.ai/en/v0.8.5/design/v1/metrics.html) 等推論服務架構，透過其原生指標取得分散式工作負載洞見。第三，收集應用程式層級的洞見，以追蹤工作負載特定的自訂指標。這種分層方法為您提供從硬體使用率到應用程式效能的可見性。

#### 工具和架構
<a name="aiml-observability-tools-and-frameworks"></a>

數個工具和架構提供原生out-of-the-box指標，用於監控 AI/ML 工作負載。這些內建指標可免除自訂檢測的需求，並縮短設定時間。這些指標著重於延遲、輸送量和權杖產生等效能層面，這些層面對於推論服務和基準測試至關重要。使用原生指標可讓您立即開始監控，而無需建置自訂集合管道。
+  **vLLM**：適用於大型語言模型 (LLMs) 的高輸送量服務引擎，可提供請求延遲和記憶體用量等原生指標。
+  **Ray**：分散式運算架構，可發出可擴展 AI 工作負載的指標，包括任務執行時間和資源使用率。
+  **Hugging Face Text Generation Inference (TGI)**：用於部署和服務 LLMs 的工具組，具有內建的推論效能指標。
+  **NVIDIA genai-perf**：一種命令列工具，用於基準化生成式 AI 模型、測量輸送量、延遲和 LLM 特定指標，例如在特定時間間隔內完成的請求。

#### 可觀測性方法
<a name="aiml-observability-methods"></a>

我們建議以下列其中一種方式實作任何其他可觀測性機制。

 **CloudWatch Container Insights** 如果您的組織偏好設定最少的 AWS 原生工具，我們建議您使用 [CloudWatch Container Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/deploy-container-insights-EKS.html)。它與 [NVIDIA DCGM Exporter](https://docs.nvidia.com/datacenter/dcgm/latest/gpu-telemetry/dcgm-exporter.html) 整合，以收集 GPU 指標，並提供預先建置的儀表板以快速洞察。Container Insights 透過在叢集上安裝 [CloudWatch 可觀測性附加元件](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-setup-EKS-addon.html)來啟用，可部署和管理 [NVIDIA DCGM Exporter](https://docs.nvidia.com/datacenter/dcgm/latest/gpu-telemetry/dcgm-exporter.html) 的生命週期，該匯出程式會從 Nvidia 的驅動程式收集 GPU 指標並將其公開給 CloudWatch。

安裝 Container Insights 後，CloudWatch 會自動偵測您環境中的 NVIDIA GPUs，並收集重要的運作狀態和效能指標。這些指標會出現在已整理out-of-the-box儀表板上。您也可以使用統一 CloudWatch Agent 將 [Ray](https://docs.ray.io/en/latest/cluster/vms/user-guides/launching-clusters/aws.html) 和 [vLLM](https://docs.vllm.ai/en/latest/) 與 CloudWatch 整合，以傳送其原生指標。 [ CloudWatch ](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/UseCloudWatchUnifiedAgent.html) 這種統一的方法簡化了 EKS 環境中的可觀測性，並讓團隊專注於效能調校和成本最佳化，而不是建置監控基礎設施。

如需可用指標的完整清單，請參閱 [Amazon EKS 和 Kubernetes Container Insights 指標](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-metrics-EKS.html#Container-Insights-metrics-EKS-GPU)。如需實作 GPU step-by-step指引，請參閱[使用 Amazon CloudWatch Container Insights 取得 NVIDIA GPU 工作負載的操作洞見](https://aws.amazon.com/blogs/mt/gain-operational-insights-for-nvidia-gpu-workloads-using-amazon-cloudwatch-container-insights/)。如需最佳化推論延遲的實際範例，請參閱[最佳化 AI 回應能力：Amazon Bedrock 延遲最佳化推論的實際指南](https://aws.amazon.com/blogs/machine-learning/optimizing-ai-responsiveness-a-practical-guide-to-amazon-bedrock-latency-optimized-inference/)。

 **受管 Prometheus 和 Grafana** 如果您的組織需要自訂儀表板和進階視覺化功能，請使用 [NVIDIA DCGM-Exporter](https://catalog.ngc.nvidia.com/orgs/nvidia/teams/k8s/containers/dcgm-exporter) 和 Grafana 部署 Prometheus 以進行 Kubernetes 原生監控。Prometheus 會從 DCGM-Exporter 抓取和存放 GPU 指標，而 Grafana 則提供靈活的視覺化和提醒功能。相較於 CloudWatch Container Insights，此方法可讓您更能控制儀表板設計和指標保留。

您可以整合 Ray、vLLM Ray [和 vLLM](https://awslabs.github.io/ai-on-eks/docs/blueprints/inference/GPUs/vLLM-rayserve) 等開放原始碼架構，將原生指標匯出至 Prometheus，以擴展此監控堆疊。您也可以[將 Grafana 連線至 AWS X-Ray 資料來源](https://docs.aws.amazon.com/grafana/latest/userguide/x-ray-data-source.html)，以視覺化分散式追蹤，並識別推論管道的效能瓶頸。此組合透過應用程式層級請求流程，提供 GPU 層級指標end-to-end可見性。

如需部署此監控堆疊的step-by-step指引，請參閱[使用 AWS 受管開放原始碼服務在 Amazon EKS 上監控 GPU 工作負載](https://aws.amazon.com/blogs/mt/monitoring-gpu-workloads-on-amazon-eks-using-aws-managed-open-source-services/)。

### 考慮監控核心訓練和微調指標
<a name="aiml-consider-monitor-fine-tuning-metrics"></a>

監控核心訓練指標，以追蹤 Amazon EKS 叢集的運作狀態和效能，以及其上執行的機器學習工作負載。訓練工作負載與推論工作負載具有不同的監控需求，因為它們會長時間執行、以不同的方式使用資源，而且需要模型收斂和資料管道效率的可見性。以下指標可協助您識別瓶頸、最佳化資源配置，並確保訓練任務成功完成。如需實作此監控方法step-by-step指引，請參閱在 [Amazon EKS 上觀察機器學習工作負載的簡介](https://aws.amazon.com/blogs/containers/part-1-introduction-to-observing-machine-learning-workloads-on-amazon-eks/)。

 **資源用量指標** 

監控資源用量指標，以驗證您的資源是否正確使用。這些指標可協助您識別瓶頸和根本原因效能問題。
+  **CPU、記憶體、網路、GPU Power 和 GPU 溫度** - 監控這些指標，以確保配置的資源符合工作負載需求，並識別最佳化機會。追蹤 gpu\$1memory\$1usage\$1bytes 等指標，以識別記憶體消耗模式並偵測尖峰用量。計算百分位數，例如第 95 個百分位數 (P95)，以了解訓練期間最高的記憶體需求。此分析可協助您最佳化模型和基礎設施，以避免 OOM 錯誤並降低成本。
+  **SM 佔用、SM 活動、FPxx 活動** - 監控這些指標，以了解 GPU 上的基礎資源如何使用。SM 活動的目標 0.8 作為[經驗法](https://docs.nvidia.com/datacenter/dcgm/latest/user-guide/feature-overview.html#metrics)則。
+  **節點和 Pod 資源使用率** - 追蹤節點和 Pod 層級的資源使用量，以識別資源爭用和潛在的瓶頸。監控節點是否接近容量限制，這可能會延遲 Pod 排程和緩慢的訓練任務。
+  **資源使用率 與請求和限制**比較 — 將實際資源使用量與設定的請求和限制進行比較，以確定您的叢集是否可以處理目前的工作負載並容納未來的工作負載。此比較會顯示是否需要調整資源配置，以避免 OOM 錯誤或資源浪費。
+  **ML 架構的內部指標** - 從 TensorFlow 和 PyTorch 等 ML 架構中擷取內部訓練和收斂指標。這些指標包括損失曲線、學習率、批次處理時間和訓練步驟持續時間。使用 TensorBoard 或類似工具視覺化這些指標，以追蹤模型收斂並識別訓練效率低下。

 **模型效能指標** 

監控模型效能指標，以驗證您的訓練程序是否產生符合準確性和業務需求的模型。這些指標可協助您判斷何時停止訓練、比較模型版本，以及識別效能降低。
+  **準確性、精確度、召回和 F1-score — **追蹤這些指標，以了解模型對驗證資料的效能。在每個訓練 epoch 之後計算驗證集上的 F1-score，以評估模型是否正在改善，以及何時達到可接受的效能等級。
+  **業務特定指標和 KPIs** — 定義和追蹤直接測量 AI/ML 計畫商業價值的指標。對於建議系統，追蹤點擊率或轉換率等指標，以確保模型推動預期的業務成果。
+  **隨時間推移的效能** — 比較跨模型版本和訓練執行的效能指標，以識別趨勢並偵測降級。相較於基準模型，追蹤較新的模型版本是否維持或改善效能。此歷史比較可協助您決定是否部署新模型或調查訓練問題。

 **資料品質和偏離指標** 

監控資料品質和偏離指標，以確保您的訓練資料保持一致且具代表性。資料偏離可能會導致模型效能隨著時間降低，而資料品質問題可能會阻止模型收斂或產生不可靠的結果。
+  **輸入資料的統計屬性** — 追蹤一段時間內輸入特徵的平均值、標準差和分佈等統計屬性，以偵測資料偏離或異常。監控功能分佈是否從您的基準訓練資料大幅轉移。例如，如果關鍵特徵的平均值變更超過兩個標準差，請調查您的資料管道是否已變更或基礎資料來源是否已轉移。
+  **資料偏離偵測和提醒** — 實作自動化機制，在資料品質問題影響訓練之前對其進行偵測和提醒。使用統計測試，例如 Kolmogorov-Smirnov 測試或卡方測試，將目前的資料分佈與原始訓練資料進行比較。在測試偵測到重大偏離時設定提醒，以便您可以使用更新的資料重新訓練模型或調查資料管道問題。

 **延遲和輸送量指標** 

監控延遲和輸送量指標，以識別訓練管道中的瓶頸，並最佳化資源使用率。這些指標可協助您了解在訓練期間花費的時間，以及專注於最佳化工作的位置。
+  **ML 訓練管道的End-to-End延遲** — 測量資料流經整個訓練管道的總時間，從資料擷取到模型更新。跨訓練執行追蹤此指標，以識別管道變更是否改善或降低效能。高延遲通常表示節點之間的資料載入、預先處理或網路通訊存在瓶頸。
+  **訓練輸送量和處理率** — 追蹤訓練管道每單位時間處理的資料量，以確保有效率的資源使用率。監控指標，例如每秒處理的樣本或每分鐘完成的批次。相對於您的硬體容量而言，低輸送量表示浪費 GPU 週期的資料載入、預先處理或模型運算效率低下。
+  **檢查點儲存和還原延遲** – 監控將模型檢查點儲存到儲存體 (S3、EFS、FSx) 所需的時間，並在恢復任務或從故障中復原時將其還原到 GPU 或 CPU 記憶體。緩慢的檢查點操作會延長任務復原時間並增加成本。追蹤檢查點大小、節省持續時間、還原持續時間和失敗計數，以識別最佳化機會，例如壓縮或更快的儲存層。
+  **資料載入和預先處理時間** - 測量從儲存體載入資料和套用預先處理轉換所花費的時間。將此時間與模型運算時間進行比較，以判斷您的訓練是資料限制還是運算限制。如果資料載入耗用超過總訓練時間的 20%，請考慮使用快取、預先擷取或更快的儲存來最佳化資料管道。

 **錯誤率和失敗** 

監控整個訓練管道的錯誤率和故障，以維持可靠性並防止運算資源浪費。未偵測到的錯誤可能會導致訓練任務無提示地失敗、產生無效的模型，或在發現問題之前浪費數小時的 GPU 時間。
+  **管道錯誤監控** — 追蹤 ML 管道所有階段的錯誤，包括資料預先處理、模型訓練和檢查點操作。記錄錯誤類型、頻率和受影響的元件，以快速識別問題。常見的錯誤包括資料格式不相符、預先處理期間out-of-memory故障，以及檢查點儲存因儲存限制而失敗。設定錯誤率超過基準閾值時的提醒，以便在錯誤層疊之前進行調查。
+  **重複錯誤分析** — 識別和調查重複錯誤中的模式，以防止未來失敗並改善管道可靠性。分析日誌，以找出特定資料範例、批次大小或訓練組態是否一致地導致失敗。例如，如果某些輸入資料類型觸發預先處理錯誤，請在管道中稍早新增驗證檢查，或更新您的資料清理邏輯。追蹤故障之間的平均時間 (MTBF)，以測量管道可靠性是否隨著時間改善。」

 **Kubernetes 和 EKS 特定指標** 

監控 Kubernetes 和 EKS 指標，以確保您的叢集基礎設施正常運作，並可支援您的訓練工作負載。這些指標可協助您在基礎設施問題導致訓練任務失敗或效能降低之前對其進行偵測。
+  **Kubernetes 叢集狀態指標** — 監控 Kubernetes 物件的運作狀態和狀態，包括 Pod、節點、部署和服務。追蹤 Pod 狀態以識別停滯在待定、失敗或當機迴圈狀態的 Pod。監控節點條件，以偵測磁碟壓力、記憶體壓力或網路無法使用等問題。使用 kubectl 或監控工具持續檢查這些指標，並在 Pod 無法啟動或節點變得無法排程時設定提醒。
+  **訓練管道執行指標** — 追蹤成功和失敗的管道執行、任務持續時間、步驟完成時間和協同運作錯誤。監控訓練任務是否在預期的時段內完成，以及失敗率是否隨著時間增加。追蹤指標，例如任務成功率、平均任務持續時間和失敗時間。這些指標可協助您識別基礎設施問題、組態問題或資料品質問題是否會導致訓練失敗。
+  **AWS 服務指標** — 追蹤支援 EKS 基礎設施和訓練工作負載之 AWS 服務的指標。監控 S3 指標，例如請求延遲、錯誤率和輸送量，以確保資料載入效能保持一致。追蹤 EBS 磁碟區指標，包括 IOPS、輸送量和佇列長度，以偵測儲存瓶頸。監控 VPC 流量日誌和網路指標，以識別節點或外部服務之間的連線問題。
+  **Kubernetes 控制平面指標** — 監控 API 伺服器、排程器、控制器管理員等資料庫，以偵測影響叢集操作的效能問題或故障。追蹤 API 伺服器請求延遲、請求率和錯誤率，以確保控制平面快速回應排程請求。監控刻印資料庫大小、遞交持續時間和領導者變更，以偵測穩定性問題。高 API 伺服器延遲或頻繁的等推領導者變更可能會延遲 Pod 排程並延長訓練任務啟動時間。

 **應用程式和執行個體日誌** 

收集和分析應用程式和執行個體日誌，以診斷指標本身無法解釋的問題。日誌提供有關錯誤、狀態變更和系統事件的詳細內容，協助您了解訓練任務失敗或效能不佳的原因。將日誌與指標建立關聯可讓您更快地找出根本原因。
+  **應用程式日誌** - 從訓練任務、資料管道和 ML 架構收集應用程式日誌，以識別瓶頸並診斷故障。這些日誌會擷取任務執行的詳細資訊，包括資料載入錯誤、模型初始化失敗、檢查點儲存錯誤，以及架構特定的警告。將日誌時間戳記與指標峰值建立關聯，以了解造成效能降低或故障的原因。例如，如果 GPU 使用率突然下降，請檢查應用程式日誌是否有錯誤，指出資料管道停滯或預先處理失敗。使用 CloudWatch Logs 或 Fluent Bit 等集中式記錄工具來彙總所有 Pod 的日誌，並使其可供搜尋。
+  **執行個體日誌** - 收集執行個體層級日誌，例如系統日誌日誌和 dmesg 輸出，以偵測硬體問題和核心層級問題。這些日誌會顯示 GPU 驅動程式錯誤、記憶體配置失敗、磁碟 I/O 錯誤，以及應用程式日誌中可能不會出現的網路界面問題等問題。將執行個體日誌與應用程式日誌和指標建立關聯，以判斷訓練失敗是否來自硬體問題或應用程式問題。例如，如果訓練任務因out-of-memory錯誤而失敗，請檢查核心 OOM 刪除程式訊息的 dmesg 日誌，指出系統是否記憶體不足，或應用程式是否超過其容器限制。設定重大硬體錯誤的提醒，例如 GPU XID 錯誤或磁碟故障，以便在造成訓練中斷之前取代失敗的執行個體。

下列各節說明如何使用兩種 AWS 建議的方法收集上述指標：[CloudWatch Container Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/deploy-container-insights-EKS.html) 和 Amazon Managed Prometheus 與 Amazon [Managed](https://docs.aws.amazon.com/prometheus/latest/userguide/AMP-getting-started.html) Grafana。 [https://docs.aws.amazon.com/grafana/latest/userguide/getting-started-with-AMG.html](https://docs.aws.amazon.com/grafana/latest/userguide/getting-started-with-AMG.html)如果您偏好具有最少設定和預先建置儀表板的 AWS 原生工具，請選擇 CloudWatch Container Insights。如果您需要自訂儀表板、進階視覺化功能，或想要與現有的 Prometheus 型監控基礎設施整合，請選擇 Amazon Managed Prometheus with Amazon Managed Grafana。如需可用 Container Insights 指標的完整清單，請參閱 [Amazon EKS 和 Kubernetes Container Insights 指標](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-metrics-enhanced-EKS.html)。

### 考慮監控即時線上推論指標
<a name="_consider_monitoring_real_time_online_inference_metrics"></a>

在即時系統中，低延遲對於及時回應使用者或其他相依系統至關重要。高延遲可能會降低使用者體驗或違反效能要求。影響推論延遲的元件包括模型載入時間、預先處理時間、實際預測時間、後製處理時間、網路傳輸時間。我們建議監控推論延遲，以確保符合服務層級協議 (SLAs) 的低延遲回應，並為下列項目開發自訂指標。在預期負載下進行測試，包括網路延遲、考慮並行請求，以及使用不同的批次大小進行測試。
+  **首次權杖的時間 (TTFT)** — 從使用者提交請求到收到回應開始的時間長度 （第一個單字、權杖或區塊）。例如，在聊天機器人中，您會檢查使用者提出問題後產生第一段輸出 （權杖） 所需的時間。
+  **End-to-End延遲**：這是從收到請求到傳送回回應的總時間。例如，測量從請求到回應的時間。
+  **每秒輸出權杖 (TPS)** — 指出模型開始回應後產生新權杖的速度。例如，在聊天機器人中，您可以追蹤基準文字的語言模型產生速度。
+  **錯誤率 ** — 追蹤失敗的請求，這可能表示效能問題。例如，監控大型文件或特定字元的失敗請求。
+  **輸送量** — 測量系統每單位時間可處理的請求或操作數量。例如，追蹤每秒請求以處理尖峰負載。

K/V （金鑰/值） 快取可以是強大的推論延遲最佳化技術，尤其與轉換器型模型相關。K/V 快取會儲存先前轉換器層運算的金鑰和值張量，以減少自動迴歸推論期間的備援運算，尤其是大型語言模型 LLMs)。快取效率指標 （特別是 K/V 或工作階段快取使用）：
+  **快取命中/遺失率** — 對於利用快取 (K/V 或內嵌快取） 的推論設定，測量快取的協助頻率。低命中率可能表示快取組態或工作負載變更不佳，這兩者都可能增加延遲。

在後續主題中，我們會示範如何收集上述幾個指標的資料。我們將提供兩種 AWS 建議方法的範例：[AWS 原生 CloudWatch Container Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/deploy-container-insights-EKS.html) 和開放原始碼 [Amazon Managed Prometheus](https://docs.aws.amazon.com/prometheus/latest/userguide/AMP-getting-started.html) with [Amazon Managed Grafana](https://docs.aws.amazon.com/grafana/latest/userguide/getting-started-with-AMG.html)。您可以根據整體可觀測性需求選擇其中一個解決方案。如需 [Container Insights 指標的完整清單，請參閱 Amazon EKS 和 Kubernetes](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-metrics-enhanced-EKS.html) Container Insights 指標。

### 追蹤 GPU 記憶體用量
<a name="tracking-gpu-memory-usage"></a>

如[考慮監控核心訓練和微調指標](#aiml-consider-monitor-fine-tuning-metrics)主題所述，GPU 記憶體用量對於防止out-of-memory(OOM) 錯誤並確保有效率的資源使用率至關重要。下列範例示範如何檢測您的訓練應用程式，以公開自訂長條圖指標 `gpu_memory_usage_bytes`，並計算 P95 記憶體用量以識別尖峰耗用量。請務必在預備環境中使用範例訓練任務 （例如微調轉換器模型） 進行測試。

 **AWS 原生 CloudWatch Container Insights 範例** 

此範例示範如何使用 AWS 原生方法檢測您的訓練應用程式，以長條圖`gpu_memory_usage_bytes`的形式公開。請注意，您的 AI/ML 容器必須設定為以 CloudWatch [Embedded Metrics Format (EMF)](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format_Specification.html) 格式發出結構化日誌。CloudWatch 日誌會剖析 EMF 並發佈指標。在訓練應用程式中使用 [aws\$1embedded\$1metrics](https://github.com/awslabs/aws-embedded-metrics-python)，將 EMF 格式的結構化日誌傳送至擷取 GPU 指標的 CloudWatch Logs。

```
from aws_embedded_metrics import metric_scope
import torch
import numpy as np

memory_usage = []

@metric_scope
def log_gpu_memory(metrics):
    # Record current GPU memory usage
    mem = torch.cuda.memory_allocated()
    memory_usage.append(mem)

    # Log as histogram metric
    metrics.set_namespace("MLTraining/GPUMemory")
    metrics.put_metric("gpu_memory_usage_bytes", mem, "Bytes", "Histogram")

    # Calculate and log P95 if we have enough data points
    if len(memory_usage) >= 10:
        p95 = np.percentile(memory_usage, 95)
        metrics.put_metric("gpu_memory_p95_bytes", p95, "Bytes")
        print(f"Current memory: {mem} bytes, P95: {p95} bytes")

# Example usage in training loop
for epoch in range(20):
    # Your model training code would go here
    log_gpu_memory()
```

 **Prometheus 和 Grafana 範例** 

此範例示範如何使用 Python 中的 Prometheus 用戶端程式庫，檢測您的訓練應用程式以長條圖`gpu_memory_usage_bytes``形式公開。

```
from prometheus_client import Histogram
from prometheus_client import start_http_server
import pynvml

start_http_server(8080)
memory_usage = Histogram(
    'gpu_memory_usage_bytes',
    'GPU memory usage during training',
    ['gpu_index'],
    buckets=[1e9, 2e9, 4e9, 8e9, 16e9, 32e9]
)

# Function to get GPU memory usage
def get_gpu_memory_usage():
    if torch.cuda.is_available():
        # Get the current GPU device
        device = torch.cuda.current_device()

        # Get memory usage in bytes
        memory_allocated = torch.cuda.memory_allocated(device)
        memory_reserved = torch.cuda.memory_reserved(device)

        # Total memory usage (allocated + reserved)
        total_memory = memory_allocated + memory_reserved

        return device, total_memory
    else:
        return None, 0

# Get GPU memory usage
gpu_index, memory_used = get_gpu_memory_usage()
```

### 追蹤即時線上推論的推論請求持續時間
<a name="track-inference-request-duration-for-real-time-online-inference"></a>

如[考慮監控核心訓練和微調指標](#aiml-consider-monitor-fine-tuning-metrics)主題所述，低延遲對於為使用者或其他相依系統提供及時回應至關重要。下列範例示範如何追蹤您的推論應用程式`inference_request_duration_seconds`公開的自訂長條圖指標 。計算第 95 個百分位數 (P95) 延遲以專注於最壞的情況，在預備環境中使用合成推論請求 （例如，透過 Locust) 進行測試，並設定警示閾值 （例如，>500 毫秒） 以偵測 SLA 違規。

 **AWS 原生 CloudWatch Container Insights 範例** 

此範例示範如何使用 AWS CloudWatch Embedded Metric Format 在 inference\$1request\$1duration\$1seconds 的推論應用程式中建立自訂長條圖指標。

```
import boto3
import time
from aws_embedded_metrics import metric_scope, MetricsLogger

cloudwatch = boto3.client('cloudwatch')

@metric_scope
def log_inference_duration(metrics: MetricsLogger, duration: float):
    metrics.set_namespace("ML/Inference")
    metrics.put_metric("inference_request_duration_seconds", duration, "Seconds", "Histogram")
    metrics.set_property("Buckets", [0.1, 0.5, 1, 2, 5])

@metric_scope
def process_inference_request(metrics: MetricsLogger):
    start_time = time.time()

    # Your inference processing code here
    # For example:
    # result = model.predict(input_data)

    duration = time.time() - start_time
    log_inference_duration(metrics, duration)

    print(f"Inference request processed in {duration} seconds")

# Example usage
process_inference_request()
```

 **Prometheus 和 Grafana 範例** 

此範例示範如何使用 Python 中的 Prometheus 用戶端程式庫，在推論應用程式中為 inference\$1request\$1duration\$1seconds 建立自訂長條圖指標：

```
from prometheus_client import Histogram
from prometheus_client import start_http_server
import time

start_http_server(8080)
request_duration = Histogram(
    'inference_request_duration_seconds',
    'Inference request latency',
    buckets=[0.1, 0.5, 1, 2, 5]
)
start_time = time.time()
# Process inference request
request_duration.observe(time.time() - start_time)
```

在 Grafana 中，使用查詢`histogram_quantile(0.95, sum(rate(inference_request_duration_seconds_bucket[5m])) by (le, pod))`將 P95 延遲趨勢視覺化。若要進一步了解，請參閱 [Prometheus 直方圖文件](https://prometheus.io/docs/practices/histograms/)和 [Prometheus 用戶端文件](https://github.com/prometheus/client_python)。

### 追蹤即時線上推論的字符輸送量
<a name="_track_token_throughput_for_real_time_online_inference"></a>

如[考慮監控核心訓練和微調指標](#aiml-consider-monitor-fine-tuning-metrics)主題中所述，我們建議監控字符處理時間，以衡量模型效能並最佳化擴展決策。下列範例示範如何追蹤您的推論應用程式`token_processing_duration_seconds`公開的自訂長條圖指標 。計算第 95 個百分位數 (P95) 持續時間以分析處理效率、在非生產叢集中使用模擬請求負載 （例如每秒 100 到 1000 個請求） 進行測試，以及調整 KEDA 觸發以最佳化擴展。

 **AWS 原生 CloudWatch Container Insights 範例** 

此範例示範如何使用 AWS CloudWatch Embedded Metric Format 在 token\$1processing\$1duration\$1seconds 的推論應用程式中建立自訂長條圖指標。它使用維度 (`set\$1dimension`) with a custom `get_duration_bucket` 函數將持續時間分類為儲存貯體 （例如 "⇐0.01"、">1")。

```
import boto3
import time
from aws_embedded_metrics import metric_scope, MetricsLogger

cloudwatch = boto3.client('cloudwatch')

@metric_scope
def log_token_processing(metrics: MetricsLogger, duration: float, token_count: int):
    metrics.set_namespace("ML/TokenProcessing")
    metrics.put_metric("token_processing_duration_seconds", duration, "Seconds")
    metrics.set_dimension("ProcessingBucket", get_duration_bucket(duration))
    metrics.set_property("TokenCount", token_count)

def get_duration_bucket(duration):
    buckets = [0.01, 0.05, 0.1, 0.5, 1]
    for bucket in buckets:
        if duration <= bucket:
            return f"<={bucket}"
    return f">{buckets[-1]}"

@metric_scope
def process_tokens(input_text: str, model, tokenizer, metrics: MetricsLogger):
    tokens = tokenizer.encode(input_text)
    token_count = len(tokens)

    start_time = time.time()
    # Process tokens (replace with your actual processing logic)
    output = model(tokens)
    duration = time.time() - start_time

    log_token_processing(metrics, duration, token_count)
    print(f"Processed {token_count} tokens in {duration} seconds")
    return output
```

 **Prometheus 和 Grafana 範例** 

此範例示範如何在推論應用程式中使用 Python 中的 Prometheus 用戶端程式庫為 token\$1processing\$1duration\$1seconds 建立自訂長條圖指標。

```
from prometheus_client import Histogram
from prometheus_client import start_http_server
import time

start_http_server(8080)
token_duration = Histogram(
    'token_processing_duration_seconds',
    'Token processing time per request',
    buckets=[0.01, 0.05, 0.1, 0.5, 1]
)
start_time = time.time()
# Process tokens
token_duration.observe(time.time() - start_time)
```

在 Grafana 中，使用查詢`histogram_quantile(0.95, sum(rate(token_processing_duration_seconds_bucket[5m])) by (le, pod))``將 P95 處理時間趨勢視覺化。若要進一步了解，請參閱 [Prometheus 直方圖文件](https://github.com/prometheus/client_python)和 [Prometheus 用戶端文件](https://github.com/prometheus/client_python)。

 **測量檢查點還原延遲** 

如[考慮監控核心訓練和微調指標](#aiml-consider-monitor-fine-tuning-metrics)主題所述，檢查點延遲是模型生命週期的多個階段期間的關鍵指標。下列範例示範如何追蹤應用程式`checkpoint_restore_duration_seconds``公開的自訂長條圖指標 。計算第 95 個百分位數 (P95) 持續時間以監控還原效能、在非生產叢集中使用 Spot 中斷進行測試，並設定警示閾值 （例如 <30 秒） 以偵測延遲。

 **AWS 原生 CloudWatch Container Insights 範例** 

此範例示範如何使用 CloudWatch Insights 檢測批次應用程式，以長條圖的形式公開 checkpoint\$1restore\$1duration\$1seconds：

```
import boto3
import time
import torch
from aws_embedded_metrics import metric_scope, MetricsLogger

@metric_scope
def log_checkpoint_restore(metrics: MetricsLogger, duration: float):
    metrics.set_namespace("ML/ModelOperations")
    metrics.put_metric("checkpoint_restore_duration_seconds", duration, "Seconds", "Histogram")
    metrics.set_property("Buckets", [1, 5, 10, 30, 60])
    metrics.set_property("CheckpointSource", "s3://my-bucket/checkpoint.pt")

@metric_scope
def load_checkpoint(model, checkpoint_path: str, metrics: MetricsLogger):
    start_time = time.time()

    # Load model checkpoint
    model.load_state_dict(torch.load(checkpoint_path))

    duration = time.time() - start_time
    log_checkpoint_restore(metrics, duration)

    print(f"Checkpoint restored in {duration} seconds")
```

 **Prometheus 和 Grafana 範例** 

此範例示範如何使用 Python 中的 Prometheus 用戶端程式庫來檢測批次應用程式，以長條圖`checkpoint_restore_duration_seconds`的形式公開：

```
from prometheus_client import Histogram
from prometheus_client import start_http_server
import torch

start_http_server(8080)
restore_duration = Histogram(
    'checkpoint_restore_duration_seconds',
    'Time to restore checkpoint',
    buckets=[1, 5, 10, 30, 60]
)
with restore_duration.time():
    model.load_state_dict(torch.load("s3://my-bucket/checkpoint.pt"))
```

在 Grafana 中，使用查詢`histogram_quantile(0.95, sum(rate(checkpoint_restore_duration_seconds_bucket[5m]) by (le))`將 P95 還原延遲趨勢視覺化。若要進一步了解，請參閱 [Prometheus 直方圖文件](https://prometheus.io/docs/practices/histograms/)和 [Prometheus 用戶端文件](https://github.com/prometheus/client_python)。

# 應用程式擴展和效能
<a name="aiml-performance"></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)最佳實務。

## 管理 ML 成品、服務架構和啟動最佳化
<a name="_managing_ml_artifacts_serving_frameworks_and_startup_optimization"></a>

在 Amazon EKS 上部署機器學習 (ML) 模型需要考慮模型如何整合到容器映像和執行期環境中。這可確保可擴展性、重現性和高效的資源使用率。本主題說明處理 ML 模型成品、選取服務架構，以及透過預先快取等技術最佳化容器啟動時間的不同方法，所有方法都專為縮短容器啟動時間而量身打造。

### 在 部署中處理 ML 模型成品
<a name="_handling_ml_model_artifacts_in_deployments"></a>

關鍵決策是如何處理 ML 模型成品 （例如權重和組態）。選擇會影響影像大小、部署速度、模型更新頻率和操作額外負荷。請注意，當參考儲存「模型」時，我們指的是模型成品 （例如訓練過的參數和模型權重）。有不同的方法來處理 Amazon EKS 上的 ML 模型成品。每個 都有其權衡，最佳權衡取決於模型的大小、更新節奏和基礎設施需求。從最低到最高建議考慮以下方法：
+  **將模型製作到容器映像**中：在映像建置期間，將模型檔案 （例如 .safetensors、.pth、.h5) 複製到容器映像 （例如 Dockerfile)。模型是不可變影像的一部分。對於不常更新的小型模型，我們建議使用此方法。這可確保一致性和可重現性、提供無載入延遲，並簡化相依性管理，但會導致較大的映像大小、降低建置和推送速度、需要重建和重新部署模型更新，而且由於登錄提取輸送量，不適合大型模型。
+  **在執行時間下載模型**：在容器啟動時，應用程式會透過初始化容器或進入點中的指令碼，從外部儲存體 （例如，由 S3 CRT 支援的 Amazon S3，以使用 S3 CSI 驅動程式掛載點、AWS S3 CLI 或 s5cmd OSS CLI 等方法進行最佳化的高輸送量傳輸） 下載模型。對於經常更新的大型模型，我們建議您從此方法開始。這可讓容器映像專注於程式碼/執行時間、在不重建的情況下輕鬆進行模型更新、支援透過儲存中繼資料進行版本控制，但會導致潛在的網路故障 （需要重試邏輯）、需要身分驗證和快取。

若要進一步了解，請參閱《AI on EKS 研討會》中的[加速提取程序](https://awslabs.github.io/ai-on-eks/docs/guidance/container-startup-time/accelerate-pull-process)。

### 提供 ML 模型
<a name="_serving_ml_models"></a>

在 Amazon EKS 上部署和服務機器學習 (ML) 模型需要選擇適當的模型服務方法，以最佳化延遲、輸送量、可擴展性和操作簡單性。選擇取決於您的模型類型 （例如語言、視覺模型）、工作負載需求 （例如即時推論） 和團隊專業知識。常見的方法包括用於原型建構的 Python 型設定、用於生產級功能的專用模型伺服器，以及用於高效能和效率的專用推論引擎。每個方法都涉及設定複雜性、效能和資源使用率的權衡。請注意，服務架構可能會因為相依性而增加容器映像大小 （多個 GBs)，這可能會影響啟動時間，請考慮使用成品處理技術進行解耦來緩解這種情況。選項從最低到最高建議列出：

 **使用 Python 架構 （例如 FastAPI、HuggingFace 轉換器與 PyTorch)** 在容器化節點設定中，使用 Python 架構、內嵌模型檔案 （權重、組態、權杖化工具） 開發自訂應用程式。
+  **Pros**：簡單的原型設計，僅 Python，無需額外的基礎設施，相容於所有 HuggingFace 模型，簡單的 Kubernetes 部署。
+  **Cons**：限制為單一請求/簡單批次處理、權杖產生緩慢 （沒有最佳化的核心）、記憶體效率低下、缺少擴展/監控，以及涉及較長的啟動時間。
+  **建議**：用於需要自訂邏輯整合的初始原型或單一節點任務。

 **使用專用模型服務架構 （例如 TensorRT-LLM、TGI)** 採用 TensorRT-LLM 或 TGI 等特殊伺服器進行 ML 推論、管理模型載入、路由和最佳化。這些支援安全張量等格式，具有選用的編譯或外掛程式。
+  **Pros**：提供批次處理 （靜態/傳輸中或連續）、量化 (INT8、FP8、GPTQ)、硬體最佳化 (NVIDIA、AMD、Intel、Inferentia) 和多 GPU 支援 (Tensor/Pipeline 平行處理）。TensorRT-LLM 支援各種模型 (LLMs、Encoder-Decoder)，而 TGI 則利用 HuggingFace 整合。
+  **Cons**：TensorRT-LLM 需要編譯且僅限 NVIDIA；TGI 的批次處理效率可能較低；兩者都會增加組態額外負荷，而且可能不適合所有模型類型 （例如非轉換器）。
+  **建議**：適用於需要生產功能的 PyTorch/TensorFlow 模型，例如 A/B 測試或具有相容硬體的高輸送量。

 **使用專門的高輸送量推論引擎 （例如 vLLM)** 利用 vLLM 等進階推論引擎、使用 PagedAttention 最佳化 LLM 服務、傳輸中批次處理和量化 (INT8、FP8-KV、AWQ)，可與 EKS Autoscaling 整合。
+  **優點**：高輸送量和記憶體效率 （節省 40-60% VRAM)、動態請求處理、字符串流、單節點 Tensor 平行多 GPU 支援，以及廣泛的硬體相容性。
+  **Cons**：針對僅限解碼器的轉換器 （例如 LLaMA) 最佳化，對於非轉換器模型效率較低，需要相容的硬體 （例如 NVIDIA GPUs) 和設定工作。
+  **建議**：EKS 上大量、低延遲 LLM 推論的首選，可最大化可擴展性和效能。

## 最佳化容器映像提取時間
<a name="_optimizing_container_image_pull_times"></a>

大型容器映像可能會導致冷啟動延遲，進而影響 Pod 啟動延遲。對於延遲敏感工作負載，例如水平擴展的即時推論工作負載，快速 Pod 啟動至關重要。請考慮下列方法來最佳化容器映像提取時間：

### 減少容器映像大小
<a name="_reducing_container_image_sizes"></a>

在啟動期間減少容器映像的大小是使映像變小的另一種方式。您可以在容器映像建置程序的每個步驟進行減少。若要開始，請選擇包含所需最少數量相依性的基礎映像。在映像建置期間，僅包含必要的基本程式庫和成品。建置映像時，請嘗試結合多個 `RUN`或 `COPY`命令來建立較少數量的較大層。對於 AI/ML 架構，請使用多階段建置來分隔建置和執行時間、僅複製必要的成品 （例如，透過 `COPY —from=`用於登錄檔或本機內容），以及選取變體，例如僅限執行時間的影像 （例如，3`pytorch/pytorch:2.7.1-cuda11.8-cudnn9-runtime`.03 GB 與 6.66 GB 的 Devel)。若要進一步了解，請參閱 EKS 上的 AI 研討會中的[減少容器映像大小](https://awslabs.github.io/ai-on-eks/docs/guidance/container-startup-time/reduce-container-image-size)。

### 使用 SOCI 快照器預先提取影像
<a name="_using_soci_snapshotter_to_pre_pull_images"></a>

對於您無法輕鬆最小化的超大型映像，您可以使用平行提取和解壓縮模式中設定的開放原始碼 Seekable OCI (SOCI) 快照器。此解決方案可讓您使用現有的映像，而無需重建或修改建置管道。此選項在將具有非常大型映像的工作負載部署到高效能 EC2 運算執行個體時特別有效。它適用於高輸送量聯網和高效能儲存組態，如同擴展 AI/ML 工作負載一般。

SOCI 平行提取/解壓縮模式透過可設定的平行化策略改善end-to-end映像提取效能。更快的影像提取和準備會直接影響部署新工作負載和有效率地擴展叢集的速度。影像提取有兩個主要階段：

 **1。從登錄檔擷取層到節點**   
對於圖層擷取最佳化，SOCI 會為每個圖層建立多個並行 HTTP 連線，將下載輸送量乘以超過單一連線限制。它會將大型分層分割為區塊，並同時跨多個連線下載它們。此方法有助於飽和您的可用網路頻寬，並大幅縮短下載時間。這對單一 layer 可以是數 GB 的 AI/ML 工作負載來說特別重要。

 **2. 解壓縮和準備這些層以建立容器**   
為了進行 layer unpacking 最佳化，SOCI 會同時處理多個 layer。其使用您可用的 CPU 核心同時解壓縮和擷取多個層，而不是等待每個層完全解壓縮，再開始下一個層。此平行處理會將傳統 I/O 繫結的解壓縮階段轉換為 CPU 最佳化操作，以隨您可用的核心進行擴展。系統會仔細協調此平行化，以維持檔案系統一致性，同時最大化輸送量。

SOCI 平行提取模式使用雙閾值控制系統搭配可設定的參數，用於下載並行和解壓縮平行處理。此精細控制可讓您微調 SOCI 的行為，以符合您的特定效能需求和環境條件。了解這些參數可協助您最佳化執行時間，以獲得最佳提取效能。

 **參考** 
+ 如需解決方案和調校權衡的詳細資訊，請參閱 GitHub 上 [SOCI 專案儲存庫](https://github.com/awslabs/soci-snapshotter)中的[功能文件](https://github.com/awslabs/soci-snapshotter/blob/main/docs/parallel-mode.md)。
+ 如需在 Amazon EKS 上使用 Karpenter 的實作範例，請參閱[使用 SOCI 快照器平行提取/解壓縮模式的 Karpenter 藍圖](https://github.com/aws-samples/karpenter-blueprints/tree/main/blueprints/soci-snapshotter)。
+ 如需有關設定 Bottlerocket 進行平行提取的資訊，請參閱 Bottlerocket 文件中的[社交快照平行提取解壓縮模式](https://bottlerocket.dev/en/os/1.44.x/api/settings/container-runtime-plugins/#tag-soci-parallel-pull-configuration)。o

### 使用 EBS 快照預先提取映像
<a name="_using_ebs_snapshots_to_pre_pull_images"></a>

您可以拍攝快取容器映像的 Amazon Elastic Block Store (EBS) 快照，並為 EKS 工作者節點重複使用此快照。這可確保在節點啟動時在本機預先擷取映像，從而縮短 Pod 初始化時間。如需針對[受管節點群組使用 Karpenter](https://aws-ia.github.io/terraform-aws-eks-blueprints/patterns/machine-learning/ml-container-cache/) [和 EKS Terraform 藍圖的詳細資訊，請參閱使用 Bottlerocket 資料磁碟區縮短 Amazon EKS 上的容器啟動時間](https://aws.amazon.com/blogs/containers/reduce-container-startup-time-on-amazon-eks-with-bottlerocket-data-volume/)。

若要進一步了解，請參閱 AI on EKS 研討會中的[使用容器化快照器](https://awslabs.github.io/ai-on-eks/docs/guidance/container-startup-time/accelerate-pull-process/containerd-snapshotter)和將容器映像預先載入 Bottlerocket 資料磁碟區與 EBS 快照。 [https://awslabs.github.io/ai-on-eks/docs/guidance/container-startup-time/accelerate-pull-process/prefecthing-images-on-br](https://awslabs.github.io/ai-on-eks/docs/guidance/container-startup-time/accelerate-pull-process/prefecthing-images-on-br)

### 使用容器執行期快取來預先提取映像
<a name="_using_the_container_runtime_cache_to_pre_pull_images"></a>

您可以使用 Kubernetes 資源 （例如 DaemonSet 或 Deployment) 將容器映像預先提取至節點，以填入節點的容器執行期快取。容器執行期快取是由容器執行期管理的本機儲存體 （例如，從登錄檔提取後存放映像的[容器](https://containerd.io/)。 預先提取可確保映像可在本機使用，避免在 Pod 啟動期間發生下載延遲。 當映像經常變更 （例如頻繁更新）、EBS 快照未預先設定、建置 EBS 磁碟區比直接從容器登錄檔提取更耗時，或節點已在叢集中且需要使用多個可能映像之一隨需啟動 Pod 時，這種方法特別有用。

預先提取所有變體可確保快速啟動時間，無論需要哪個映像。例如，在需要 100，000 個使用 10 種不同技術建置之小型模型的大規模平行 ML 工作負載中，透過大型叢集 （例如數千個節點） 中的 DaemonSet 預先提取 10 個映像，可將 Pod 啟動時間降至最低，避免隨需提取在 10 秒內完成。使用容器執行期快取方法不需要管理 EBS 快照， 會確保您始終使用 DaemonSets 取得最新的容器映像版本，但對於節點擴展/擴展的即時推論工作負載，Cluster Autoscaler 等工具新增的新節點可能會在預先提取 DaemonSet 完成映像提取之前排程工作負載 Pod。這可能會導致新節點上的初始 Pod 觸發提取，進而可能延遲啟動並影響低延遲需求。此外，當磁碟用量超過特定閾值，或超過設定的最長未使用存留期時，kubelet 映像廢棄收集可以透過移除未使用的映像來影響預先提取的映像。在向內擴展/向外擴展模式中，這可能會移出閒置節點上的映像，這需要在後續擴展期間重新提取，並降低高載工作負載的快取可靠性。

如需將映像預先提取至容器執行期快取的範例，請參閱 [AWS GitHub 儲存庫](https://github.com/aws-samples/aws-do-eks/tree/main/Container-Root/eks/deployment/prepull)。

## 考慮 NVMe for kubelet 和容器儲存
<a name="_consider_nvme_for_kubelet_and_containerd_storage"></a>

請考慮設定 `kubelet`和 `containerd` 以使用暫時性 NVMe 執行個體儲存磁碟，以提高磁碟效能。容器提取程序涉及從登錄檔下載容器映像，並將其層解壓縮為可用的格式。若要在解壓縮期間最佳化 I/O 操作，您應該評估為容器主機執行個體類型提供更高水準的 I/O 效能和輸送量：具有本機儲存體的 [NVMe 後端執行個體](https://docs.aws.amazon.com/en_us/documentdb/latest/developerguide/db-instance-nvme.html)與 EBS 磁碟區 IOPS/輸送量。對於具有 NVMe 本機儲存的 EC2 執行個體，請考慮為 kubelet (`/var/lib/kubelet`)、 containerd (`/var/lib/containerd`) 和 Pod 日誌 (`/var/log/pods`) 設定節點的基礎檔案系統，以使用暫時性 NVMe 執行個體儲存磁碟以獲得更高層級的 I/O 效能和輸送量。

節點的暫時性儲存可以在請求暫時性儲存的 Pod 之間共用，以及請求下載到節點的容器映像。如果將 Karpenter 與 Bottlerocket 或 AL2023 EKS Optimized AMIs 搭配使用，這可以透過將 instanceStorePolicy 設定為 [RAID0](https://docs.aws.amazon.com/ebs/latest/userguide/raid-config.html)，或在 [NodeConfig](https://eksctl.io/usage/node-bootstrapping/#configuring-the-bootstrapping-process) 中將 localStoragePolicy 設定為使用者資料的一部分，在 [EC2NodeClass](https://karpenter.sh/docs/concepts/nodeclasses/#specinstancestorepolicy) 中設定。