前陣子 Dynamic Resource Allocation (DRA) 終於在 Kubernetes v1.35 進入 GA,相信不少人想要躍躍欲試,加上 NVIDIA 也把 dra-driver-nvidia-gpu 送進到 Kubernetes SIGs 當中,原有文件把 Beta 字眼拿掉,象徵技術和標準逐漸成熟。
這次我借了 CNTUG Infra Labs 目前所有的 NVIDIA GPU,來學習如何用 DRA 優雅的分配設備和資源。
友情工商:CNTUG Infra Labs#
CNTUG Infra Labs 成立的宗旨是為了培育台灣軟體基礎設施領域的未來學生和工程師。目前已在 Equinix 東京機房成功建立完善的環境,得到了 CNTUG 社群多位成員的共同出資支持。此建置過程中運用了大量開源專案,例如 OpenStack、Ceph 和 Ansible 等。
由於基礎設施相關軟體具有較高的上手難度,並需要足夠的運算、儲存和網路資源,因此 CNTUG Infra Labs 計劃提供一個雲端平台供學生和社群成員測試及架設相關服務。我們期望這將吸引更多學生參與,並在軟體基礎設施領域不斷精進。同時,剩餘資源將提供給開源社群,供他們架設所需服務(如網站、Mattermost 和 Jitsi Meet 等),或用於工作坊活動。
目前已經有許多使用者利用此平台積極開源貢獻,詳情可以翻閱使用案例。
接下來,回到我們的實驗環境介紹。
實驗環境介紹#
這次會使用 Cluster API + OpenStack 建構的 Kubernetes cluster,篇幅關係此環境安裝過程會省略,想要詳細介紹可以看其他人 blog,或等我整理完步驟。
- OS: Ubuntu 24.04
- Kubernetes v1.35.3
- Containerd 2.2.2
- Node:
- 1 Control Plane + etcd
- 3 Workers
- No GPU
- T10 * 2
- A5000 * 1
- NVIDIA GPU Operator v26.3.1
- NVIDIA DRA Driver GPU v25.12.0
用 kubectl get node 看完會有以下資訊:
NAME STATUS ROLES AGE VERSION
capi-dralabs-control-plane-xtcth Ready control-plane 8m7s v1.35.3
capi-dralabs-md-0-p4xkh-rpfxc Ready <none> 6m55s v1.35.3
capi-dralabs-md-gpua5000-jw4mx-d64jz Ready <none> 2m37s v1.35.3
capi-dralabs-md-gput10-gzl84-f2m2d Ready <none> 6m49s v1.35.3安裝 NVIDIA GPU Operator#
開始安裝 GPU Operator 前,要先幫有 GPU 的 Node 加上標籤,以我的環境來說就會像這樣:
kubectl label node capi-dralabs-md-gpua5000-jw4mx-d64jz nvidia.com/dra-kubelet-plugin=true
kubectl label node capi-dralabs-md-gput10-gzl84-f2m2d nvidia.com/dra-kubelet-plugin=true加入 NVIDIA 的 Chart Repo:
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update建立 values-gpu-operator.yaml 檔案,等等安裝會使用:
1# version: v26.3.1
2devicePlugin:
3 enabled: false
4
5driver:
6 manager:
7 env:
8 - name: NODE_LABEL_FOR_GPU_POD_EVICTION
9 value: "nvidia.com/dra-kubelet-plugin"如果 Kubernetes 是使用其他發行版 (e.g. Rancher 或 K3s) ,可能會因為 Containerd 預設安裝位置不一樣,記得加入以下設定到 values-gpu-operator.yaml 中:
1toolkit:
2 env:
3 - name: CONTAINERD_SOCKET
4 value: /run/k3s/containerd/containerd.sock安裝 NVIDIA GPU Operator:
helm upgrade --install gpu-operator nvidia/gpu-operator \
--version=v26.3.1 \
--create-namespace \
--namespace gpu-operator -f values-gpu-operator.yaml接下來就等待 GPU Operator 啟動完成,它會安裝好 NVIDIA GPU Driver 和修改 Container Runtime 設定,如果有需要個別調整設定需求,請詳閱 NVIDIA 官方文件。
安裝 NVIDIA DRA Driver GPU#
建立 values-nvidia-dra-driver-gpu.yaml 檔案,等等安裝會使用:
1# version: 25.12.0
2nvidiaDriverRoot: /run/nvidia/driver
3gpuResourcesEnabledOverride: true
4image:
5 pullPolicy: IfNotPresent
6kubeletPlugin:
7 nodeSelector:
8 nvidia.com/dra-kubelet-plugin: "true"
9resources:
10 gpus:
11 enabled: true
12 computeDomains:
13 enabled: false # No NVLink here
14# featureGates:
15# TimeSlicingSettings: true如果想要嘗試後面情境 IV 的 GPU Time Slicing,可以一併開啟 TimeSlicingSettings 這個 Feature Gate;如果暫時不需要也可以保留註解,之後再 helm upgrade 補上。
安裝 NVIDIA DRA Driver GPU:
helm upgrade -i nvidia-dra-driver-gpu nvidia/nvidia-dra-driver-gpu \
--version="25.12.0" \
--namespace nvidia-dra-driver-gpu \
--create-namespace -f values-nvidia-dra-driver-gpu.yaml用 kubectl get pod 確認一下安裝的 NVIDIA DRA Driver GPU 是否都上線:
kubectl get pod -n nvidia-dra-driver-gpuNAME READY STATUS RESTARTS AGE
nvidia-dra-driver-gpu-kubelet-plugin-6skhp 1/1 Running 0 10m
nvidia-dra-driver-gpu-kubelet-plugin-jswk6 1/1 Running 0 10m初探 DRA#
DeviceClass#
安裝完成後,就會看到 DeviceClass 和 ResourceSlice 已經由 NVIDIA DRA Driver GPU 設定,DeviceClass 顧名思義就是設備種類,打開就會看到裡面有一般 GPU、MIG 和 VFIO。(如果 ComputeDomains 沒關掉,也會看到 ComputeDomains 資訊。)
kubectl get deviceclassNAME AGE
gpu.nvidia.com 44m
mig.nvidia.com 44m
vfio.gpu.nvidia.com 44mResourceSlice#
ResourceSlice 由各個節點上的 DRA driver 自動更新,記錄該 driver 在這個節點上管理的所有裝置。
同節點同 driver 的裝置會在同一個 Pool,當裝置數量過多(上限 128 個,有 taint 或使用 counter 會降為 64 個)無法塞進同個物件時,driver 會把 Pool 拆成多個 ResourceSlice。
.spec.pool.generation 和 .spec.pool.resourceSliceCount 讓 scheduler 判斷是不是拿到該節點完整的最新裝置列表。
kubectl get resourcesliceNAME NODE DRIVER POOL AGE
capi-dralabs-md-gpua5000-jw4mx-d64jz-gpu.nvidia.com-w9fnv capi-dralabs-md-gpua5000-jw4mx-d64jz gpu.nvidia.com capi-dralabs-md-gpua5000-jw4mx-d64jz 5m13s
capi-dralabs-md-gput10-gzl84-f2m2d-gpu.nvidia.com-dtgtc capi-dralabs-md-gput10-gzl84-f2m2d gpu.nvidia.com capi-dralabs-md-gput10-gzl84-f2m2d 23m可以用 -o yaml 展開完整的內容:
kubectl get resourceslices -o yaml完整內容可以點擊下方展開,每個 ResourceSlice 會在 .metadata.ownerReferences 寫上節點、.spec.devices 紀錄裝置,每個裝置都會有 .attributes,包括但不限於架構、型號、裝置版本等。
由於本次實驗環境每個節點最多只有 2 張顯卡,遠低於單一 ResourceSlice 的 128 個上限,因此每個節點都只會看到一個 ResourceSlice。
ResourceSlice 完整輸出結果
1apiVersion: v1
2items:
3- apiVersion: resource.k8s.io/v1
4 kind: ResourceSlice
5 metadata:
6 creationTimestamp: "2026-05-04T14:40:17Z"
7 generateName: capi-dralabs-md-gpua5000-jw4mx-d64jz-gpu.nvidia.com-
8 generation: 1
9 name: capi-dralabs-md-gpua5000-jw4mx-d64jz-gpu.nvidia.com-w9fnv
10 ownerReferences:
11 - apiVersion: v1
12 controller: true
13 kind: Node
14 name: capi-dralabs-md-gpua5000-jw4mx-d64jz
15 uid: 83aafab6-7eb3-42d0-9faf-6118f78341ef
16 resourceVersion: "11490"
17 uid: d03fd27e-f6cb-4386-ae61-80aa84309e77
18 spec:
19 devices:
20 - attributes:
21 addressingMode:
22 string: HMM
23 architecture:
24 string: Ampere
25 brand:
26 string: NvidiaRTX
27 cudaComputeCapability:
28 version: 8.6.0
29 cudaDriverVersion:
30 version: 13.0.0
31 driverVersion:
32 version: 580.126.20
33 productName:
34 string: NVIDIA RTX A5000
35 resource.kubernetes.io/pciBusID:
36 string: "0000:00:06.0"
37 resource.kubernetes.io/pcieRoot:
38 string: pci0000:00
39 type:
40 string: gpu
41 uuid:
42 string: GPU-e13ce856-7474-797f-d143-16e99b65c0c3
43 capacity:
44 memory:
45 value: 23028Mi
46 name: gpu-0
47 driver: gpu.nvidia.com
48 nodeName: capi-dralabs-md-gpua5000-jw4mx-d64jz
49 pool:
50 generation: 1
51 name: capi-dralabs-md-gpua5000-jw4mx-d64jz
52 resourceSliceCount: 1
53- apiVersion: resource.k8s.io/v1
54 kind: ResourceSlice
55 metadata:
56 creationTimestamp: "2026-05-04T14:21:53Z"
57 generateName: capi-dralabs-md-gput10-gzl84-f2m2d-gpu.nvidia.com-
58 generation: 1
59 name: capi-dralabs-md-gput10-gzl84-f2m2d-gpu.nvidia.com-dtgtc
60 ownerReferences:
61 - apiVersion: v1
62 controller: true
63 kind: Node
64 name: capi-dralabs-md-gput10-gzl84-f2m2d
65 uid: d7ecdc93-1d6c-4868-8503-4251bcf8cf3b
66 resourceVersion: "7408"
67 uid: 66f32713-c547-4369-84de-97f86430d18d
68 spec:
69 devices:
70 - attributes:
71 addressingMode:
72 string: HMM
73 architecture:
74 string: Turing
75 brand:
76 string: Nvidia
77 cudaComputeCapability:
78 version: 7.5.0
79 cudaDriverVersion:
80 version: 13.0.0
81 driverVersion:
82 version: 580.126.20
83 productName:
84 string: Tesla T10
85 resource.kubernetes.io/pciBusID:
86 string: "0000:00:06.0"
87 resource.kubernetes.io/pcieRoot:
88 string: pci0000:00
89 type:
90 string: gpu
91 uuid:
92 string: GPU-dae084a2-974c-00e2-6dec-4ba1999b8652
93 capacity:
94 memory:
95 value: 16Gi
96 name: gpu-0
97 - attributes:
98 addressingMode:
99 string: HMM
100 architecture:
101 string: Turing
102 brand:
103 string: Nvidia
104 cudaComputeCapability:
105 version: 7.5.0
106 cudaDriverVersion:
107 version: 13.0.0
108 driverVersion:
109 version: 580.126.20
110 productName:
111 string: Tesla T10
112 resource.kubernetes.io/pciBusID:
113 string: "0000:00:07.0"
114 resource.kubernetes.io/pcieRoot:
115 string: pci0000:00
116 type:
117 string: gpu
118 uuid:
119 string: GPU-d1bf2033-42f6-096c-b0c6-470575bc08df
120 capacity:
121 memory:
122 value: 16Gi
123 name: gpu-1
124 driver: gpu.nvidia.com
125 nodeName: capi-dralabs-md-gput10-gzl84-f2m2d
126 pool:
127 generation: 1
128 name: capi-dralabs-md-gput10-gzl84-f2m2d
129 resourceSliceCount: 1
130kind: List
131metadata:
132 resourceVersion: ""有了這些資訊,Pod 該如何跟 Kubernetes 說我要哪些裝置呢?接下來就要來介紹 ResourceClaim 和 ResourceClaimTemplate!
ResourceClaim & ResourceClaimTemplate#
如果會希望很多個 Pod 對同一個裝置做使用,可以手動建立 ResourceClaim 管理,不論 Pod 新增或刪除,都不會被影響,完全獨立自主。

那假設想要每個 Pod 都有自己的裝置呢?ResourceClaimTemplate 可以先寫好 ResourceClaim 資源,Deployment 寫上 ResourceClaimTemplate 的名字,只要 Deployment 新增 Pod,就會自動產生對應的 ResourceClaim,反之刪除 Pod,就會把相對應的 ResourceClaim 刪除。

有沒有覺得上面這些概念哪裡似曾相識呢?DRA 概念就是借鑑 Storage 來達成,PersistentVolumeClaim 和 PersistentVolumeClaimTemplate(後者僅存在於 StatefulSet 當中),DeviceClass 就有點像 StorageClass。
DRA 練習#
情境 I:2 個容器共用 1 張 GPU#
用 ResourceClaim 宣告說要一張 NVIDIA GPU,接著 Pod 開兩個容器使用該顯卡。
1apiVersion: resource.k8s.io/v1
2kind: ResourceClaim
3metadata:
4 name: must-nvidia-gpu
5spec:
6 devices:
7 requests:
8 - name: gpu
9 exactly:
10 deviceClassName: gpu.nvidia.com
11 count: 1接下來套用資源:
kubectl apply -f lab01-rc.yaml用 get 取得 ResourceClaim 資訊:
kubectl get resourceclaim就能看到目前狀態是 pending,因為還沒有 Pod 使用該資源。
NAME STATE AGE
must-nvidia-gpu pending 10s這裡寫好兩個容器的 Pod,並且使用剛剛建立的 ResourceClaim —— must-nvidia-gpu。
1apiVersion: v1
2kind: Pod
3metadata:
4 name: must-nvidia-gpu-pod
5spec:
6 restartPolicy: Never
7 containers:
8 - name: ctr0
9 image: ubuntu:24.04
10 command: ["bash", "-c"]
11 args: ["nvidia-smi -L; trap 'exit 0' TERM; sleep 9999 & wait"]
12 resources:
13 claims:
14 - name: gpu
15 - name: ctr1
16 image: ubuntu:24.04
17 command: ["bash", "-c"]
18 args: ["nvidia-smi -L; trap 'exit 0' TERM; sleep 9999 & wait"]
19 resources:
20 claims:
21 - name: gpu
22 resourceClaims:
23 - name: gpu
24 resourceClaimName: must-nvidia-gpu接著就可以開新的 Pod:
kubectl apply -f lab01-pod.yaml重新看 ResourceClaim 資訊:
kubectl get resourceclaim就能看到狀態更改為 allocated 和 reserved,因為已經有 Pod 使用該資源。
NAME STATE AGE
must-nvidia-gpu allocated,reserved 16s接下來就可以用 logs 印出內容:
kubectl logs pod must-nvidia-gpu-pod --all-containers --prefix[pod/must-nvidia-gpu-pod/ctr0] GPU 0: Tesla T10 (UUID: GPU-dae084a2-974c-00e2-6dec-4ba1999b8652)
[pod/must-nvidia-gpu-pod/ctr1] GPU 0: Tesla T10 (UUID: GPU-dae084a2-974c-00e2-6dec-4ba1999b8652)實際不一定是 T10,也有可能是 A5000。
接下來把 Pod 刪除掉:
kubectl delete -f lab01-pod.yaml重新看 ResourceClaim 資訊:
kubectl get resourceclaim狀態重新回到 pending,因為已經沒有 Pod 使用該資源。
NAME STATE AGE
must-nvidia-gpu pending 3m39s刪除 ResourceClaim:
kubectl delete -f lab01-rc.yaml但上面範例只寫了一張 GPU,不過根本不知道用哪張 GPU。
這情境其實跟原本的 Device Plugin 沒什麼兩樣,對吧?但後面情境才是 DRA 的優勢!
情境 II:ResourceClaimTemplate 優先使用 A5000 套用 Deployment#
今天 RD 跑來跟我說,他想要有推論模型可以優先使用 A5000,但知道機器沒有很多,希望 scale up 的時候可以用 T10。
ResourceClaim 資源除了 exactly 以外,也可以用 firstAvailable 排優先順序,回到 ResourceSlice 的完整輸出結果,想要指定顯卡名稱,可以用 .attributes.productName。
就會像以下的寫法:
1apiVersion: resource.k8s.io/v1
2kind: ResourceClaimTemplate
3metadata:
4 name: first-a5000
5spec:
6 spec:
7 devices:
8 requests:
9 - name: gpu
10 firstAvailable:
11 - name: a5000
12 deviceClassName: gpu.nvidia.com
13 selectors:
14 - cel:
15 expression: device.attributes["gpu.nvidia.com"].productName == "NVIDIA RTX A5000"
16 - name: fallback-t10
17 deviceClassName: gpu.nvidia.com
18 selectors:
19 - cel:
20 expression: device.attributes["gpu.nvidia.com"].productName == "Tesla T10"
21---
22apiVersion: apps/v1
23kind: Deployment
24metadata:
25 name: first-a5000-deploy
26 labels:
27 app: first-a5000-deploy
28spec:
29 replicas: 1
30 selector:
31 matchLabels:
32 app: first-a5000-deploy
33 template:
34 metadata:
35 labels:
36 app: first-a5000-deploy
37 spec:
38 containers:
39 - name: ctr0
40 image: ubuntu:24.04
41 command: ["bash", "-c"]
42 args: ["nvidia-smi -L; trap 'exit 0' TERM; sleep 9999 & wait"]
43 resources:
44 claims:
45 - name: gpu
46 resourceClaims:
47 - name: gpu
48 resourceClaimTemplateName: first-a5000把上面內容存為 lab02.yaml,套用進去:
kubectl apply -f lab02.yaml確認 Pod 在 Running,並從 nvidia-smi -L 的輸出確認分到的是 A5000:
kubectl get pod
kubectl logs deployments/first-a5000-deploy --all-podsNAME READY STATUS RESTARTS AGE
first-a5000-deploy-8c6cf4568-2lsv9 1/1 Running 0 9s
[pod/first-a5000-deploy-8c6cf4568-2lsv9/ctr0] GPU 0: NVIDIA RTX A5000 (UUID: GPU-e13ce856-7474-797f-d143-16e99b65c0c3)接著 scale up 到 2 個副本,看新的 Pod 會分到哪張:
kubectl scale deployment first-a5000-deploy --replicas 2
kubectl logs deployments/first-a5000-deploy --all-pods[pod/first-a5000-deploy-8c6cf4568-2lsv9/ctr0] GPU 0: NVIDIA RTX A5000 (UUID: GPU-e13ce856-7474-797f-d143-16e99b65c0c3)
[pod/first-a5000-deploy-8c6cf4568-865jj/ctr0] GPU 0: Tesla T10 (UUID: GPU-dae084a2-974c-00e2-6dec-4ba1999b8652)第一個 Pod 已經佔用唯一一張 A5000,第二個 Pod 因此 fallback 到 T10 —— 這正是 firstAvailable 在第一順位不可用時的預期行為。
並且可以看到相對應的 ResourceClaim:
kubectl get resourceclaimNAME STATE AGE
first-a5000-deploy-8c6cf4568-2lsv9-gpu-bdz9j allocated,reserved 4m29s
first-a5000-deploy-8c6cf4568-865jj-gpu-mqfcx allocated,reserved 3m29s如果把 A5000 的 Pod 下令刪除,重建的 Pod 會回到 A5000 嗎?
如果以上面的設定檔來說,不會回到 A5000。Deployment 預設的 strategy.type 是 RollingUpdate,舊的 Pod 進到 Terminating 的時候,ResourceClaim 並沒有被釋放。Deployment controller 會立刻建立新的 Pod,也會依照 ResourceClaimTemplate 建立新的 ResourceClaim,新的 ResourceClaim 看到 A5000 依然被舊的 Pod 佔用,會 fallback 到 T10。
接下來,就可以把資源清除掉:
kubectl delete -f lab02.yaml情境 III:需要 20 GiB 以上記憶體的 GPU#
今天有個 LLM 模型要部署,RD 跟我說需要使用 20 GiB 以上記憶體的單張 GPU,但還在測試中所以不用算力要求,有空閒的 GPU 就可以了。
除了 .attributes 外,還有 .capacity.memory 可以使用,但該如何寫比較規則呢?可以看看第 15 行:
1apiVersion: resource.k8s.io/v1
2kind: ResourceClaimTemplate
3metadata:
4 name: gt20g
5spec:
6 spec:
7 devices:
8 requests:
9 - name: gpu
10 firstAvailable:
11 - name: gt20g
12 deviceClassName: gpu.nvidia.com
13 selectors:
14 - cel:
15 expression: device.capacity["gpu.nvidia.com"].memory.isGreaterThan(quantity("20Gi"))
16---
17apiVersion: apps/v1
18kind: Deployment
19metadata:
20 name: gt20g-deploy
21 labels:
22 app: gt20g-deploy
23spec:
24 replicas: 1
25 selector:
26 matchLabels:
27 app: gt20g-deploy
28 template:
29 metadata:
30 labels:
31 app: gt20g-deploy
32 spec:
33 containers:
34 - name: ctr0
35 image: ubuntu:24.04
36 command: ["bash", "-c"]
37 args: ["nvidia-smi -L; trap 'exit 0' TERM; sleep 9999 & wait"]
38 resources:
39 claims:
40 - name: gpu
41 resourceClaims:
42 - name: gpu
43 resourceClaimTemplateName: gt20g利用 CEL 的 isGreaterThan(quantity("20Gi")) 表示需要大於 20 GiB。
接下來就可以套用進去:
kubectl apply -f lab03.yaml確認一下 Pod 是否在 Running,確認顯卡是不是 A5000。
kubectl get pod
kubectl logs deployments/gt20g-deploy --all-podsNAME READY STATUS RESTARTS AGE
gt20g-deploy-5ff576476-hdz8f 1/1 Running 0 5m16s
[pod/gt20g-deploy-5ff576476-hdz8f/ctr0] GPU 0: NVIDIA RTX A5000 (UUID: GPU-e13ce856-7474-797f-d143-16e99b65c0c3)接著,試試看 scale up 後會發生什麼事:
kubectl scale deployment gt20g-deploy --replicas 2增長了之後,確認一下 Pod 有沒有新加入:
kubectl get podNAME READY STATUS RESTARTS AGE
gt20g-deploy-5ff576476-hdz8f 1/1 Running 0 8m9s
gt20g-deploy-5ff576476-vjss8 0/1 Pending 0 26s對 gt20g-deploy-5ff576476-vjss8 這個 Pod 做 describe:
kubectl describe pod gt20g-deploy-5ff576476-vjss8Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 98s default-scheduler 0/4 nodes are available: 1 node(s) had untolerated taint(s), 3 cannot allocate all claims. still not schedulable, preemption: 0/4 nodes are available: 4 Preemption is not helpful for scheduling.因為現在 Cluster 沒有其他可用的 20 GiB 以上記憶體的 GPU,T10 只有 16 GiB,因此新加入的 Pod 就會被卡在 Pending。
接下來把資源清除:
kubectl delete -f lab03.yaml如果要更複雜的判斷方式,可以去詳讀 CEL 在 Kubernetes 的使用方式。
情境 IV:GPU Time Slicing in DRA#
截至 2026/5/10 發文當下,NVIDIA 官方文件和 NVIDIA DRA Driver GPU 的 Wiki 文件並沒有針對 Time Slicing 撰寫任何教學。
設定內容是參照 demo/specs/quickstart/v1/gpu-test5.yaml 的內容改編,筆者也去讀了部分程式碼,Feature Gate 部分參考國外文章資料撰寫。
設定方式可能會隨著未來更新有所不同,特此注意!
今天 RD 又跑過來跟我說:「我知道 DRA 很棒,能更有效分配資源,但有沒有辦法還是可以回去使用 Time Slicing 模式?」
想要回去原本的模式?當然是……,沒問題的!
只要在 .spec.devices.config 寫上我要設定的裝置,共享策略調整為 TimeSlicing。內容範例如下:
1apiVersion: resource.k8s.io/v1
2kind: ResourceClaim
3metadata:
4 name: time-slicing-manual
5spec:
6 devices:
7 requests:
8 - name: ts-gpu
9 exactly:
10 deviceClassName: gpu.nvidia.com
11 config:
12 - requests: ["ts-gpu"]
13 opaque:
14 driver: gpu.nvidia.com
15 parameters:
16 apiVersion: resource.nvidia.com/v1beta1
17 kind: GpuConfig
18 sharing:
19 strategy: TimeSlicing
20 timeSlicingConfig:
21 interval: Long
22---
23apiVersion: apps/v1
24kind: Deployment
25metadata:
26 name: ts-gpu-deployment
27spec:
28 replicas: 4
29 selector:
30 matchLabels:
31 app: ts-gpu
32 template:
33 metadata:
34 labels:
35 app: ts-gpu
36 spec:
37 containers:
38 - name: ctr
39 image: nvcr.io/nvidia/k8s/cuda-sample:nbody-cuda11.6.0-ubuntu18.04
40 command: ["bash", "-c"]
41 args: ["trap 'exit 0' TERM; /tmp/sample --benchmark --numbodies=4226000 & wait"]
42 resources:
43 claims:
44 - name: gpu
45 resourceClaims:
46 - name: gpu
47 resourceClaimName: time-slicing-manual將上面內容儲存為 lab04.yaml,就可以套用進去:
kubectl apply -f lab04.yaml確認一下 Pod 是否都有正常運作:
kubectl get podNAME READY STATUS RESTARTS AGE
ts-gpu-deployment-549c945798-6t2dx 1/1 Running 0 4s
ts-gpu-deployment-549c945798-tlgp4 1/1 Running 0 4s
ts-gpu-deployment-549c945798-x2gbv 1/1 Running 0 4s
ts-gpu-deployment-549c945798-xbv22 1/1 Running 0 4s因為 4 個 Pod 共用同一個 ResourceClaim,用 kubectl get resourceclaim 會只看到一筆,這本身就說明它們在共享:
kubectl get resourceclaimNAME STATE AGE
time-slicing-manual allocated,reserved 30s如果再用 describe 進去看,會看到 Reserved For 列出全部 4 個 Pod:
kubectl describe resourceclaim time-slicing-manualStatus:
Allocation:
Devices:
Config:
Opaque:
Driver: gpu.nvidia.com
Parameters:
API Version: resource.nvidia.com/v1beta1
Kind: GpuConfig
Sharing:
Strategy: TimeSlicing
Time Slicing Config:
Interval: Long
Requests:
ts-gpu
Source: FromClaim
Results:
Device: gpu-0
Driver: gpu.nvidia.com
Pool: capi-dralabs-md-gpua5000-jw4mx-d64jz
Request: ts-gpu
Node Selector:
Node Selector Terms:
Match Fields:
Key: metadata.name
Operator: In
Values:
capi-dralabs-md-gpua5000-jw4mx-d64jz
Reserved For:
Name: ts-gpu-deployment-549c945798-x2gbv
Resource: pods
UID: be21eecf-2d58-4891-9cac-ac3674f4ff09
Name: ts-gpu-deployment-549c945798-6t2dx
Resource: pods
UID: 37d504a0-966e-4263-9fcd-b713d73c0e77
Name: ts-gpu-deployment-549c945798-xbv22
Resource: pods
UID: 2b5ec297-9889-4cb9-8079-b626a854b292
Name: ts-gpu-deployment-549c945798-tlgp4
Resource: pods
UID: ee836856-8c6b-4161-9582-4bc4ff63a606這樣就能在 DRA 下啟用 Time Slicing 行為,效果類似舊有 Device Plugin 的 Time Slicing 模式,不需要刻意寫要切幾等份,只需要設定 timeSlicingConfig 與循環週期。
接下來就可以把資源清除:
kubectl delete -f lab04.yaml總結#
相比 Device Plugin,現在的 DRA 能以更清晰的方式使用,讓開發者和叢集管理員更精準分配裝置。不需要再把同一個裝置放到同一個節點,或者寫複雜的規則放在 nodeSelector 或 Affinity 等。
K8s v1.36 以後還有裝置健康狀態回報,不再讓 Pod 只有顯示 Error,能知道 Error 原因是裝置問題還是應用程式問題。
過去,K8s 叢集如果發現所需的 CPU、Memory 不夠,可以透過 Cluster Autoscaler 開啟新機器,如果 GPU 不夠,未來說不定也可以透過 Cluster Autoscaler 產生所需的 GPU 節點,更有效地去分配資源。
後記#
前年為了一些測試需求買了 A5000,就把這張顯卡放到 Infra Labs,但覺得很可惜沒有更多的實驗測試,再加上自己太忙,一直放在機房裡面吃電和吃灰塵。
dra-driver-nvidia-gpu 進到 Kubernetes SIGs 的時候,想到裡面還有提供兩張 T10 顯卡,於是就促成這次的 Lab。
同時,我也看到了許多 AI Gateway 的出現,還有 Gateway API 的延伸套件 —— Gateway API Inference Extension,有機會再來寫文章介紹!