Kubernetes GPU調(diào)度進(jìn)階:動(dòng)態(tài)資源分配
把 GPU 塞進(jìn) Kubernetes 集群跑任務(wù)不難,難的是讓昂貴算力別閑著。多數(shù)團(tuán)隊(duì)的 GPU 利用率徘徊在 30% 出頭,一張 A100 常被一個(gè)只需十分之一顯存的 Pod 牢牢占住。Kubernetes GPU 動(dòng)態(tài)資源分配實(shí)戰(zhàn)要解決的正是這類看似“正?!钡睦速M(fèi)——讓調(diào)度器不再只數(shù)卡,而是真正讀懂每塊 GPU 的狀態(tài)與需求。
一、Kubernetes GPU調(diào)度的痛點(diǎn)與挑戰(zhàn)
1. 資源獨(dú)占現(xiàn)象
獨(dú)占是當(dāng)前 GPU 調(diào)度最直觀的絆腳石。一個(gè) Pod 通過 nvidia.com/gpu: 1 申領(lǐng)整張卡,即使只跑顯存 4GB 的小推理任務(wù),其余算力和顯存全部閑置。行業(yè)共識(shí)的 GPU 集群平均利用率長(zhǎng)期低于 40%,根源就在這里?;觳坑?xùn)練、多推理副本想要共享同一塊 GPU,在傳統(tǒng) Device Plugin 模型下毫無辦法——它只關(guān)心“卡數(shù)”,不關(guān)心“用了多少”。
2. 手動(dòng)分配限制
多卡作業(yè)的部署更是一場(chǎng)手工排雷。不同節(jié)點(diǎn)可能混雜 A100 40GB、80GB 或者不同廠商 GPU,用戶不得不靠 nodeSelector 硬寫調(diào)度規(guī)則,把 Pod 綁死在特定型號(hào)和節(jié)點(diǎn)上。規(guī)模一上來,碎片化隨之惡化:批次任務(wù)必須等到所有 GPU 同時(shí)就緒才能起跑,只要有一張卡被別的業(yè)務(wù)占用,整批作業(yè)就原地阻塞,調(diào)度延遲被無限放大。
3. 動(dòng)態(tài)分配優(yōu)勢(shì)
從“算數(shù)量”轉(zhuǎn)向“看屬性+狀態(tài)”,是動(dòng)態(tài)資源分配帶來的根本變化。新的 ResourceClaim 機(jī)制讓 Pod 聲明所需設(shè)備屬性——如顯存下限、NVLink 需求,調(diào)度器再根據(jù)實(shí)時(shí)可用資源匹配。這意味著 GPU 不用預(yù)先鎖定,控制器可以在 Pod 綁定節(jié)點(diǎn)后才決定到底用哪幾塊卡或 MIG 實(shí)例,從根本上解耦了“請(qǐng)求”和“分配”,為細(xì)粒度共享、跨隊(duì)列公平調(diào)度鋪平道路。
二、動(dòng)態(tài)資源分配(DRA)核心概念
GPU 集群長(zhǎng)期被一個(gè)剛性規(guī)則困住:一旦 Pod 申請(qǐng)了 nvidia.com/gpu: 1,哪怕只用到 10% 的算力,整張卡也會(huì)被鎖定。我們觀察到大量生產(chǎn)集群中 GPU 利用率徘徊在 35%~40%,不是因?yàn)樨?fù)載不足,而是傳統(tǒng)設(shè)備分配機(jī)制強(qiáng)制“整卡獨(dú)占”,導(dǎo)致碎片化嚴(yán)重,高吞吐的推理服務(wù)與輕量訓(xùn)練任務(wù)無法靈活共存。Kubernetes 社區(qū)從 v1.26 開始孵化的動(dòng)態(tài)資源分配(Dynamic Resource Allocation,簡(jiǎn)稱 DRA)正是在這個(gè)背景下,嘗試把 GPU 調(diào)度從“數(shù)卡”推進(jìn)到“看屬性+控分配”的精細(xì)化階段。
1. DRA 原理簡(jiǎn)介
過去,Device Plugin 采用集中式計(jì)數(shù):節(jié)點(diǎn)上報(bào) GPU 總量,調(diào)度器在 Pod 綁定時(shí)一次扣除請(qǐng)求數(shù),之后按剩余數(shù)量決策能否分配。這種模式對(duì)同構(gòu) GPU、獨(dú)占整卡場(chǎng)景足夠簡(jiǎn)單,但一遇到 A100 40G 與 80G 混部的節(jié)點(diǎn)、或需要按顯存大小和 NVLink 拓?fù)溥x擇設(shè)備集的作業(yè),就只能靠節(jié)點(diǎn)選擇器手動(dòng)“對(duì)號(hào)入座”,自動(dòng)化程度幾乎為零,跨節(jié)點(diǎn)多卡申請(qǐng)也極易因資源碎片化而整體阻塞。
DRA 的核心改變?cè)谟诎选胺峙洹边@個(gè)動(dòng)作從調(diào)度時(shí)硬編碼的設(shè)備數(shù),變成 運(yùn)行時(shí)由資源控制器根據(jù)實(shí)時(shí)屬性動(dòng)態(tài)完成。工作流大致為:用戶創(chuàng)建 ResourceClaim,描述所需設(shè)備的屬性(如至少 30G 顯存、支持 NVLink、可用于共享),調(diào)度器不再只盯數(shù)量,而是結(jié)合集群內(nèi)實(shí)際可用的 GPU 屬性與狀態(tài),為 Pod 匹配最合適的設(shè)備集;綁定節(jié)點(diǎn)后,由設(shè)備驅(qū)動(dòng)初始化并掛載這些資源。這種時(shí)序和粒度的調(diào)整,讓 GPU 請(qǐng)求從“必須提前知道型號(hào)、數(shù)量、所在節(jié)點(diǎn)”進(jìn)化為“聲明需求、系統(tǒng)自動(dòng)適配”,從而大幅壓縮碎片化等待時(shí)間,也為后續(xù)更復(fù)雜的拓?fù)涓兄?、?dòng)態(tài)共享鋪平了道路。
截至 Kubernetes v1.29,DRA 仍為 Alpha 特性,需在 kube-apiserver 和 kubelet 上同時(shí)開啟 DynamicResourceAllocation 特性門控,調(diào)度器和資源控制器版本須嚴(yán)格對(duì)齊。雖然特性門控帶來一定的早期采用成本,但主流硬件廠商(如 NVIDIA)已發(fā)布兼容 DRA 的 GPU Operator,使生產(chǎn)集群可以保留原有的 Device Plugin 路徑,同時(shí)在需要細(xì)粒度控制的負(fù)載上啟用 DRA,形成兩條路徑并存的過渡策略。
2. 對(duì)比 Device Plugin
常見的顧慮是:上了 DRA 是不是就得拋棄 Device Plugin?事實(shí)正好相反。二者并不是互斥關(guān)系,而是分層協(xié)作——Device Plugin 依然是內(nèi)核驅(qū)動(dòng)與 Kubernetes 之間的基礎(chǔ)適配層,負(fù)責(zé)上報(bào)設(shè)備數(shù)量、健康狀態(tài);DRA 則疊加在它之上,相當(dāng)于增加了一層動(dòng)態(tài)調(diào)度和分配邏輯。
一個(gè)直觀的對(duì)比:傳統(tǒng)路徑下發(fā) nvidia.com/gpu: 2 時(shí),調(diào)度器只關(guān)心“節(jié)點(diǎn)上還有沒有 2 張完整的 GPU”,至于這兩張卡是哪張、顯存多少、是否直連 NVLink,統(tǒng)統(tǒng)不管。而 DRA 的 ResourceClaim 可以使用結(jié)構(gòu)化參數(shù)表達(dá)約束,比如:“請(qǐng)求兩張顯存≥40G、支持 NVLink 的 GPU,且允許使用已切分的 MIG 實(shí)例”。調(diào)度器會(huì)結(jié)合設(shè)備屬性做匹配,即便節(jié)點(diǎn)上只有部分滿足條件的卡,也不會(huì)直接判為調(diào)度失敗,而是可能等待部分資源被釋放或通過排隊(duì)機(jī)制順序滿足。
從數(shù)據(jù)上看,多數(shù)團(tuán)隊(duì)的 GPU 集群中,獨(dú)占整卡的訓(xùn)練作業(yè)依然占主流,此時(shí) Device Plugin 足夠成熟穩(wěn)定;而需要多任務(wù)共享一卡、動(dòng)態(tài)組合多卡拓?fù)洹⒒虿煌瑥S商 GPU 混部的場(chǎng)景,才真正體現(xiàn) DRA 的價(jià)值。因此實(shí)操上的最佳做法是:按場(chǎng)景分層使用。為標(biāo)準(zhǔn)的單卡訓(xùn)練保留 nvidia.com/gpu: 1 這類簡(jiǎn)單請(qǐng)求;對(duì)于推理服務(wù)共享、MIG 分區(qū)使用或跨卡 NVLink 指定的高級(jí)需求,才轉(zhuǎn)向 ResourceClaim。這樣既避免全局切換帶來的不穩(wěn)定,又能精準(zhǔn)地在合適的地方提高利用率。
3. ResourceClaim 是什么
ResourceClaim 是 DRA 引入的核心 API 對(duì)象,在命名空間內(nèi)代表一組請(qǐng)求的設(shè)備資源。它既可以被單個(gè) Pod 獨(dú)占,也可以被多個(gè) Pod 共享(共享模式下,由驅(qū)動(dòng)決定如何隔離上下文),從而在 Kubernetes 原生語義里實(shí)現(xiàn)了設(shè)備的“復(fù)用”。與過去必須將設(shè)備數(shù)量直接寫入 Pod spec 不同,ResourceClaim 可以在 Pod 部署前單獨(dú)創(chuàng)建、修改(處于未綁定狀態(tài)時(shí)),讓運(yùn)維或調(diào)度器有更多編排空間。
編寫 ResourceClaim 時(shí),一個(gè)關(guān)鍵建議是:盡量使用結(jié)構(gòu)化參數(shù),避免硬編碼節(jié)點(diǎn)名或設(shè)備 ID。例如:
spec: devices: requests: - name: gpu-req deviceClassName: gpu.nvidia.com allocationMode: All attributes: memoryGB: ">=40" nvlink: "true"
這段配置讓調(diào)度器去尋找滿足條件的所有設(shè)備,而不是指定“node-12 上的 GPU-0”,從而保留調(diào)度彈性。一旦 Claim 被 Pod 綁定,修改就會(huì)受限,通常需要 Pod 終止才能釋放。因此,引入 DRA 的團(tuán)隊(duì)必須配套碎片監(jiān)控(如 DCGM + Prometheus 持續(xù)追蹤已分配但閑置的設(shè)備)和回收策略,防止僵死的 ResourceClaim 造成資源泄漏。
需要糾正一個(gè)常見誤讀:DRA 本身并不提供 GPU 切分能力,它負(fù)責(zé)的是“發(fā)布”和“申請(qǐng)”這些細(xì)粒度資源。真正把一張 A100 拆成多個(gè)實(shí)例,靠的是 NVIDIA MIG 控制器等驅(qū)動(dòng)層工具,DRA 只是讓這些切好的實(shí)例能以統(tǒng)一的方式被調(diào)度和掛載。這也解釋了為什么 DRA 上線過程中,Device Plugin 依然不可或缺——內(nèi)核驅(qū)動(dòng)、設(shè)備發(fā)現(xiàn)這些地基活,仍然由它完成,而 DRA 帶來的是上層調(diào)度策略的升級(jí)。
三、環(huán)境準(zhǔn)備:開啟GPU動(dòng)態(tài)分配
在開始構(gòu)建動(dòng)態(tài)分配的調(diào)度鏈路之前,需要讓集群的底層組件承認(rèn)這樣一個(gè)事實(shí):GPU 不再只是一個(gè)靠“數(shù)量”來計(jì)算的靜態(tài)資源,而是帶有顯存、拓?fù)?、互?lián)方式等多維屬性的可描述設(shè)備。這一層的準(zhǔn)備工作,直接決定了 DRA 是跑在一個(gè)穩(wěn)健的地基上,還是懸浮在半空中的實(shí)驗(yàn)特性。
1. 集群與驅(qū)動(dòng)要求
最低門檻是 Kubernetes 1.27,但從社區(qū)反饋和 bug-fix 密度來看,1.29 才是第一個(gè)值得嚴(yán)肅對(duì)待 DRA 的版本——resource.k8s.io/v1alpha2 在 1.29 中已經(jīng)凍結(jié)了絕大部分字段,后續(xù)變動(dòng)將主要圍繞控制器的穩(wěn)定性和調(diào)度吞吐展開。因此,如果要在生產(chǎn)集群上嘗試,基線建議定在 1.29,且 control plane 與所有 GPU 節(jié)點(diǎn)的 kubelet 版本必須嚴(yán)格一致;混部不同小版本的 kubelet 會(huì)直接導(dǎo)致 ResourceClass 在節(jié)點(diǎn)上解析失敗,這是最容易踩到的第一個(gè)坑。
節(jié)點(diǎn)側(cè)需要提前安裝好 NVIDIA 驅(qū)動(dòng),版本至少 525.60.13,容器運(yùn)行時(shí)推薦使用 containerd 配合 nvidia-container-toolkit。這里一個(gè)容易被忽視的關(guān)鍵是,Driver 必須暴露可被 DRA 感知的資源接口,而不只是支持傳統(tǒng)的 Device Plugin 掛載。實(shí)際做法是啟用 NVIDIA GPU Operator 的 driver.enabled=true 和 kataManager 等模塊,并確認(rèn) ClusterPolicy 中 driver.rdma.enabled 等標(biāo)識(shí)已按需打開。效果驗(yàn)證很簡(jiǎn)單:登錄任一 GPU 節(jié)點(diǎn)執(zhí)行 nvidia-smi topo -m,確認(rèn) GPU 與 NUMA 親和、NVLink 連接狀態(tài)等信息可被正確讀取——這是 DRA 在后續(xù)調(diào)度中判斷“哪個(gè) GPU 更適合 Pod”的基礎(chǔ)數(shù)據(jù)。
如果集群中還混有不同廠商的加速器(例如某些節(jié)點(diǎn)插著 AMD Instinct 或 Intel Data Center GPU Max),則需要為每種設(shè)備安裝對(duì)應(yīng)的驅(qū)動(dòng)棧,并在后文構(gòu)建 ResourceDriver 時(shí)分別注冊(cè)。不過,本次實(shí)戰(zhàn)以 NVIDIA GPU 為主,跨廠商場(chǎng)景可以作為下一步演進(jìn)方向。
2. 啟用 DRA 特性門控
DRA 在 1.29 仍然掛在 Alpha 門控下,所以 kube-apiserver、kube-controller-manager、kube-scheduler 和 kubelet 必須同時(shí)傳入 --feature-gates=DynamicResourceAllocation=true。只改其中一兩個(gè)組件會(huì)導(dǎo)致 Pod 被調(diào)度后被卡在“等待資源聲明”的不可恢復(fù)狀態(tài)。這在多個(gè)社區(qū) issue 中被反復(fù)提及——因?yàn)?scheduler 以為資源已經(jīng)分配出去,但 kubelet 完全無視 ResourceClaim,最終 Pod 永遠(yuǎn)無法啟動(dòng)。
在 kubeadm 部署的集群中,修改方式如下(示例為 apiserver 配置片段):
apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration apiServer: extraArgs: feature-gates: "DynamicResourceAllocation=true" controllerManager: extraArgs: feature-gates: "DynamicResourceAllocation=true" scheduler: extraArgs: feature-gates: "DynamicResourceAllocation=true"
kubelet 則需要逐節(jié)點(diǎn)修改 /var/lib/kubelet/config.yaml 或等價(jià)配置文件,加入 featureGates: DynamicResourceAllocation: true,然后用 systemctl restart kubelet 使其生效。完成所有組件修改后,可以用 kubectl api-versions | grep resource 驗(yàn)證——如果看到 resource.k8s.io/v1alpha2,說明 DRA API 已經(jīng)就緒。
這里有一個(gè)典型的踩坑點(diǎn):僅僅啟用門控還不夠,必須確保調(diào)度器加載了 DRA 插件。如果采用的是自定義調(diào)度器(比如集成 Kueue 或 Volcano),需要在調(diào)度器配置的 plugins 列表中顯式啟用 DynamicResources。默認(rèn)的 kube-scheduler 在門控打開后會(huì)自動(dòng)加載該插件,但一旦脫離默認(rèn)部署,就需要手動(dòng)核對(duì) KubeSchedulerConfiguration 的配置文件。
啟用后的直觀效果是,你可以通過 kubectl get resourceclasses 看到系統(tǒng)內(nèi)置的 ResourceClass(如果已經(jīng)安裝了資源驅(qū)動(dòng)),而所有節(jié)點(diǎn)在 kubectl describe node 的 Capacity 中不再只是顯示 nvidia.com/gpu: 8,還會(huì)出現(xiàn)由結(jié)構(gòu)化參數(shù)描述的細(xì)粒度屬性——這一步標(biāo)志著集群已經(jīng)初步脫離“以卡為原子單位”的舊世界。
3. 安裝必要組件
門控打開只是拿到了入場(chǎng)券,核心的分配邏輯需要由 DRA 控制器和資源驅(qū)動(dòng)共同實(shí)現(xiàn)。目前最成熟的選擇是部署 NVIDIA GPU DRA driver,它與傳統(tǒng)的 GPU Operator 共享節(jié)點(diǎn)驅(qū)動(dòng),但在上層提供了一組面向 ResourceClaim 的 CRD。
部署過程大致如下:
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia helm install gpu-dra-driver nvidia/gpu-dra-driver \ --create-namespace -n gpu-dra-system
部署完成后,需要?jiǎng)?chuàng)建至少一個(gè) ResourceClass 來告訴調(diào)度器“我可以管理什么樣的 GPU”。例如,以下模板描述了一個(gè)請(qǐng)求任意共享 GPU 的 ResourceClass:
apiVersion: resource.k8s.io/v1alpha2 kind: ResourceClass metadata: name: shared-gpu.example.com driverName: gpu.resource.nvidia.com parametersRef: apiGroup: gpu.resource.nvidia.com kind: GpuConfig name: shared-config
其中 GpuConfig 可以指定顯存下限、NVLink 需求、時(shí)鐘頻率要求等結(jié)構(gòu)化參數(shù)。這里的一個(gè)關(guān)鍵判斷是——不要直接把節(jié)點(diǎn)名或 GPU UUID 寫死在 Claim 模板里,而是用屬性來描述需求,否則調(diào)度彈性會(huì)被削弱回傳統(tǒng)節(jié)點(diǎn)選擇器的水平,DRA 的靈活匹配優(yōu)勢(shì)就消失了。
安裝驗(yàn)證可以直接創(chuàng)建一個(gè)簡(jiǎn)單的測(cè)試 Claim,并用 kubectl describe resourceclaim 觀察其 Phase 從 Pending 變?yōu)?Allocated,說明整條鏈路已經(jīng)聯(lián)通。此時(shí)如果在一個(gè) GPU 節(jié)點(diǎn)上故意部署一個(gè)只請(qǐng)求 1GB 顯存的 Pod,通過 nvidia-smi 可以看到它并未獨(dú)占整張卡,而是與其他工作負(fù)載共享——這正是 DRA 區(qū)別于 Device Plugin 的直接體驗(yàn)變化。
需要提醒的是,在生產(chǎn)環(huán)境引入這套組件之前,最好先在隔離的 staging 集群上盲測(cè)一兩周,重點(diǎn)關(guān)注控制器內(nèi)存泄漏、大型 Claim 回收延遲以及組件版本升級(jí)時(shí) CRD 兼容性,畢竟 DRA 的 GC 和調(diào)度性能在 1.29 上仍然處在早期階段,不少企業(yè)的內(nèi)部 slack channel 里都能看到“半夜被 ResourceClaim 泄漏喚醒”的討論。
四、實(shí)戰(zhàn):配置GPU動(dòng)態(tài)分配
動(dòng)態(tài)資源分配(DRA)解決的是傳統(tǒng) nvidia.com/gpu: 1 分配模型中最頑固的痛點(diǎn):一旦請(qǐng)求,整張卡就被獨(dú)占,即使任務(wù)只用 10% 的算力,集群 GPU 利用率也很難突破 40% 的行業(yè)常態(tài)。DRA 將調(diào)度邏輯從“數(shù)卡”轉(zhuǎn)向“看屬性+看狀態(tài)”,讓 Pod 能夠在資源就緒后再綁定,而不是在調(diào)度那一刻就固化。下面我們從零開始走通一個(gè)基于 ResourceClaim 的 GPU 動(dòng)態(tài)分配全流程——請(qǐng)先確認(rèn)你的集群已通過 DynamicResourceAllocation 特性門控啟用該 Alpha 功能(Kubernetes v1.29 以上),且已安裝兼容 DRA 的 GPU 驅(qū)動(dòng)聲明,例如 NVIDIA GPU Operator 的對(duì)應(yīng)版本。
1. 創(chuàng)建 ResourceClaim:把 GPU 抽象為可臨時(shí)占用的聲明
第一步不是直接寫 Pod,而是定義一個(gè) ResourceClaim。這個(gè)對(duì)象類似“資源代金券”,指明你需要的設(shè)備屬性,而非指定某張物理卡。推薦使用結(jié)構(gòu)化參數(shù)聲明需求,比如要求至少 40GB 顯存、支持 NVLink,但不硬編碼節(jié)點(diǎn)名稱,以保留調(diào)度彈性。
下面是一個(gè)基礎(chǔ)示例,在 gpu-claim 命名空間下創(chuàng)建一個(gè)名為 nv-gpu-claim 的 ResourceClaim,請(qǐng)求一個(gè)來自 nvidia.com 驅(qū)動(dòng)、型號(hào)為 gpu 的設(shè)備:
apiVersion: resource.k8s.io/v1alpha2 kind: ResourceClaim metadata: name: nv-gpu-claim spec: allocationMode: Allocate resourceClassName: nvidia-gpu parameters: apiVersion: gpu.example.com/v1alpha1 kind: GPURequirements spec: minMemoryGB: 40 count: 1
這里的關(guān)鍵是 resourceClassName 所引用的 ResourceClass 需要事先由集群管理員配置,它指定了驅(qū)動(dòng)是誰、設(shè)備屬性如何匹配。提交后,DRA 控制器會(huì)在后臺(tái)為這個(gè)聲明尋找合適的 GPU,但此時(shí)不會(huì)立即分配,只是在資源池中鎖定一個(gè)符合條件的位置。操作完成后可用 kubectl get resourceclaims 看到聲明的狀態(tài)從 pending 變?yōu)?reserved,這表明未來被 Pod 引用時(shí),有對(duì)應(yīng)資源可以配給。
2. 在 Pod 中引用 ResourceClaim:讓調(diào)度與設(shè)備綁定解耦
有了 ResourceClaim,Pod 就不再直接寫 nvidia.com/gpu,而是通過 claims 字段引用聲明。正是這一步,讓調(diào)度器不再在評(píng)分階段就硬綁 GPU,而是等到 Pod 已經(jīng)選中節(jié)點(diǎn)后,再由資源控制器去完成設(shè)備的分配與初始化。
下面的 Pod 示例啟動(dòng)一個(gè)簡(jiǎn)單的 CUDA 測(cè)試容器,它將使用上一步創(chuàng)建的 nv-gpu-claim:
apiVersion: v1 kind: Pod metadata: name: gpu-test spec: containers: - name: cuda-container image: nvidia/cuda:12.1-base command: ["nvidia-smi"] resources: claims: - name: gpu resourceClaims: - name: gpu source: resourceClaimName: nv-gpu-claim
提交 Pod 后,你可以觀察調(diào)度過程的時(shí)序變化:調(diào)度器為 Pod 選擇節(jié)點(diǎn)時(shí),只要求節(jié)點(diǎn)上資源池有尚未被其他 Claim 占用的 GPU;綁定節(jié)點(diǎn)后,節(jié)點(diǎn)上的 DRA kubelet 插件才會(huì)執(zhí)行具體的 GPU 分配。也就是說,即使集群中有碎片化空閑 GPU,只要它們能夠組合滿足 ResourceClaim 的要求,Pod 就能成功啟動(dòng)——這正是 DRA 區(qū)別于靜態(tài)計(jì)數(shù)的核心價(jià)值。
3. 驗(yàn)證動(dòng)態(tài)分配:看日志、查節(jié)點(diǎn)、理解“使用時(shí)才分配”
Pod 啟動(dòng)后,執(zhí)行 kubectl logs gpu-test 應(yīng)能看到 nvidia-smi 輸出的 GPU 信息,同時(shí)如果所申請(qǐng)的設(shè)備支持共享模式(例如預(yù)先用 NVIDIA MIG 劃好的 10GB 小實(shí)例),你可能會(huì)發(fā)現(xiàn)容器只看到被分配的那一份算力,而非整張卡。這驗(yàn)證了 DRA 并未簡(jiǎn)單傳回一個(gè)“我占了一張卡”的符號(hào),而是真正向容器注入了那一部分設(shè)備。
更深入的驗(yàn)證可以在節(jié)點(diǎn)的 kubelet 日志中觀察到類似 "Staging resource for claim" 的記錄,表明資源在 Pod 啟動(dòng)時(shí)才被“實(shí)例化”。另外,通過 DCGM + Prometheus 監(jiān)控這類節(jié)點(diǎn),能看到已分配但未被活躍使用的 GPU 區(qū)塊,這種透明性對(duì)后續(xù)的碎片回收至關(guān)重要。若此時(shí)刪除 Pod,ResourceClaim 會(huì)自動(dòng)釋放,資源回歸池中;如果重復(fù)申請(qǐng),其他 Pod 可復(fù)用同一塊資源。
需要指出,DRA 并不能原生將一張 A100 隨意切成 MIG 實(shí)例,實(shí)際的 GPU 劃分仍需管理員預(yù)先配置 MIG 控制器,DRA 只是負(fù)責(zé)把這些“定制好的資源包”按單分配給合適的 Pod,所以切勿期待 ResourceClaim 會(huì)替你完成驅(qū)動(dòng)層面的劃分。對(duì)于簡(jiǎn)單的整卡獨(dú)占任務(wù),Device Plugin 路徑仍是更穩(wěn)的選擇——直到 DRA 在后續(xù)版本完成 Beta 甚至 GA 演進(jìn)。
五、生產(chǎn)優(yōu)化與問題排查
把 DRA 從概念驗(yàn)證推進(jìn)到生產(chǎn)環(huán)境,最終還是要落到兩個(gè)問題上:能不能讓 GPU 不被浪費(fèi),以及出了問題能不能快速定位。下面這三個(gè)環(huán)節(jié),是多數(shù)團(tuán)隊(duì)從“能跑起來”到“跑得穩(wěn)”的必經(jīng)之路。
1. 避免資源碎片
傳統(tǒng)整卡分配帶來的碎片是靜默但致命的——一個(gè) Pod 哪怕只用 8?GB 顯存,也會(huì)占滿一張 80?GB 的 A100,導(dǎo)致集群層面 GPU 利用率普遍低于 40%。DRA 的改進(jìn)不在于它能切割 GPU,而在于它讓調(diào)度器可以感知“部分”資源,并通過 ResourceClaim 描述真實(shí)需求而非簡(jiǎn)單計(jì)數(shù)。
在調(diào)度側(cè),要避免碎片需要抓住兩個(gè)要點(diǎn):結(jié)構(gòu)化參數(shù)一定不要退化成節(jié)點(diǎn)名。在 ResourceClaim 模板里盡量使用 attributes 描述所需顯存、拓?fù)溆?、NVLink 需求,而不是通過 nodename 強(qiáng)行綁定。這樣調(diào)度器才能在節(jié)點(diǎn)池里根據(jù)實(shí)際剩余資源動(dòng)態(tài)匹配,而不是硬裝進(jìn)去就完事了。例如:
spec: devices: requests: - name: gpu deviceClassName: nvidia-gpu allocationMode: ExactCount count: 1 adminAccess: false constraints: - requests: - gpu matchAttribute: "nvidia.com/gpu.memory" matchExpression: ">= 32Gi"
這樣寫的是“我需要至少 32?GB 顯存的 GPU”,而不是“我要 node-13 那個(gè) 80G 的卡”。實(shí)際效果上,碎片從靜態(tài)“算數(shù)量”變成了動(dòng)態(tài)“看庫存”,結(jié)合 Kueue 排隊(duì)后,中等負(fù)載任務(wù)可以自動(dòng)填補(bǔ)大作業(yè)留下的間隙,整集群碎片率能從約 35% 壓到 15% 以內(nèi)。
另一層避免碎片的關(guān)鍵在回收機(jī)制。被終止或僵尸的 Pod 有可能殘留已綁定的 ResourceClaim,如果不主動(dòng)清理,它們占用的 GPU 既不能被調(diào)度,也不會(huì)出現(xiàn)在空閑列表里。建議部署一個(gè)清理控制器(例如簡(jiǎn)單的 CronJob),定期檢查 status.deallocationRequested 為 true 但仍有設(shè)備引用的 Claim,強(qiáng)制釋放。配合 Kubernetes 原生的 TTLController 清理已完成 Job 所屬的資源,可以顯著減少半永久性的資源泄漏。
2. GPU 使用監(jiān)控
DRA 引入后,監(jiān)控視角必須從“節(jié)點(diǎn)上有幾張卡在工作”下鉆到“每個(gè) ResourceClaim 實(shí)際用了多少顯存和計(jì)算”。否則你會(huì)看到 GPU 并未空閑,但實(shí)際負(fù)載幾乎為零的尷尬局面。
目前行業(yè)里比較標(biāo)準(zhǔn)的方案是用 DCGM Exporter + Prometheus + Grafana 打底,然后添加 DRA 特定的告警規(guī)則。需要關(guān)注三個(gè)核心指標(biāo):
DCGM_FI_DEV_MEM_COPY_UTIL和DCGM_FI_DEV_GPU_UTIL:底層 GPU 的實(shí)際算力與顯存帶寬使用率。如果這兩個(gè)值持續(xù)低于 10%,同時(shí) Pod 狀態(tài)為 Running,基本可以判定是資源申請(qǐng)過多。kubelet_resource_claim_status:由自定義指標(biāo)導(dǎo)出器從 kube-apiserver 拉取,用于標(biāo)記 Claim 是否綁定、分配到哪個(gè)節(jié)點(diǎn)、申請(qǐng)的設(shè)備型號(hào)。把節(jié)點(diǎn)維度的 GPU 總量減去已綁定的 Claim 數(shù)量得到的差值,才是真正的可調(diào)度余量。kube_pod_resource_claim_info:關(guān)聯(lián) Pod 與 Claim 的關(guān)系。當(dāng)出現(xiàn) Pod 已消失但 Claim 仍為allocated狀態(tài)時(shí),自動(dòng)觸發(fā)告警并上報(bào)到清理隊(duì)列。
建議為每個(gè) GPU 節(jié)點(diǎn)部署 nvidia_gpu_exporter 的 sidecar,將 Claim 維度的顯存占用直接打標(biāo)成項(xiàng)目標(biāo)簽(例如 team=ml-training),而不是只展示 GPU 序號(hào)。這樣當(dāng)在凌晨收到 GPU 利用率告警時(shí),可以直接定位是哪個(gè)業(yè)務(wù)的 Pod 占著卡不干活,不用再從一堆 Pod IP 里排查。
3. 常見錯(cuò)誤處理
生產(chǎn)里踩坑最多的幾種情況,本質(zhì)上都是因?yàn)?DRA 的 alpha 特性與現(xiàn)有組件之間的預(yù)期不一致。
錯(cuò)誤一:ResourceClaim 一直處于 Pending,調(diào)度器日志報(bào)“no driver registered”
原因幾乎肯定是 kube-apiserver 開啟了 DynamicResourceAllocation 門控,但 kubelet 沒有同步開啟,或者節(jié)點(diǎn)上的 DRA driver(如 NVIDIA GPU DRA driver)未安裝或版本不匹配。解決方法:檢查所有節(jié)點(diǎn)的 kubelet 啟動(dòng)參數(shù),確保 --feature-gates=DynamicResourceAllocation=true;同時(shí)確認(rèn) GPU operator 版本支持當(dāng)前 Kubernetes 版本,1.29 以下的 DRA 驅(qū)動(dòng)與 1.29 以上不兼容??梢栽谌我夤?jié)點(diǎn)執(zhí)行 kubectl get resourceclasses 確認(rèn)驅(qū)動(dòng)程序是否已注冊(cè),如果為空則驅(qū)動(dòng)未上線。
錯(cuò)誤二:Pod 調(diào)度成功,但啟動(dòng)時(shí)卡在 ContainerCreating,kubelet 報(bào)“failed to prepare resource”
多數(shù)是因?yàn)?ResourceClaim 里的設(shè)備屬性描述與實(shí)際節(jié)點(diǎn)可提供的資源不匹配。比如申請(qǐng)了 nvidia.com/gpu.memory >= 40Gi,但目標(biāo)節(jié)點(diǎn)上的 A100 只有 40?GB 可分配部分已被 MIG 切割,剩余顯存不足。解決辦法:在 Claim 中不要只依賴單一屬性,可以加上備選條件,比如允許小顯存回退的規(guī)則,或者確保 MIG 分區(qū)計(jì)劃與拓?fù)浼s束已提前在驅(qū)動(dòng)層配置好。檢查 kubectl describe resourceclaim 中的 status.conditions 會(huì)有詳細(xì)錯(cuò)誤信息。
錯(cuò)誤三:多 Pod 共享同一 ResourceClaim 時(shí),第二個(gè) Pod 無法啟動(dòng),提示“claim in use”
DRA 允許共享 Claim,但要求 Claim 的 sharePolicy 必須顯式設(shè)置為 Shared,且驅(qū)動(dòng)支持共享。默認(rèn)創(chuàng)建的是獨(dú)占模式。解決辦法:在 Claim 的 spec 中添加 sharePolicy: Shared,但要清楚 NVIDIA GPU 驅(qū)動(dòng)層面只有特定場(chǎng)景(如使用時(shí)分復(fù)用或 MPS)才能真正安全共享算力,否則多個(gè)容器并行訪問同一張卡會(huì)導(dǎo)致 CUDA 上下文沖突。更穩(wěn)妥的做法是為共享任務(wù)專門創(chuàng)建顯存受限的 MIG 分區(qū),每個(gè)容器各綁到一個(gè)分區(qū)。
排查這類問題的通用思路是沿著 Pod → ResourceClaim → ResourceClass → Driver 這條鏈路一層層檢查 conditions,而不是只看 Pod 的 events。DRA 把資源分配的復(fù)雜狀態(tài)回寫到了 Claim 對(duì)象里,kubectl get resourceclaim -o yaml 往往比 describe pod 更能揭示根本原因。
六、未來方向:通用GPU調(diào)度
動(dòng)態(tài)資源分配(DRA)在 Kubernetes 1.29 中仍以 Alpha 特性門控存在,但我們已經(jīng)能從控制面與生態(tài)快速迭代中看到一個(gè)清晰的方向:從“設(shè)備計(jì)數(shù)”演進(jìn)為“屬性感知+動(dòng)態(tài)拓?fù)洹钡耐ㄓ?GPU 調(diào)度層。這一層不再只是把 GPU 當(dāng)作可枚舉的整卡資源,而是將顯存、NVLink 拓?fù)?、MIG 實(shí)例甚至功耗墻都納入調(diào)度決策,真正把 GPU 集群從“硬件池”變成面向混合負(fù)載的算力工廠。想要抵達(dá)這個(gè)目標(biāo),下面三個(gè)技術(shù)路徑正在彼此疊加,構(gòu)成未來一兩年內(nèi)的落地骨架。
1. Kueue 批調(diào)度與 DRA 的職責(zé)解耦
當(dāng)前不少團(tuán)隊(duì)把 GPU 閑置率高的鍋單純甩給調(diào)度器,實(shí)際是兩個(gè)問題絞在了一起:作業(yè)排隊(duì)時(shí)的公平性、以及資源分配時(shí)的靈活性。DRA 解決的是后者——讓 Pod 可以根據(jù)設(shè)備屬性動(dòng)態(tài)匹配物理 GPU,而批調(diào)度組件(特別是 Kueue)負(fù)責(zé)在前置隊(duì)列層面決定誰先跑、能跑幾個(gè)副本、如何防止餓死。
在社區(qū)已經(jīng)驗(yàn)證的實(shí)踐中,這套組合的典型數(shù)據(jù)是:在 64 張 A100 的集群上運(yùn)行混合訓(xùn)練與推理負(fù)載,單純開啟 DRA 可以讓碎片利用率從 32% 提升到 58%,但出現(xiàn)明顯的隊(duì)頭阻塞,部分高優(yōu)先作業(yè)等待時(shí)間超過 40 分鐘。接入 Kueue 并配置 Cohort 隊(duì)列和公平共享規(guī)則后,平均排隊(duì)延遲壓到 9 分鐘以內(nèi),GPU 整體分配率(含實(shí)際使用)穩(wěn)定在 68%。這個(gè)案例說明,DRA 本身并不能理解作業(yè)的優(yōu)先級(jí)與資源預(yù)留需求,它只是一個(gè)強(qiáng)大的“分配執(zhí)行器”。Kueue 這樣的批調(diào)度框架承擔(dān)準(zhǔn)入控制、配額管理和跨命名空間公平性,才能真正把動(dòng)態(tài)資源從“能分”變成“分得好”。
未來半年內(nèi),預(yù)計(jì) Kueue 社區(qū)會(huì)增強(qiáng)對(duì) ResourceClaim 生命周期感知,比如在 Flavor 中指定 ResourceClaim 模板,并在作業(yè)掛起時(shí)預(yù)先“軟鎖定”一組資源但不實(shí)際分配,等到所有切片的 GPU 都可獲得時(shí)才一次綁定。這種分階段預(yù)留的能力,將進(jìn)一步減少因部分 GPU 就緒導(dǎo)致的大規(guī)模訓(xùn)練作業(yè)反復(fù)失敗重啟。
2. 多租戶共享的粒度與安全邊界
多租戶共享 GPU 的呼聲很高,但落地中常見的問題不是技術(shù)做不到,而是租戶間隔離不夠徹底。DRA 為共享帶來了新的可能:ResourceClaim 可以指定為“Shared”模式,允許多個(gè) Pod 在同一張 GPU 上分配不同的顯存段或時(shí)間片。然而,直接使用 DRA 實(shí)現(xiàn)共享會(huì)踩到一個(gè)坑——內(nèi)核驅(qū)動(dòng)和 CUDA 上下文并沒有因此被完全隔離,一旦某個(gè)租戶出現(xiàn)顯存泄漏或內(nèi)核崩潰,仍然可能波及其他租戶。
現(xiàn)階段可行的方案是將 DRA 與 NVIDIA MIG 控制器結(jié)合,由 MIG 完成硬件級(jí)隔離,由 DRA 暴露這些 MIG 實(shí)例為獨(dú)立的 ResourceClaim。這樣做可以做到顯存與緩存的嚴(yán)格分區(qū),甚至不同租戶跑不同的 CUDA 版本。實(shí)際數(shù)據(jù):某云廠商在內(nèi)部實(shí)驗(yàn)集群里,將一張 A100-80G 通過 MIG 切成 3g.20gb 實(shí)例 4 個(gè),利用 DRA 按租戶配額下發(fā) ResourceClaim,實(shí)現(xiàn)了 4 個(gè)互相隔離的推理服務(wù)共享一張卡,相比單純的 MPS 共享,延遲抖動(dòng)從 12% 降低到 2% 以內(nèi)。
而真正的“細(xì)粒度共享”還需要應(yīng)用層配合。業(yè)內(nèi)正在探索通過 Coordinated Admission 讓應(yīng)用程序顯式聲明所需的最小顯存與彈性算力,比如一個(gè)推理任務(wù)聲明“至少 5GB 顯存,愿意接受算力被壓縮到 30%”,調(diào)度器結(jié)合 DRA 的動(dòng)態(tài)屬性可以將其塞入剩余碎片中,同時(shí)配合 GPU Operator 動(dòng)態(tài)調(diào)節(jié)算力上限。這條路仍需驅(qū)動(dòng)層和調(diào)度層之間更強(qiáng)的協(xié)同,但方向已經(jīng)明確。
3. 動(dòng)態(tài) MIG 重配置:從靜態(tài)切分到彈性重構(gòu)
當(dāng)前 MIG(多實(shí)例 GPU)的最大短板是重配置需要清空整張 GPU,這在線上的代價(jià)非常高。而動(dòng)態(tài) MIG 技術(shù)試圖實(shí)現(xiàn)不中斷服務(wù)的實(shí)例重劃分,這正是 DRA 能真正釋放威力的場(chǎng)景。設(shè)想這樣一種調(diào)度:高峰時(shí),集群自動(dòng)將多張空閑的 A100 從 1g.5gb 切為 2g.10gb,交付給緊急的微調(diào)任務(wù);低峰時(shí)再聚合回細(xì)粒度 MIG 實(shí)例,供大量小推理任務(wù)共享。
在 NVIDIA 的路線圖中,動(dòng)態(tài) MIG 重構(gòu)依賴 GPU 系統(tǒng)處理器(GSP)與新的驅(qū)動(dòng)架構(gòu),預(yù)計(jì)在 Hopper 架構(gòu)后續(xù)通過固件更新和驅(qū)動(dòng)支持逐步成熟。Kubernetes 側(cè),DRA 的結(jié)構(gòu)化參數(shù)正好可以表示這種可變拓?fù)洹恍枰孪仍诠?jié)點(diǎn)上寫好 MIG 配置,而是由 DRA 控制器在分配瞬間根據(jù) ResourceClaim 里的需求去調(diào) MIG 分區(qū)。這本質(zhì)上把“選設(shè)備”變成了“塑造設(shè)備”。
不過必須保持冷靜:動(dòng)態(tài) MIG 目前還有諸多限制,例如重配置的時(shí)延在秒級(jí)到分鐘級(jí)不等,對(duì)正在運(yùn)行的負(fù)載需要快照或遷移支持。行業(yè)里已經(jīng)有實(shí)驗(yàn)性方案通過結(jié)合 DRA 和 KubeVirt 的虛擬機(jī) GPU 透?jìng)鲗?shí)現(xiàn)準(zhǔn)實(shí)時(shí)重配置,但生產(chǎn)就緒程度很低。未來一到兩年,更可能的路徑是夜間窗口或低峰定時(shí)執(zhí)行重配置,由 Kueue 的 CronJob 風(fēng)格任務(wù)觸發(fā),再配合 DRA 更新 ResourceClass,實(shí)現(xiàn)準(zhǔn)靜態(tài)的彈性重構(gòu),而不是真正的實(shí)時(shí)在線變更。
常見問題 FAQ
Q:DRA 能解決我集群里的 GPU 碎片化問題嗎?
A:能部分解決。DRA 可以按屬性分配不同的 GPU,避免因?yàn)椤爸灰粡埧ǖ麄€(gè)節(jié)點(diǎn)被鎖死”的情況。但徹底消除碎片仍需批調(diào)度(如 Kueue)配合隊(duì)列重排序,以及任務(wù)本身的彈性伸縮能力。沒有應(yīng)用層的配合,單靠調(diào)度層做不到零碎片。
Q:我們現(xiàn)在用的 Device Plugin 方案,有必要遷移到 DRA 嗎?
A:短期不必須。Device Plugin 對(duì)于整卡獨(dú)占場(chǎng)景成熟穩(wěn)定,性能開銷極小。DRA 適合需要 GPU 共享、跨廠商設(shè)備、復(fù)雜拓?fù)浠騽?dòng)態(tài)切分的場(chǎng)景。建議先在非核心業(yè)務(wù)上并行運(yùn)行,積累運(yùn)維經(jīng)驗(yàn),等社區(qū)達(dá)到 Beta 且有更多生產(chǎn)案例后再?zèng)Q定全量遷移。
Q:開啟 DRA 后,我怎么知道哪些 ResourceClaim 沒有被使用而可以回收?
A:通過 kubectl get resourceclaims -o json 查看 status 字段,判斷是否被 Pod 引用。推薦部署一個(gè)集群級(jí)監(jiān)控,比如用 DCGM 結(jié)合 Prometheus 指標(biāo)顯示實(shí)際 GPU 利用率,結(jié)合 Claim 分配記錄就可以發(fā)現(xiàn)“已分配但利用率持續(xù)為零”的情況,再用簡(jiǎn)單的清理控制器定期回收這些死 Claim。需注意,強(qiáng)行刪除已綁定的 Claim 會(huì)導(dǎo)致 Pod 異常,必須確認(rèn) Pod 已終止。
Q:動(dòng)態(tài) MIG 現(xiàn)在能用嗎?
A:不推薦直接用于生產(chǎn)。動(dòng)態(tài) MIG 需要特定的 GPU 型號(hào)和驅(qū)動(dòng)版本,且在 Kubernetes 側(cè)尚無標(biāo)準(zhǔn)的控制器能可靠地協(xié)調(diào)重配置與調(diào)度?,F(xiàn)階段最好把 MIG 分區(qū)當(dāng)作靜態(tài)配置,通過 DRA 暴露這些靜態(tài)分區(qū)來實(shí)現(xiàn)多租戶共享,等 NVIDIA 和 K8s 社區(qū)共同推動(dòng)的重配置協(xié)議成熟后再評(píng)估。
標(biāo)簽
熱門文章更多>
- 深圳阿里云代理商:ECS部署SSL證書與到期提醒配置全攻略
- 上海阿里云代理商:阿里云服務(wù)器SSL證書備份方案
- 北京阿里云代理商:RDS讀寫分離配置指南
- 重慶阿里云代理商:用好 OSS 生命周期 降低長(zhǎng)期存儲(chǔ)花費(fèi)
- 上海阿里云代理商:DMS 多庫同步搭建 異構(gòu)數(shù)據(jù)庫集成實(shí)操
- 上海阿里云代理商:阿里云SLB健康檢查異常排查:端口、網(wǎng)絡(luò)、應(yīng)用狀態(tài)一步到位
- 重慶阿里云代理商:阿里云Redis延遲突然升高?慢查詢大Key連接數(shù)排查指南
- 廣州阿里云代理商:阿里云ACK Pod Pending?三步排查與節(jié)點(diǎn)擴(kuò)容實(shí)戰(zhàn)
- 深圳阿里云代理商:阿里云ECS降本增效方法:實(shí)例、帶寬、云盤省錢全攻略
- 上海阿里云代理商:阿里云函數(shù)計(jì)算冷啟動(dòng)優(yōu)化
- 廣州阿里云代理商:阿里云ECS防CC攻擊安全加固配置教程
- 深圳阿里云代理商:阿里云Linux接口慢全鏈路排查指南
- 上海阿里云代理商:阿里云ECS CPU滿載診斷修復(fù)全指南
- 重慶阿里云代理商:阿里云ECS規(guī)格選型與彈性伸縮降本實(shí)戰(zhàn)指南
- 深圳阿里云代理商:阿里云STAROps自動(dòng)巡檢告警配置指南
- 深圳阿里云代理商:云服務(wù)器AI運(yùn)維權(quán)限管控策略,如何規(guī)避誤操作風(fēng)險(xiǎn)?
- 上海阿里云代理商:后端開發(fā)者私有AI大模型云端部署完整流程指南
- 北京阿里云代理商:AI日志分析工具,快速定位服務(wù)器異常宕機(jī)實(shí)戰(zhàn)指南
- 重慶阿里云代理商:AI腳本自動(dòng)化完成云服務(wù)器批量運(yùn)維配置實(shí)戰(zhàn)指南
- 廣州阿里云代理商:大模型推理部署,服務(wù)器內(nèi)存調(diào)優(yōu)實(shí)操全攻略

