この記事でやること
今回は kubernetes-sigs/dra-example-driver を使い実際のGPUがなくとも擬似的なGPUがあるという想定で、
- ノード側にDRAドライバ(kubelet plugin)を入れる
- ドライバが ResourceSlice(在庫表)を自動で公開する
- Podを作ると、schedulerがClaimを割当て
- kubeletがドライバを呼んで Prepare/Unprepare(=デバイス注入の準備)が走る
このDRAの流れをkindで体験するチュートリアルです。
dra-example-driver とは
dra-example-driver は、Kubernetes公式ドキュメントでも使われているDRAドライバのサンプル実装です。
- ノードにDaemonSetで入る kubelet plugin として動作
- GPUがあることにして、ノードごとに複数台の擬似GPUを生成(例:NUM_DEVICES=9)
- 生成した在庫(デバイスの一覧)を ResourceSlice としてAPIに公開し
- PodがClaimしたときに、kubelet経由で PrepareResourceClaims / UnprepareResourceClaims が呼ばれ、コンテナ側に「割当てられたGPU情報」を見せる(主にCDIを使う)
という流れです
役割と責務を整理する
-
クラスタ管理者
- DRAドライバをインストールします。
- デバイスのカテゴリを表すDeviceClassを用意します。
-
DRAドライバ
- ノードにあるデバイスの在庫をResourceSliceとして公開します。
- kubeletから呼ばれるPrepareとUnprepareを実装します。
-
ワークロード運用者
- 必要なデバイス条件をResourceClaimまたはResourceClaimTemplateとして宣言します。
- PodでClaimを参照します。
リソースの関係を整理する
- ResourceSliceは在庫表です。
- DeviceClassはカテゴリ定義です。
- ResourceClaimとResourceClaimTemplateは注文書です。
- Podは注文書を参照して実行します。
割当の結果はResourceClaimのstatusに書き込まれます。
kindでクラスタを用意
ここではkindを例にします。クラスタが既にある場合は、この手順を省略してもかまいません。
kind create cluster --name dra-tutorial-cluster \
--image kindest/node:v1.35.0 \
--config - <<'EOF'
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
EOF
クラスタが作成されます。
Creating cluster "dra-tutorial-cluster" ...
✓ Ensuring node image (kindest/node:v1.35.0) 🖼
✓ Preparing nodes 📦 📦 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
✓ Joining worker nodes 🚜
Set kubectl context to "kind-dra-tutorial-cluster"
You can now use your cluster with:
kubectl cluster-info --context kind-dra-tutorial-cluster
Have a nice day! 👋
kubectl cluster-info --context kind-dra-tutorial-cluster
Kubernetes control plane is running at https://127.0.0.1:55596
CoreDNS is running at https://127.0.0.1:55596/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
dra-example-driverをインストール
次のマニフェストを適用して、DeviceClass、RBAC、PriorityClass、DaemonSetなどを作成します。
kubectl create namespace dra-tutorial
namespace/dra-tutorial created
kubectl apply --server-side -f https://k8s.io/examples/dra/driver-install/deviceclass.yaml
kubectl apply --server-side -f https://k8s.io/examples/dra/driver-install/serviceaccount.yaml
kubectl apply --server-side -f https://k8s.io/examples/dra/driver-install/clusterrole.yaml
kubectl apply --server-side -f https://k8s.io/examples/dra/driver-install/clusterrolebinding.yaml
kubectl apply --server-side -f https://k8s.io/examples/dra/driver-install/priorityclass.yaml
kubectl apply --server-side -f https://k8s.io/examples/dra/driver-install/daemonset.yaml
deviceclass.resource.k8s.io/gpu.example.com serverside-applied
serviceaccount/dra-example-driver-service-account serverside-applied
clusterrole.rbac.authorization.k8s.io/dra-example-driver-role serverside-applied
clusterrolebinding.rbac.authorization.k8s.io/dra-example-driver-role-binding serverside-applied
priorityclass.scheduling.k8s.io/dra-driver-high-priority serverside-applied
daemonset.apps/dra-example-driver-kubeletplugin serverside-applied
ドライバPodとResourceSliceを確認する
kubectl get pod -n dra-tutorial -l app.kubernetes.io/name=dra-example-driver
NAME READY STATUS RESTARTS AGE
dra-example-driver-kubeletplugin-n8wgk 1/1 Running 0 2m15s
dra-example-driver-kubeletplugin-qw8nb 1/1 Running 0 2m15s
ノードごとにResourceSliceが作成されていることが確認できます。
kubectl get resourceslices
NAME NODE DRIVER POOL AGE
dra-tutorial-cluster-worker-gpu.example.com-848mn dra-tutorial-cluster-worker gpu.example.com dra-tutorial-cluster-worker 2m32s
dra-tutorial-cluster-worker2-gpu.example.com-5sdxj dra-tutorial-cluster-worker2 gpu.example.com dra-tutorial-cluster-worker2 2m29s
ResourceSliceが自動で作成されていれば、ドライバが在庫表を公開できています。
具体的にどんな在庫があるかを見てみます。
kubectl get resourceslice dra-tutorial-cluster-worker-gpu.example.com-848mn -o yaml \
| grep -E 'kind:|name:|driver:|nodeName:'
dra-tutorial-cluster-worker、dra-tutorial-cluster-worker2ノードでは、それぞれgpu-0からgpu-8の合計9個のGPUがある状態です。
kind: ResourceSlice
name: dra-tutorial-cluster-worker-gpu.example.com-848mn
kind: Node
name: dra-tutorial-cluster-worker
name: gpu-6
name: gpu-7
name: gpu-8
name: gpu-0
name: gpu-1
name: gpu-2
name: gpu-4
name: gpu-3
name: gpu-5
driver: gpu.example.com
nodeName: dra-tutorial-cluster-worker
name: dra-tutorial-cluster-worker
ワークロードを作ってGPUを消費させてみる
ResourceClaimTemplateを作成する
1つのGPUを要求するテンプレートをgpu-templateという名前で作成してみます。
kubectl apply -f - <<'EOF'
apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
name: gpu-template
spec:
spec:
devices:
requests:
- name: gpu
exactly:
deviceClassName: gpu.example.com
EOF
resourceclaimtemplate.resource.k8s.io/gpu-template createdとなり、ResourceClaimTemplateが作成されました。
Deploymentを作成する
Pod側では次の2つを対応させます。
- spec.resourceClaimsでClaimを生成します。
- containers.resources.claimsでそのClaimをコンテナに割り当てます。
このような2つのGPUがあるPodを1つ作成するとします。
kubectl apply -f - <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: dra-demo
spec:
replicas: 1
selector:
matchLabels:
app: dra-demo
template:
metadata:
labels:
app: dra-demo
spec:
containers:
- name: c
image: ubuntu:24.04
command: ['bash', '-lc', 'sleep 1d']
resources:
claims:
- name: gpu0
- name: gpu1
resourceClaims:
- name: gpu0
resourceClaimTemplateName: gpu-template
- name: gpu1
resourceClaimTemplateName: gpu-template
EOF
deployment.apps/dra-demo createdとなり、Podが作成されました。
PodがRunningになっていることを確認できます。
kubectl get pod -l app=dra-demo -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
dra-demo-7665c948d5-knx2d 1/1 Running 0 16m 10.244.1.3 dra-tutorial-cluster-worker <none> <none>
ResourceClaimでGPUが割り当てられていることを確認
STATEがallocated,reservedになっていれば割当が決まり、Podに予約されています。
kubectl get resourceclaim
NAME STATE AGE
dra-demo-7665c948d5-knx2d-gpu0-t9tz4 allocated,reserved 44s
dra-demo-7665c948d5-knx2d-gpu1-vldwn allocated,reserved 44s
ResourceClaimのAllocationとNodeSelectorを確認
kubectl describe resourceclaim dra-demo-7665c948d5-knx2d-gpu0-t9tz4 \
| grep -E '^(Name:|Namespace:| *Device Class Name:| *Count:|Status:| *Allocation:| *Results:| *Device:| *Driver:| *Pool:| *Request:| *Node Selector:| *Values:| *dra-tutorial-| *Reserved For:| *Name: *)'
Pod:dra-demo-7665c948d5-knx2dにdra-tutorial-cluster-workerのノードにあるgpu-6のGPUが割り当てられていることがわかります。また、Node Selectorで配置先ノードの制約が入っていることも確認できます。
Name: dra-demo-7665c948d5-knx2d-gpu0-t9tz4
Namespace: default
Name: dra-demo-7665c948d5-knx2d
Count: 1
Device Class Name: gpu.example.com
Name: gpu
Status:
Allocation:
Results:
Device: gpu-6
Driver: gpu.example.com
Pool: dra-tutorial-cluster-worker
Request: gpu
Node Selector:
Values:
dra-tutorial-cluster-worker
Reserved For:
Name: dra-demo-7665c948d5-knx2d
もう1つのResourceClaimのdra-demo-7665c948d5-knx2d-gpu1-vldwnではgpu-7が割り当ててられています。
kubectl describe resourceclaim dra-demo-7665c948d5-knx2d-gpu1-vldwn \
| grep -E '^(Name:| *Device Class Name:| *Count:| *Device:)'
Name: dra-demo-7665c948d5-knx2d-gpu1-vldwn
Count: 1
Device Class Name: gpu.example.com
Device: gpu-7
結果として以下のように2つのResourClaimが作成されているのを確認できます。
実機のGPUではないためnvidia-smiのようなGPU自体の動作確認はできませんが、Prepare(GPUの用意)に至る経路が成立していることを確認できました。
スケールさせても空いているGPUを選べるか確認
kubectl scale deployment dra-demo --replicas=2
deployment.apps/dra-demo scaledとなり、Pod数を1→2にスケールさせました。
kubectl get pod -l app=dra-demo -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
dra-demo-7665c948d5-hq9s4 1/1 Running 0 3m48s 10.244.2.3 dra-tutorial-cluster-worker2 <none> <none>
dra-demo-7665c948d5-knx2d 1/1 Running 0 84m 10.244.1.3 dra-tutorial-cluster-worker <none> <none>
ResourceClaimの数も2GPU x 2Podで4つとなっています。
kubectl get resourceclaim
NAME STATE AGE
dra-demo-7665c948d5-hq9s4-gpu0-z7mvr allocated,reserved 4m20s
dra-demo-7665c948d5-hq9s4-gpu1-pvgnq allocated,reserved 4m20s
dra-demo-7665c948d5-knx2d-gpu0-t9tz4 allocated,reserved 85m
dra-demo-7665c948d5-knx2d-gpu1-vldwn allocated,reserved 85m
しっかり空いているGPUを割り当てていることがわかります。結果的に2GPUを持つPod2つが作成されています。
kubectl get resourceclaim -o name \
| xargs -n1 kubectl describe \
| grep -E '^(Name:| *Device:| *Pool:| *Reserved For:)'
後片付け
kubectl delete deployment dra-demo
kubectl delete resourceclaimtemplate single-gpu
kind delete cluster --name dra


