Ringkasan Utama
Kubernetes 1.36 menjadikan prioritized list di Dynamic Resource Allocation stable: ResourceClaim berisi subrequest firstAvailable, misalnya satu H100 dulu lalu dua A100, dan scheduler mengambil yang pertama bisa dialokasikan. Partitionable devices seperti MIG slice masih beta di 1.36, jadi adopsi dengan sadar.
Permintaan yang sering saya lihat di cluster GPU sebenarnya bukan untuk satu model kartu. Yang dibutuhkan adalah memori cukup untuk memuat model, dengan preferensi ke kartu cepat dan toleransi ke kartu yang lebih lambat. Cara meminta ala device plugin, jumlah tetap dari satu resource bernama pada container, tidak bisa menyatakan itu, sehingga tim akhirnya punya dua Deployment, dua set manifest, dan manusia yang memutuskan mana yang di-apply.
Kubernetes 1.36 menutup celah itu lewat prioritized list di Dynamic Resource Allocation (DRA) yang sudah stable. Post ini adalah hasil membaca, bukan benchmark. Saya membaca post v1.36 dari tim DRA Kubernetes, halaman concept dan task terbaru, serta dokumentasi driver DRA NVIDIA, dan saya tidak menjalankan apa pun di cluster GPU. Setiap nama field di bawah berasal dari halaman yang saya baca, dan bagian yang saya rakit sendiri saya tandai.
Kenapa claim, bukan sekadar jumlah
DRA bekerja mirip dynamic volume provisioning. Driver mempublikasikan ResourceSlice yang menjelaskan device, admin atau driver mendefinisikan DeviceClass sebagai kategori, dan workload meminta device lewat ResourceClaim atau ResourceClaimTemplate yang memfilter dengan ekspresi CEL pada atribut device. Docs menyebut keunggulan dibanding device plugin: filter CEL yang fleksibel, sharing device antar container dan Pod, konfigurasi per workload, dan kategori terpusat, sementara device plugin butuh request per container dan tanpa sharing atau filter ekspresi. Fitur intinya stable sejak Kubernetes 1.35 dan pertama muncul di 1.30.
Claim adalah objek yang bisa diperiksa, dibagi dan dijadikan template, dan itulah yang membuat fallback mungkin. Jumlah pada container hanyalah angka yang dipenuhi scheduler atau tidak. Claim adalah query kecil, dan query bisa punya pilihan kedua. Harganya adalah objek baru yang harus dipelajari: ResourceSlice, DeviceClass, ResourceClaim, ResourceClaimTemplate.
Prioritized list dalam satu manifest
Post Kubernetes merangkumnya dalam satu kalimat: beri saya H100, tetapi kalau tidak ada, fallback ke A100. Di API ini adalah field firstAvailable pada sebuah request, berisi daftar subrequest berurutan. Halaman API concepts menandainya Stable since 1.36, aktif secara default, dan pertama tersedia di 1.33. Scheduler memilih subrequest pertama yang bisa dialokasikan, dan tiap subrequest bisa membawa selector dan count sendiri.
Di bawah ini claim template dengan bentuk contoh di docs, disesuaikan untuk driver NVIDIA. Atribut productName dan DeviceClass gpu.nvidia.com berasal dari referensi ResourceSlice driver, yang mencantumkan nilai seperti NVIDIA A100-PCIE-40GB. String produk H100 yang persis tidak ada di halaman itu, jadi saya memakai substring match dan Anda sebaiknya memastikan string aslinya dengan kubectl get resourceslices -o yaml di node Anda sendiri.
apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
name: h100-else-a100
spec:
spec:
devices:
requests:
- name: gpu
# firstAvailable replaces "exactly": the scheduler walks this list
# in order and takes the first entry it can allocate.
firstAvailable:
- name: h100
deviceClassName: gpu.nvidia.com
selectors:
- cel:
expression: |-
device.attributes["gpu.nvidia.com"].productName.contains("H100")
- name: a100-pair
deviceClassName: gpu.nvidia.com
count: 2 # a fallback may ask for a different shape, not just a different card
selectors:
- cel:
expression: |-
device.attributes["gpu.nvidia.com"].productName.contains("A100")Perhatikan fallback di sini tidak sepadan: satu H100 dulu, dua A100 kemudian. Itulah gunanya count per subrequest. Itu juga jebakannya, karena workload yang jalan harus bisa berjalan di kedua bentuk, dan claim tidak bisa menjamin itu untuk Anda.
Menyambungkan ke Pod dan membaca hasilnya
Pod merujuk template di spec.resourceClaims lalu menyebut nama claim di resources.claims milik container, dua langkah yang sama dengan contoh Job di halaman task. ResourceClaimTemplate memberi tiap Pod claim hasil generate sendiri, dengan lifetime terikat pada Pod. Pakai ResourceClaim tulisan tangan bila beberapa Pod harus berbagi device yang sama.
apiVersion: v1
kind: Pod
metadata:
name: inference
spec:
containers:
- name: server
image: ubuntu:24.04
command: ["sleep", "9999"]
resources:
claims:
- name: accelerator # must match the entry below
resourceClaims:
- name: accelerator
resourceClaimTemplateName: h100-else-a100 # one generated claim per Pod
# Then, per the task page, drill down when it does not start:
# kubectl describe pod inference
# kubectl get resourceclaims
# kubectl describe resourceclaim <generated-name>Scheduler juga memakai posisi subrequest yang terpilih sebagai salah satu input saat menilai node, sehingga node yang bisa memenuhi subrequest berperingkat lebih tinggi lebih mungkin dipilih. Setelah scheduling, saran troubleshooting di docs berlaku: telusuri dari Job ke Pod ke ResourceClaim dan jalankan kubectl describe di tiap level, lihat status dan event.
Beri nama subrequest sesuai maknanya, misalnya h100 dan a100-pair, bukan first dan second. Nama itulah yang Anda cari saat membaca kembali hasil alokasi, dan itu yang dibaca tim on-call tengah malam.
Partitionable devices: MIG tanpa membohongi scheduler
Partitionable devices beta di 1.36 dan docs terbaru menulis Beta since 1.36, aktif secara default, di balik feature gate DRAPartitionableDevices pada kube-apiserver dan kube-scheduler. Modelnya adalah counter. ResourceSlice mendeklarasikan counter set bernama yang menggambarkan isi device fisik, dan tiap device logis mendeklarasikan apa yang ia konsumsi. Pada contoh docs, dua device masing-masing mengonsumsi 6Gi dari satu counter berisi 8Gi, sehingga hanya satu yang bisa dialokasikan pada satu waktu, dan API ResourceClaim di sisi konsumen tidak berubah.
# From the DRA features page: two devices that each consume 6Gi of a shared
# 8Gi counter. Both are advertised, only one can ever be allocated.
apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
name: resourceslice-with-countersets
spec:
nodeName: worker-1
pool: {name: pool, generation: 1, resourceSliceCount: 2}
driver: dra.example.com
sharedCounters: # counter sets live in their own slice...
- name: gpu-1-counters
counters:
memory:
value: 8Gi
---
apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
name: resourceslice-with-devices
spec:
nodeName: worker-1
pool: {name: pool, generation: 1, resourceSliceCount: 2}
driver: dra.example.com
devices: # ...and the devices that draw on them in another
- name: device-1
consumesCounters:
- counterSet: gpu-1-counters
counters:
memory:
value: 6Gi
- name: device-2
consumesCounters:
- counterSet: gpu-1-counters
counters:
memory:
value: 6GiItulah representasi jujur untuk GPU berkemampuan MIG: device logis yang saling tumpang tindih dan tidak bisa ada semuanya sekaligus. CounterSet harus dipublikasikan di ResourceSlice terpisah dari device yang mengonsumsinya, dan device hanya bisa mengambil dari counter set di pool yang sama. Dengan driver NVIDIA, MIG slice muncul di DeviceClass mig.nvidia.com dengan atribut profile seperti 1g.5gb dan atribut parentUUID, dan panduan driver menunjukkan constraint matchAttribute pada parentUUID untuk memaksa dua slice berada di satu GPU fisik.
# Assembled by me from the NVIDIA MIG guide's description, not copied.
# Two MIG slices that must sit on the same physical GPU.
apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
name: two-mig-slices
spec:
spec:
devices:
requests:
- name: small
exactly:
deviceClassName: mig.nvidia.com
selectors:
- cel:
expression: device.attributes['gpu.nvidia.com'].profile == '1g.5gb'
- name: medium
exactly:
deviceClassName: mig.nvidia.com
selectors:
- cel:
expression: device.attributes['gpu.nvidia.com'].profile == '2g.10gb'
constraints:
- requests: ["small", "medium"]
matchAttribute: "gpu.nvidia.com/parentUUID"Claim kedua di bawah saya rakit dari deskripsi panduan itu dan bentuk API DRA, bukan salinan dari satu halaman, jadi cocokkan dengan panduan sebelum dipakai. Nama profile bergantung pada model GPU.
Device taint: mencabut GPU rusak tanpa drain node
Device taint bekerja seperti node taint, dengan key, value dan effect. NoSchedule membuat device bertaint tidak terlihat oleh alokasi, NoExecute juga mengeluarkan Pod yang sudah memakainya lewat device taint eviction controller, dan None diabaikan scheduler serta dipakai untuk memberi sinyal. Claim bisa menoleransi taint, dan eviction bisa ditunda dengan toleransi selama durasi tertentu. Admin membuat taint lewat DeviceTaintRule yang memilih device berdasarkan DeviceClass, driver, pool atau nama device, dan rule tanpa selector sengaja tidak menaint apa pun, supaya selector yang terlupa tidak mengusir semuanya.
# Dry run first: effect None changes nothing, but the controller reports
# how many devices it selects and how many Pods NoExecute would evict.
apiVersion: resource.k8s.io/v1
kind: DeviceTaintRule
metadata:
name: example
spec:
deviceSelector:
driver: dra.example.com # no selector at all would taint nothing, on purpose
taint:
key: dra.example.com/unhealthy
value: Broken
effect: None # read the status message, then change to NoExecute
# kubectl describe devicetaintrules
# kubectl wait --for=condition=EvictionInProgress=false DeviceTaintRule/exampleEffect None memberi Anda dry run. Docs menjelaskan cara membuat rule dengan effect None, membaca pesan tentang berapa device terpilih dan berapa Pod yang akan diusir, lalu mengubahnya ke NoExecute. Satu catatan jujur: post 1.36 mencantumkan device taint sebagai beta, sedangkan docs terbaru menandai taint dan DeviceTaintRule sebagai Stable since 1.37. Baca statusnya untuk versi cluster Anda, bukan untuk tanggal post ini.
Apa yang stable di 1.36 dan apa kata docs sekarang
Soal tingkat kematangan, post DRA paling cepat usang, jadi berikut post 1.36 dibandingkan halaman concept terbaru yang saya baca. Jika keduanya berbeda, halaman yang lebih baru yang benar, dan versi cluster Anda yang menentukan mana yang berlaku.
| Fitur | Di post 1.36 | Docs terbaru |
|---|---|---|
| Prioritized list | Stable | Stable since 1.36 |
| Extended resource support | Beta | Stable since 1.37 |
| Partitionable devices | Beta | Beta since 1.36, aktif default |
| Device taints dan tolerations | Beta | Stable since 1.37 |
| Device binding conditions | Beta | Beta since 1.36, aktif default |
| ResourceClaim untuk PodGroup | Alpha | Beta since 1.37, nonaktif default |
| Node allocatable resources (CPU, memory) | Alpha | Alpha since 1.36, nonaktif default |
Extended resource support adalah yang paling pelan tapi penting untuk adopsi. DeviceClass bisa membawa extendedResourceName, sehingga Pod yang meminta example.com/gpu: 2 dengan cara lama dipenuhi oleh device DRA di sebagian node dan oleh device plugin di node lain. Operator bisa memigrasikan cluster tanpa memaksa setiap tim aplikasi menulis ulang manifest lebih dulu.
# From the DRA API page: a DeviceClass that answers old-style requests.
# A Pod asking for "example.com/gpu: 2" can now land on DRA-managed nodes.
apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
name: gpu.example.com
spec:
selectors:
- cel:
expression: device.driver == 'gpu.example.com' && device.attributes['gpu.example.com'].type == 'gpu'
extendedResourceName: example.com/gpuYang berisiko: trade-off yang harus disebut
Batas pertama tertulis jelas di docs: scheduler tidak mendukung preemption untuk resource DRA. Pod berprioritas tinggi yang butuh device DRA tidak bisa mengusir Pod berjalan yang memegangnya, dan tetap Pending sampai device dibebaskan. Daftar fallback membuat ini lebih jarang menyakitkan karena ada lebih banyak cara untuk terpenuhi, tetapi tidak menghilangkannya.
Yang kedua, prioritized list diputuskan per Pod. Docs menyebut bila Pod bagian dari ReplicaSet atau grup serupa, Anda tidak bisa mengandalkan semua anggota memilih subrequest yang sama, jadi workload harus bisa menampungnya. Delapan replika bisa naik sebagai campuran satu H100 dan dua A100. Inference server dengan ukuran tensor parallel tetap atau anggaran memori tetap harus menoleransi itu atau dipecah ke claim terpisah.
Driver NVIDIA adalah catatan lain. README-nya menyatakan fitur alokasi GPU masih dalam pengembangan dan belum didukung resmi, dengan ComputeDomain sebagai bagian yang didukung resmi, dan halaman instalasi mewajibkan gpuResourcesEnabledOverride=true untuk alokasi GPU. Dynamic MIG adalah gate Alpha terpisah yang menghancurkan partisi MIG yang tidak ia buat saat kubelet plugin mulai. Jangan aktifkan di node yang partisinya ingin Anda pertahankan.
Dua catatan lebih kecil dari panduan MIG: pada kartu Ampere seperti A100, MIG mode harus diaktifkan sebelum driver mulai karena mengubahnya butuh reset GPU, dan bila nonaktif driver kembali ke alokasi GPU penuh dan tidak mengiklankan partisi. Claim yang meminta profile MIG lalu tidak menemukan apa pun, yang terlihat seperti masalah scheduling padahal bukan.
Yang dikerjakan hari Senin
Mulai dengan memastikan apa yang benar-benar didukung cluster Anda, lalu tulis claim fallback terkecil yang masih bisa Anda terima. Perintah pertama hanya membaca.
- Cek versi server. Halaman task mensyaratkan v1.34 atau lebih baru, dan prioritized list stable sejak 1.36.
- Pastikan DRA menjawab: kubectl get deviceclasses harus mengembalikan daftar atau No resources found, bukan error resource type tidak ada.
- Dump ResourceSlice Anda dan baca nama atribut serta string produk yang sebenarnya sebelum menulis CEL apa pun.
- Tulis claim firstAvailable dengan dua entri yang pilihan keduanya benar-benar bisa dijalankan workload Anda, lalu apply ke namespace uji.
- Sebelum menyentuh GPU produksi, buat DeviceTaintRule dengan effect None dan baca pesannya untuk melihat apa yang akan diusir NoExecute.
# 1. Server version: task pages need v1.34+, prioritized list is stable from 1.36
kubectl version
# 2. Is DRA answering? "No resources found" is fine; "doesn't have a resource type" is not
kubectl get deviceclasses
# 3. What do the drivers actually publish? Read real attribute names and product strings
kubectl get resourceslices
kubectl get resourceslice <name> -o yaml
# 4. Apply the fallback claim to a test namespace, then drill down if it hangs
kubectl apply -n dra-test -f h100-else-a100.yaml
kubectl describe resourceclaims -n dra-test
# 5. Rehearse an eviction before it is real (effect: None, then read the message)
kubectl apply -f taint-dry-run.yaml
kubectl describe devicetaintrulesJangan menambahkan DRA ke workload yang tidak butuh pilihan. Jika armada Anda satu model kartu dan jumlah sudah cukup, device plugin masih bekerja, dan docs menjelaskan jalur migrasi sebagai bertahap, dengan tujuan yang dinyatakan maintainer yaitu memindahkan pengguna dari device plugin ke DRA seiring waktu.
Aturan yang saya bawa: minta kapabilitas dengan fallback berurutan, pastikan workload di balik setiap entri memang valid, dan cek kematangan tiap fitur terhadap versi cluster Anda sendiri, bukan terhadap tanggal blog tempat Anda membacanya.
Sumber dan bacaan lanjutan
- Blog Kubernetes: v1.36 More Drivers, New Features, and the Next Era of DRA
- Docs Kubernetes: DRA API objects, prioritized list dan extended resources
- Docs Kubernetes: DRA features, partitionable devices dan consumable capacity
- Docs Kubernetes: device taints dan tolerations
- Docs Kubernetes: allocate devices to workloads with DRA
- Docs Kubernetes: how DRA works
- Docs driver DRA NVIDIA: atribut device ResourceSlice
- Docs driver DRA NVIDIA: panduan MIG
- Docs driver DRA NVIDIA: instalasi
- GitHub: README kubernetes-sigs/dra-driver-nvidia-gpu

