本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
運算和自動擴展
GPU 資源最佳化和成本管理
使用 Well-Known 標籤以 GPU 需求排程工作負載
對於對不同 GPU 特性 (例如 GPU、GPU 記憶體) 敏感的 AI/ML 工作負載,建議使用與 Karpenter
範例
例如,使用 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
若要在節點上公開 GPUs,NVIDIA GPU 驅動程式必須安裝在節點的作業系統和容器執行時間上,設定成允許 Kubernetes 排程器將 Pod 指派給具有可用 GPUs 的節點。NVIDIA Kubernetes 裝置外掛程式的設定程序取決於您使用的 EKS 加速 AMI:
-
Bottlerocket 加速 AMI:此 AMI 包含 NVIDIA GPU 驅動程式,且已預先安裝 NVIDIA Kubernetes 裝置外掛程式
並可供使用,可立即支援 GPU。向 Kubernetes 排程器公開 GPUs 不需要額外的組態。 -
AL2023 加速 AMI
:此 AMI 包含 NVIDIA GPU 驅動程式,但未預先安裝 NVIDIA Kubernetes 裝置外掛程式 。您必須分別安裝和設定裝置外掛程式,通常是透過 DaemonSet。請注意,如果您使用 eksctl 在 ClusterConfig 中建立叢集並指定 GPU 執行個體類型 (例如 g5.xlarge),eksctl會自動選取適當的 AMI 並安裝 NVIDIA Kubernetes 裝置外掛程式。若要進一步了解,請參閱 eksctl 文件中的 GPU 支援。
如果您決定改用 EKS 加速 AMIs和 NVIDIA GPU 運算子
若要驗證 NVIDIA 裝置外掛程式是否作用中且 GPUs 已正確公開,請執行:
kubectl describe node | grep nvidia.com/gpu
此命令會檢查nvidia.com/gpu資源是否在節點的容量和可配置的資源中。例如,具有一個 GPU 的節點應該會顯示 nvidia.com/gpu: 1。如需詳細資訊,請參閱 Kubernetes GPU 排程指南
使用許多不同的 EC2 執行個體類型
盡可能使用多種不同的 EC2 執行個體類型,是 Amazon EKS 上可擴展性的重要最佳實務,如 Kubernetes 資料平面節所述。此建議也適用於具有加速硬體 (例如 GPUs) 的執行個體。如果您建立的叢集僅使用一種執行個體類型,並嘗試擴展超過該區域的容量的節點數量,您可能會收到容量不足錯誤 (ICE),表示沒有可用的執行個體。在任意多樣化之前,請務必了解 AI/ML 工作負載的獨特特性。使用 EC2 Instance Type Explorer
加速運算執行個體提供不同的購買模型,以符合短期、中期和穩定狀態工作負載。對於您想要避免進行保留的短期、彈性和容錯工作負載,請查看 Spot 執行個體。容量區塊、隨需執行個體和 Save Plans 可讓您佈建中長期工作負載持續時間的加速運算執行個體。為了增加在偏好的購買選項中成功存取所需容量的機會,建議使用各種執行個體類型和可用區域清單。或者,如果您遇到特定購買模型ICEs,請使用不同的模型重試。
範例 以下範例示範如何啟用 Karpenter NodePool 來佈建大於第 3 代的 G 和 P 執行個體 (例如 p3)。如需進一步了解,請參閱EKS 可擴展性最佳實務區段。
- 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 執行個體用於 GPUs 搭配 Karpenter
Amazon EC2 Spot 執行個體可讓您利用 AWS 雲端中未使用的 EC2 容量,並與隨需價格相比,提供高達 90% 的折扣。當 Amazon EC2 需要恢復容量時,Amazon EC2 Spot 執行個體可以透過兩分鐘的通知中斷。如需詳細資訊,請參閱《Amazon EC2 使用者指南》中的 Spot 執行個體。Amazon EC2 Spot 是容錯、無狀態和彈性 (時間和執行個體類型) 工作負載的理想選擇。若要進一步了解何時使用 Spot 執行個體,請參閱 EC2 Spot 執行個體最佳實務。如果適用於 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_GATES 環境變數來啟用 SpotToSpotConsolidation 功能閘道
。Karpenter price-capacity-optimized配置策略來佈建 EC2 執行個體。根據 NodePool 要求和 Pod 限制,Karpenter bin-packs 無法排程的 Pod,並將各種執行個體類型傳送至 Amazon EC2 機群 API。您可以使用 EC2 Instance Type Explorer 工具來產生符合您特定運算需求的執行個體類型清單。 -
確保工作負載無狀態、容錯能力和彈性。工作負載在執行個體/GPU 大小方面必須無狀態、容錯且靈活。這可在 Spot 中斷後無縫恢復,而執行個體彈性可讓您在 Spot 上停留更長的時間。使用 AWS SQS 佇列的名稱設定 settings.interruptionQueue Helm 值,以擷取 Spot 中斷事件,在 Karpenter 中啟用 Spot 中斷處理
。例如,透過 Helm 安裝 時,請使用 --set "settings.interruptionQueue=${CLUSTER_NAME}"。若要查看範例,請參閱 Karpenter 入門 指南。當 Karpenter 注意到 Spot 中斷事件時,它會在中斷事件之前自動封鎖、污點、耗盡和終止節點 (以最大化 Pod 的終止寬限期)。同時,Karpenter 會立即啟動新的節點,以便盡快準備就緒。 -
避免過度限制執行個體類型選擇。您應該盡可能避免限制執行個體類型。透過不限制執行個體類型,以較低的成本取得大規模 Spot 容量,並以較低的 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 追蹤等硬體需求。由於執行個體的類型可能不同,因此您需要確保您的工作負載能夠在每種類型上執行,以及您取得的效能符合您的需求。
-
利用區域中的所有可用區域。可用容量因可用區域 (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) 是一種工具,可提供分數,協助您評估 Spot 請求成功的可能性。當您使用 SPS 時,首先指定 Spot 執行個體的運算需求,然後 Amazon EC2 會傳回 Spot 請求可能成功的前 10 個區域或可用區域 (AZs)。區域和可用區域的分數範圍是從 1 到 10。分數為 10 表示您的 Spot 請求很有可能,但不保證成功。分數 1 表示您的 Spot 請求完全不可能成功。對於不同的區域或可用區域,可能會傳回相同的分數。若要進一步了解,請參閱在 AWS 上建立 Spot 配置分數追蹤器儀表板的指引。隨著 Spot 容量隨時波動,SPS 將協助您識別最適合工作負載限制 (即彈性、效能、大小等) AZs 和區域的組合。如果您的 AI/ML 工作負載需要特定或有限數量的加速器,但區域之間具有彈性,您可以使用 Spot 置放分數,在啟動之前動態識別部署工作負載的最佳區域。為了協助您自動找出取得 Spot 容量的可能性,我們提供建置 SPS 追蹤器儀表板的指引。此解決方案使用 YAML 組態來監控多樣化設定 (例如,包括 GPUs 的執行個體需求) 的 SPS 分數、在 CloudWatch 中存放指標,並提供儀表板來比較組態。定義每個工作負載的儀表板,以評估 vCPU、記憶體和 GPU 需求,確保 EKS 叢集的最佳設定,包括考慮使用其他 AWS 區域。若要進一步了解,請參閱 Spot 配置分數的運作方式。
-
優雅地處理 Spot 中斷和測試。對於終止期間超過兩分鐘的 Pod,舊節點會在重新排程這些 Pod 之前中斷,這可能會影響工作負載可用性。設計應用程式時,請考慮兩分鐘 Spot 中斷通知, 在長時間執行的應用程式中實作檢查點 (例如, 將進度儲存至 Amazon S3 等持久性儲存體),以在中斷後繼續, 在 Pod 規格中延長 terminationGracePeriodSeconds (預設值為 30 秒),以有更多時間進行正常關機, 和 會在您的應用程式中使用preStop生命週期掛鉤和/或 SIGTERM 訊號來處理中斷,以進行正常的關機活動,例如清除、 狀態儲存、 和 連線關閉。對於即時工作負載,其中擴展時間很重要,且工作負載需要超過兩分鐘的時間才能準備好為流量提供服務,請考慮透過檢閱 和應用程式擴展和效能最佳實務來最佳化容器啟動儲存和 ML 模型載入時間。若要測試替代節點,請使用 AWS Fault Injection Service
(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
等工具在執行時間分析模型的記憶體用量,並在 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
實作長時間執行訓練任務的檢查點
檢查點是一種容錯技術,涉及定期儲存程序的狀態,以便在中斷時從上次儲存的點恢復。在機器學習中,它通常與訓練相關,其中長時間執行的任務可以節省模型權重和最佳化工具狀態,以便在失敗後繼續訓練,例如硬體問題或 Spot 執行個體中斷。
您可以在訓練期間使用檢查點來儲存機器學習 (ML) 模型的狀態。檢查點是模型的快照,並且可以透過機器學習 (ML) 架構的回呼函式進行設定。您可以使用儲存的檢查點,從上次儲存的檢查點重新啟動訓練任務。使用檢查點,您可以儲存訓練中的模型快照,因為訓練任務或執行個體意外中斷。這可讓您在未來從檢查點繼續訓練模型。除了實作節點彈性系統之外,建議您實作檢查點,以減輕中斷的影響,包括硬體故障或 Amazon EC2 Spot 執行個體中斷所造成的中斷。
如果沒有檢查點,中斷可能會導致運算時間浪費和進度遺失,這對於長時間執行的訓練任務非常昂貴。檢查點可讓任務定期儲存其狀態 (例如模型權重和最佳化工具狀態),並在中斷後從最後一個檢查點 (上次處理的批次) 恢復。若要實作檢查點,請設計您的應用程式以處理大量資料,並在訓練任務進行時透過 Amazon S3 CSI 驅動程式掛載點將中繼結果儲存到持久性儲存體,例如 Amazon S3 儲存貯體。
使用案例
檢查點在特定案例中特別有用,以平衡容錯能力與效能額外負荷。在下列情況下,請考慮使用檢查點:
-
任務持續時間超過幾個小時:對於長時間執行的訓練任務 (例如,對於小型模型 >1-2 小時,對於具有數十億個參數的大型基礎模型,則為天數/週),其中中斷造成的進度損失成本很高。較短的任務可能不會證明 I/O 額外負荷。
-
對於 Spot 執行個體或硬體故障:在容易中斷的環境中,例如 EC2 Spot (2 分鐘通知) 或硬體故障 (例如 GPU 記憶體錯誤),檢查點可快速恢復,讓 Spot 能夠節省容錯工作負載的成本。
-
大規模分散式訓練:適用於具有數百/數千個加速器的設定 (例如 >100 GPUs),其中故障之間的平均時間會隨規模線性減少。使用 進行模型/資料平行處理,以處理並行檢查點存取並避免完全重新啟動。
-
具有高資源需求的大規模模型:在 PB 級 LLM 訓練中,失敗是因叢集大小而不可避免的;分層方法 (暫時性方法為快速本機每 5-30 分鐘一次,主要故障為每小時耐用一次) 可最佳化復原時間與效率。
使用 ML 容量區塊來確保 P 和 Trainium 執行個體的容量
ML 的容量區塊可讓您保留熱門的 GPU 執行個體,特別是 P 執行個體 (例如 p6-b200、p5、p5e、p5en、p4d、p4de) 和 Trainium 執行個體 (例如 trn1、trn2),以幾乎立即開始或在未來日期開始,以支援您的短期機器學習 (ML) 工作負載。這些保留非常適合用來確保運算密集型任務的容量,例如模型訓練和微調。EC2 容量區塊定價包含保留費和作業系統費用。若要進一步了解定價,請參閱適用於 ML 定價的 EC2 容量區塊
若要為 Amazon EKS 上的 AI/ML 工作負載保留 GPUs,以確保可預測的容量,建議您將 ML 容量區塊用於短期或隨需容量保留 ODCRs),以確保一般用途容量。
-
ODCRs 可讓您在特定可用區域中保留 EC2 執行個體容量 (例如 g5 或 p5 等 GPU 執行個體),即使在高需求期間也能確保可用性。ODCRs沒有長期承諾,但您要支付預留容量的隨需費率,無論是已使用或閒置。在 EKS 中,Karpenter
和受管節點群組等節點類型支援 ODCRs。若要排定 Karpenter 中的 ODCRs優先順序,請將 NodeClass 設定為使用 capacityReservationSelectorTerms欄位。請參閱 Karpenter NodePools 文件。 -
容量區塊是 GPU (例如 p5、p4d) 或 Trainium (trn1、trn2) 執行個體的特殊保留機制,專為模型訓練、微調或實驗等短期 ML 工作負載而設計。您從未來日期開始為定義的期間 (通常為 24 小時至 182 天) 保留容量,僅支付預留時間的費用。它們是預付的,需要預先規劃容量需求,且不支援自動擴展,但會共置在 EC2 UltraClusters 中以進行低延遲聯網。它們只會收取預留期間的費用。若要進一步了解,請參閱尋找和購買容量區塊,或使用建立具有 ML 容量區塊的受管節點群組中的指示,使用容量區塊設定受管節點群組。
透過 AWS 管理主控台預留容量,並將節點設定為使用 ML 容量區塊。根據工作負載排程規劃保留,並在預備叢集中進行測試。如需詳細資訊,請參閱容量區塊文件。
考慮 G Amazon EC2 執行個體的隨需、Amazon EC2 Spot 或隨需容量保留 (ODCRs)
對於 G Amazon EC2 執行個體,請考慮與隨需、Amazon EC2 Spot 執行個體和隨需容量保留不同的購買選項。ODCRs 可讓您在特定的可用區域中保留 EC2 執行個體容量一段時間,即使在高需求期間也能確保可用性。與僅適用於 P 和 Trainium 執行個體的 ML 容量區塊不同,ODCRs 可用於更廣泛的執行個體類型,包括 G 執行個體,使其適用於需要不同 GPU 功能的工作負載,例如推論或圖形。使用 Amazon EC2 Spot 執行個體時,能夠跨不同的執行個體類型、大小和可用區域進行多樣化,是能夠長時間停留在 Spot 上的關鍵。
ODCRs沒有長期承諾,但您要支付預留容量的隨需費率,無論是已使用或閒置。您可以建立 ODCRs以供立即使用,或排定未來日期,提供容量規劃的彈性。在 Amazon EKS 中,KarpentercapacityReservationSelectorTerms 欄位。請參閱 Karpenter NodePools 文件
考慮其他加速執行個體類型和大小
選取適當的加速執行個體和大小對於在 Amazon EKS 上最佳化 ML 工作負載的效能和成本至關重要。例如,不同的 GPU 執行個體系列具有不同的效能和功能,例如 GPU 記憶體。為了協助您選擇價格效能最佳的選項,請檢閱加速運算下 EC2 執行個體類型頁面中可用的 GPU 執行個體
如果您在 EKS 節點中使用 GPU 執行個體,則預設在kube-system命名空間中會有 nvidia-device-plugin-daemonset Pod。若要快速了解您是否充分利用執行個體中的 GPU,您可以使用 nvidia-smi
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 的運算容量 (GPU)。 -
-l 5旗標指出 每 5 秒輸出一次指標。如果是單一 GPU 執行個體類型,則不需要索引查詢旗標。
若要進一步了解,請參閱 AWS 文件中的 GPU 執行個體。
使用時間分割、MIG 和分量 GPU 配置來最佳化 GPU 資源配置
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 排程器
是 Run:ai 平台的一部分,透過允許 Pod 請求部分 GPU 資源來啟用此功能。
若要在 EKS 中啟用這些功能,您可以部署 NVIDIA 裝置外掛程式,將 GPUs 公開為可排程的資源,並支援時間分割和 MIG。若要進一步了解,請參閱 Kubernetes 中的時間分割 GPUs,
範例
例如,若要使用 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
節點彈性和訓練任務管理
使用自動復原實作節點運作狀態檢查
對於需要頻繁節點間通訊的 Amazon EKS 分散式訓練任務,例如跨多個節點的多 GPU 模型訓練,GPU 或 EFA 失敗等硬體問題可能會導致訓練任務中斷。這些中斷可能會導致訓練進度的損失和成本增加,尤其是依賴穩定硬體的長期執行 AI/ML 工作負載。
為了協助增加硬體故障的彈性,例如執行 GPU 工作負載的 EKS 叢集中的 GPU 失敗,我們建議您利用 EKS 節點監控代理程式搭配自動修復或 Amazon SageMaker HyperPod。雖然具有自動修復功能的 EKS 節點監控代理程式提供節點運作狀態監控和使用標準 Kubernetes 機制的自動修復等功能,但 SageMaker HyperPod 提供目標彈性和其他專為大規模 ML 訓練而設計的功能,例如深度運作狀態檢查和自動恢復任務。
-
EKS Node Monitoring Agent with Node Auto Repair 透過讀取日誌和套用 NodeConditions 來持續監控節點運作狀態,包括加速硬體的特定標準條件,例如
Ready和 條件,以識別 GPU 或網路故障等問題。當節點視為運作狀態不佳時,Node Auto Repair 會將其封鎖,並將其取代為新的節點。重新排程 Pod 和重新啟動任務取決於標準 Kubernetes 機制和任務的重新啟動政策。 -
SageMaker HyperPod
深度運作狀態檢查和運作狀態監控代理程式會持續監控 GPU 和 Trainium 型執行個體的運作狀態。它專為 AI/ML 工作負載量身打造,使用標籤 (例如 node-health-status) 來管理節點運作狀態。當節點視為運作狀態不佳時,HyperPod 會觸發自動取代故障的硬體,例如 GPUs。它預設透過 EFA 的基本運作狀態檢查來偵測與聯網相關的故障,並支援針對中斷的訓練任務自動恢復,允許任務從最後一個檢查點繼續,將大規模 ML 任務的中斷降至最低。
對於具有自動修復的 EKS 節點監控代理程式和使用 EFA 的 SageMaker HyperPod 叢集,若要監控 EFA 特定的指標,例如遠端直接記憶體存取 (RDMA) 錯誤和封包捨棄,請確定已安裝 AWS EFA 驅動程式。此外,我們建議部署 CloudWatch 可觀測性附加元件或使用 DCGM Exporter 等工具搭配 Prometheus 和 Grafana,以監控 EFA、GPU,以及針對 SageMaker HyperPod,與其功能相關的特定指標。
針對對中斷敏感的工作負載停用 Karpenter 合併
對於對處理、大規模 AI/ML 預測任務或訓練等中斷敏感的工作負載,我們建議調校 Karpenter 整合政策
WhenEmptyOrUnderutilized 合併政策可能會提早終止節點,導致執行時間延長。例如,由於 Pod 重新排程、資料重新載入,中斷可能會延遲任務恢復,這對於長時間執行的批次推論任務可能非常昂貴。若要緩解這種情況,您可以將 consolidationPolicy 設定為 ,WhenEmpty並設定consolidateAfter持續時間,例如 1 小時,以在工作負載尖峰期間保留節點。例如:
disruption: consolidationPolicy: WhenEmpty consolidateAfter: 60m
此方法可改善尖峰批次推論工作負載和其他干擾敏感任務的 Pod 啟動延遲,例如即時線上推論資料處理或模型訓練,其中中斷成本高於運算成本節省。Karpenter NodePool 中斷預算
使用 ttlSecondsAfterFinished 自動清除 Kubernetes 任務
我們建議ttlSecondsAfterFinished在 Amazon EKS 中設定 Kubernetes 任務,以自動刪除已完成的任務物件。內嵌任務物件會耗用叢集資源,例如 API 伺服器記憶體,並透過雜亂儀表板 (例如 Grafana、Amazon CloudWatch) 來複雜化監控。例如,將 TTL 設定為 1 小時可確保任務會在完成後不久移除,讓您的叢集保持整齊。如需詳細資訊,請參閱完成任務的自動清除
設定較高優先順序任務/工作負載的低優先順序任務優先順序
對於 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
應用程式擴展和效能
使用 Karpenter 或靜態節點的 ML 工作負載量身訂做運算容量
為了確保 Amazon EKS 上機器學習 (ML) 工作流程的成本效益和回應性運算容量,我們建議您根據工作負載的特性和成本承諾量身打造節點佈建策略。以下是兩個需要考慮的方法:使用 Karpenter
-
Just-in-time資料平面縮放器,例如 Karpenter:對於具有可變運算需求的動態 ML 工作流程 (例如,GPU 型推論,後面接著 CPU 型繪圖),我們建議使用just-in-time資料平面縮放器,例如 Karpenter。
-
將靜態節點群組用於可預測的工作負載:對於可預測、穩定狀態的 ML 工作負載或使用預留執行個體時,EKS 受管節點群組可協助確保預留容量已完全佈建和使用,從而最大限度地節省成本。此方法非常適合透過 RIs 或 ODCRs 遞交的特定執行個體類型。
範例
這是各種 Karpenter NodePoolg 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
使用污點和容錯,防止在加速執行個體上排程非加速工作負載
在 GPU 資源上排程非加速工作負載不具運算效率,我們建議使用污點和容錯,以確保非加速工作負載 Pod 不會排程在不適當的節點上。如需詳細資訊,請參閱 Kubernetes 文件
根據模型效能擴展
對於推論工作負載,我們建議您使用 Kubernetes Event-Driven Autoscaling (KEDA) 根據模型效能指標進行擴展,例如推論請求或字符輸送量,並具有適當的冷卻時間。靜態擴展政策可能會過度佈建或佈建不足的資源,影響成本和延遲。如需進一步了解,請參閱 KEDA 文件
進階 GPU 管理的動態資源配置
動態資源配置 (DRA)
-
精細的 GPU 配置
-
進階共用機制,例如多程序服務 (MPS) 和多執行個體 GPU (MIG)
-
支援新一代硬體架構,包括 NVIDIA GB200 UltraServers
傳統 GPU 配置會將 GPUs 視為不透明的整數資源,造成顯著的使用不足 (通常在生產叢集中為 30-40%)。這是因為即使只需要部分資源,工作負載也會取得整個 GPUs 的專屬存取權。DRA 透過引入結構化的宣告式配置來轉換此模型,讓 Kubernetes 排程器完全了解硬體特性和工作負載需求。這可實現智慧型配置決策和有效率的資源共用。
使用 DRA 而非 NVIDIA 裝置外掛程式的優點
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 支援的執行個體及其功能
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 跨節點的記憶體一致性通訊。
其他資源
如需 Kubernetes DRA 和 NVIDIA DRA 驅動程式的詳細資訊,請參閱 GitHub 上的下列資源:
設定動態資源配置以進行進階 GPU 管理
下列主題說明如何設定動態資源配置 (DRA) 以進行進階 GPU 管理。
先決條件
在 Amazon EKS 上實作 DRA 之前,請確定您的環境符合下列要求。
叢集組態
-
執行版本
1.33或更新版本的 Amazon EKS 叢集 -
Amazon EKS 受管節點群組 (DRA 目前僅支援具有 AL2023 和 Bottlerocket NVIDIA 最佳化 AMIs受管節點群組,不支援 Karpenter
) -
具有適當執行個體類型的 NVIDIA GPU 工作者節點
必要元件
-
NVIDIA 裝置外掛程式版本
0.17.1或更新版本 -
NVIDIA DRA 驅動程式版本
25.3.0或更新版本
步驟 1:使用 eksctl 使用已啟用 DRA 的節點群組建立叢集
-
建立名為 的叢集組態檔案
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 -
建立叢集:
eksctl create cluster -f dra-eks-cluster.yaml
步驟 2:部署 NVIDIA 裝置外掛程式
部署 NVIDIA 裝置外掛程式以啟用基本 GPU 探索:
-
新增 NVIDIA 裝置外掛程式 Helm 儲存庫:
helm repo add nvidia https://nvidia.github.io/k8s-device-plugin helm repo update -
為裝置外掛程式建立自訂值:
cat <<EOF > nvidia-device-plugin-values.yaml gfd: enabled: true nfd: enabled: true tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule EOF -
安裝 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
-
建立 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 -
新增 NVIDIA NGC Helm 儲存庫:
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia helm repo update -
安裝 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 安裝
-
確認 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 -
檢查可用的裝置類別:
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 工作負載
若要使用動態資源配置 (DRA) 排程簡單的 GPU 工作負載,請執行下列步驟。在繼續之前,請確定您已遵循 設定動態資源配置以進行進階 GPU 管理。
-
使用名為
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 -
套用範本:
kubectl apply -f basic-gpu-claim-template.yaml -
驗證狀態:
kubectl get resourceclaimtemplates -n gpu-test1下列為範例輸出:
NAME AGE single-gpu 9m16s -
建立使用
ResourceClaimTemplate檔案名為 的 Podbasic-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" -
套用和監控 Pod:
kubectl apply -f basic-gpu-pod.yaml -
檢查 Pod 狀態:
kubectl get pod -n gpu-test1以下是預期的輸出範例:
NAME READY STATUS RESTARTS AGE gpu-pod 1/1 Running 0 13m -
檢查
ResourceClaim狀態:kubectl get resourceclaims -n gpu-test1以下是預期的輸出範例:
NAME STATE AGE gpu-pod-gpu0-l76cg allocated,reserved 9m6s -
檢視 Pod 日誌以查看 GPU 資訊:
kubectl logs gpu-pod -n gpu-test1以下是預期的輸出範例:
GPU 0: NVIDIA L4 (UUID: GPU-da7c24d7-c7e3-ed3b-418c-bcecc32af7c5)
繼續使用 DRA 繼續取得更進階具有動態資源配置的 GPU 最佳化技術的 GPU 最佳化技術。
具有動態資源配置的 GPU 最佳化技術
現代 GPU 工作負載需要複雜的資源管理,才能達到最佳的使用率和成本效益。DRA 啟用數種進階最佳化技術,可解決不同的使用案例和硬體功能:
-
時間分割可讓多個工作負載隨時間共用 GPU 運算資源,因此非常適合偶爾使用 GPU 的推論工作負載。如需範例,請參閱「使用時間分割最佳化 GPU 工作負載」。
-
多程序服務 (MPS) 可在單一 GPU 上並行執行多個 CUDA 程序,與時間分割相比具有更好的隔離能力。如需範例,請參閱「使用 MPS 最佳化 GPU 工作負載」。
-
多執行個體 GPU (MIG) 提供硬體層級分割,以專用運算和記憶體資源建立隔離的 GPU 執行個體。如需範例,請參閱「使用多執行個體 GPU 最佳化 GPU 工作負載」。
-
Internode Memory Exchange (IMEX) 可讓跨節點的記憶體一致性通訊,以便在 NVIDIA GB200 系統上進行分散式訓練。如需範例,請參閱「使用 GB200 P6e 執行個體透過 IMEX 最佳化 GPU 工作負載」。
這些技術可以大幅改善資源使用率。Organizations 報告 GPU 使用率從傳統配置的 30-40% 增加到最佳化共用策略的 80-90%。技術選擇取決於工作負載特性、隔離要求和硬體功能。
使用時間分割最佳化 GPU 工作負載
時間分割可讓多個工作負載透過排程在相同的實體 GPU 上循序執行,來共用 GPU 運算資源。它非常適合使用零星 GPU 的推論工作負載。
執行下列步驟。
-
使用名為 的檔案定義時間分割
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 -
使用名為 的檔案,使用時間分割來定義 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 -
套用範本和 Pod:
kubectl apply -f timeslicing-claim-template.yaml kubectl apply -f timeslicing-pod.yaml -
監控資源宣告:
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 狀態:等待排程
-
狀態將從 移至
pendingallocated,reserved至running
使用 MPS 最佳化 GPU 工作負載
多程序服務 (MPS) 可在單一 GPU 上並行執行多個 CUDA 內容,其隔離能力優於時間分割。
執行下列步驟。
-
使用名為 的檔案為
ResourceClaimTemplateMPS 定義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 -
使用 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 -
套用範本並建立多個 MPS Pod:
kubectl apply -f mps-claim-template.yaml kubectl apply -f mps-pod.yaml -
監控資源宣告:
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+C (MPS + Compute) 程序。 -
監控兩個容器的日誌,這會顯示可同時執行的交錯時間戳記。
這種方法允許互補工作負載有效地共用昂貴的 GPU 硬體,而不是讓單一程序未充分利用 GPU 使用率,從而最大限度地提高 GPU 使用率。
Container1: inference-container
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
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 工作負載
多執行個體 GPU (MIG) 提供硬體層級分割,建立具有專用運算和記憶體資源的隔離 GPU 執行個體。
搭配各種設定檔使用動態 MIG 分割需要 NVIDIA GPU OperatorWITH0—REBOOT=true中啟用 對成功的 MIG 部署至關重要。
您需要 NVIDIA DRA 驅動程式
步驟 1:部署 NVIDIA GPU Operator
-
新增 NVIDIA GPU Operator 儲存庫:
helm repo add nvidia https://nvidia.github.io/gpu-operator helm repo update -
建立
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 -
使用
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 (生命週期管理)
-
-
驗證部署 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 -
使用 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 IDNVIDIA GPU Operator 使用新增至節點的標籤,
nvidia.com/mig.config: "p4de-half-balanced"並以指定的設定檔分割 GPU。 -
登入
p4de執行個體。 -
執行以下命令:
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 資源配置
現在,讓我們執行一些範例,示範 DRA 如何將 MIG 執行個體動態分配給不同的工作負載。部署 resourceclaimtemplates和 測試 Pod,以查看 DRA 驅動程式如何將工作負載放在可用的 MIG 分割區,允許多個容器與硬體層級隔離共用 GPU 資源。
-
建立
mig-claim-template.yaml以包含 MIGresourceclaimtemplates: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' -
套用三個範本:
kubectl apply -f mig-claim-template.yaml -
執行以下命令:
kubectl get resourceclaimtemplates -n mig-gpu下列為範例輸出:
NAME AGE mig-large-template 71m mig-medium-template 71m mig-small-template 71m -
建立
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 -
套用此規格,應部署三個 Pod:
kubctl apply -f mig-pod.yaml這些 Pod 應由 DRA 驅動程式排程。
-
檢查 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**],}] -
驗證
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從待定移至 。 -
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 工作負載
IMEX (Internode Memory Exchange) 可讓跨節點的記憶體一致性通訊,以便在 NVIDIA GB200 UltraServers 上進行分散式訓練。
執行下列步驟。
-
使用名為 的檔案為
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 -
使用 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 執行個體。
-
透過套用
ComputeDomain和 範本來部署 IMEX:kubectl apply -f imex-claim-template.yaml kubectl apply -f imex-compute-domain.yaml kubectl apply -f imex-pod.yaml -
檢查
ComputeDomain狀態。kubectl get computedomain distributed-training-domain -
監控 IMEX 協助程式部署。
kubectl get pods -n nvidia-dra-driver -l resource.nvidia.com/computeDomain -
檢查 Pod 中的 IMEX 頻道:
kubectl exec imex-distributed-training -- ls -la /dev/nvidia-caps-imex-channels/ -
檢視 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 範例