The module lifecycle stage: General Availability
The module has requirements for installation
This section provides ready-to-apply manifests for typical administrator and user tasks.
GPU nodes are often tainted (for example node-role=gpu:NoSchedule) so that regular workloads do not land there. To allow scheduling of regular workloads onto such nodes, add matching tolerations and a nodeSelector to the examples below.
Custom taint keys must be allowlisted in ModuleConfig global under .spec.settings.modules.placement.customTolerationKeys, otherwise creating the NodeGroup is rejected:
it is forbidden to create a NodeGroup resource with taints not specified in ModuleConfig "global"
in the array .spec.settings.modules.placement.customTolerationKeys, add: node-role to customTolerationKeys
Administrator: publishing GPU pools
All GPUs of one model
apiVersion: gpu.deckhouse.io/v1alpha1
kind: GPUClass
metadata:
name: a100
spec:
selector:
matchLabels:
gpu.deckhouse.io/device: a100-sxm4-40gbSmall MIG partitions only
apiVersion: gpu.deckhouse.io/v1alpha1
kind: GPUClass
metadata:
name: a100-small
spec:
selector:
matchLabels:
gpu.deckhouse.io/device: a100-sxm4-40gb
partitionFilter:
allow:
- 1g5gb
- 2g10gbProfile names in the filter are DNS labels: 1g5gb, not 1g.5gb.
A pool that cannot be shared
apiVersion: gpu.deckhouse.io/v1alpha1
kind: GPUClass
metadata:
name: a100-exclusive
spec:
selector:
matchLabels:
gpu.deckhouse.io/device: a100-sxm4-40gb
sharingFilter:
deny:
- mps
- tsCards on a specific node
apiVersion: gpu.deckhouse.io/v1alpha1
kind: GPUClass
metadata:
name: training-rig
spec:
selector:
matchLabels:
gpu.deckhouse.io/node: worker-gpu-1User: requesting a published class
Look up what is available, then request it by name.
To list all GPUClass objects in the cluster, use:
d8 k get gpuclassesTo list all DeviceClass objects that the GPU controller automatically created from a GPUClass, use:
d8 k get gpuclass a100 -o jsonpath='{.status.deviceClassNames}' | jqRequesting a whole GPU
apiVersion: batch/v1
kind: Job
metadata:
name: train
spec:
backoffLimit: 0
template:
spec:
restartPolicy: Never
containers:
- name: train
image: nvidia/cuda:12.8.0-devel-ubuntu24.04
command: ["nvidia-smi", "-L"]
resources:
requests:
gpu.deckhouse.io/a100: 1
limits:
gpu.deckhouse.io/a100: 1Requesting a MIG partition
resources:
requests:
gpu.deckhouse.io/a100-1g5gb: 1
limits:
gpu.deckhouse.io/a100-1g5gb: 1Requesting a quarter of a shared GPU
resources:
requests:
gpu.deckhouse.io/a100-mps-percent: 25
limits:
gpu.deckhouse.io/a100-mps-percent: 25User: writing the claim yourself
Use this when the published classes do not cover your needs.
Requesting a whole GPU exclusively
apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
name: nvidia-whole-gpu
spec:
selectors:
- cel:
expression: |
device.attributes["gpu.deckhouse.io"].vendor == "nvidia" &&
device.attributes["gpu.deckhouse.io"].computeAPI == "CUDA" &&
has(device.attributes["gpu.deckhouse.io"].deviceType) &&
device.attributes["gpu.deckhouse.io"].deviceType == "physical" &&
!has(device.attributes["gpu.deckhouse.io"].sharingStrategy)
---
apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
name: whole-gpu
spec:
spec:
devices:
requests:
- name: gpu
exactly:
deviceClassName: nvidia-whole-gpu
count: 1
---
apiVersion: batch/v1
kind: Job
metadata:
name: whole-gpu
spec:
backoffLimit: 0
template:
spec:
restartPolicy: Never
resourceClaims:
- name: gpu
resourceClaimTemplateName: whole-gpu
containers:
- name: probe
image: nvidia/cuda:12.8.0-devel-ubuntu24.04
command: ["nvidia-smi", "-L"]
resources:
claims:
- name: gpuRequesting a specific MIG profile
apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
name: nvidia-mig-2g10gb
spec:
selectors:
- cel:
expression: |
device.attributes["gpu.deckhouse.io"].vendor == "nvidia" &&
device.attributes["gpu.deckhouse.io"].computeAPI == "CUDA" &&
has(device.attributes["gpu.deckhouse.io"].deviceType) &&
device.attributes["gpu.deckhouse.io"].deviceType == "partition" &&
has(device.attributes["gpu.deckhouse.io"].partitionTechnology) &&
device.attributes["gpu.deckhouse.io"].partitionTechnology == "MIG" &&
has(device.attributes["gpu.deckhouse.io"].partitionProfile) &&
device.attributes["gpu.deckhouse.io"].partitionProfile == "2g.10gb"Profile names in a CEL selector are the hardware names, with dots.
Requesting a specific card by PCI address
- cel:
expression: |
device.attributes["gpu.deckhouse.io"].deviceType == "physical" &&
device.attributes["gpu.deckhouse.io"].pciAddress == "00000000:d5:00.0"Requesting a quarter of a GPU via MPS
apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
name: nvidia-gpu-mps
spec:
selectors:
- cel:
expression: |
device.attributes["gpu.deckhouse.io"].vendor == "nvidia" &&
device.attributes["gpu.deckhouse.io"].computeAPI == "CUDA" &&
has(device.attributes["gpu.deckhouse.io"].deviceType) &&
device.attributes["gpu.deckhouse.io"].deviceType == "physical" &&
has(device.attributes["gpu.deckhouse.io"].sharingStrategy) &&
device.attributes["gpu.deckhouse.io"].sharingStrategy == "mps"
---
apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
name: gpu-mps-quarter
spec:
spec:
devices:
requests:
- name: gpu
exactly:
deviceClassName: nvidia-gpu-mps
count: 1
capacity:
requests:
sharePercent: "25"
gpu.deckhouse.io/memory: 1Gi
config:
- requests: ["gpu"]
opaque:
driver: gpu.deckhouse.io
parameters:
apiVersion: resource.gpu.deckhouse.io/v1alpha1
kind: GpuConfig
sharing:
strategy: MPS
mpsConfig:
defaultActiveThreadPercentage: 25MPS on top of a MIG partition
Same idea, but with MigDeviceConfig and a partition selector. On a partition, sharePercent alone is enough:
requests:
- name: gpu
exactly:
deviceClassName: nvidia-mig-2g10gb-mps
count: 1
capacity:
requests:
sharePercent: "25"
config:
- requests: ["gpu"]
opaque:
driver: gpu.deckhouse.io
parameters:
apiVersion: resource.gpu.deckhouse.io/v1alpha1
kind: MigDeviceConfig
sharing:
strategy: MPS
mpsConfig:
defaultActiveThreadPercentage: 25Any share, without specifying a strategy
The selector must stay permissive — do not exclude sharing variants:
apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
name: nvidia-gpu-any
spec:
selectors:
- cel:
expression: |
device.attributes["gpu.deckhouse.io"].vendor == "nvidia" &&
device.attributes["gpu.deckhouse.io"].computeAPI == "CUDA" &&
has(device.attributes["gpu.deckhouse.io"].deviceType) &&
device.attributes["gpu.deckhouse.io"].deviceType == "physical"
---
apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
name: gpu-share
spec:
spec:
devices:
requests:
- name: gpu
exactly:
deviceClassName: nvidia-gpu-any
count: 1
capacity:
requests:
sharePercent: "25"
gpu.deckhouse.io/memory: 1GiVFIO passthrough
apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
name: h100-vfio
spec:
selectors:
- cel:
expression: |
device.attributes["gpu.deckhouse.io"].vendor == "nvidia" &&
has(device.attributes["gpu.deckhouse.io"].productName) &&
device.attributes["gpu.deckhouse.io"].productName.lowerAscii().matches("^.*h100.*$") &&
has(device.attributes["gpu.deckhouse.io"].deviceType) &&
device.attributes["gpu.deckhouse.io"].deviceType == "physical" &&
has(device.attributes["gpu.deckhouse.io"].bareMetal) &&
device.attributes["gpu.deckhouse.io"].bareMetal == true
---
apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
name: h100-vfio
spec:
spec:
devices:
requests:
- name: gpu
exactly:
deviceClassName: h100-vfio
allocationMode: ExactCount
count: 1
config:
- requests: ["gpu"]
opaque:
driver: gpu.deckhouse.io
parameters:
apiVersion: resource.gpu.deckhouse.io/v1alpha1
kind: VfioDeviceConfig
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: h100-vfio
spec:
replicas: 1
selector:
matchLabels:
app: h100-vfio
template:
metadata:
labels:
app: h100-vfio
spec:
nodeSelector:
node.deckhouse.io/gpu-vfio-ready: "true"
resourceClaims:
- name: gpu
resourceClaimTemplateName: h100-vfio
containers:
- name: vfio-consumer
image: busybox:1.36
command: ["/bin/sh", "-c", "ls -l /dev/vfio && sleep infinity"]
resources:
claims:
- name: gpuInside a passthrough container there is no CUDA and no nvidia-smi — only VFIO device nodes.
Manifests for Device Plugin mode
These examples apply to Device Plugin mode (with dra.enabled: false). Sharing is configured per NodeGroup through spec.gpu, and workloads request nvidia.com/gpu.
Exclusive
apiVersion: deckhouse.io/v1
kind: NodeGroup
metadata:
name: gpu-exclusive
spec:
nodeType: Static # Or CloudStatic/CloudEphemeral as needed.
gpu:
sharing: Exclusive
nodeTemplate:
labels:
node-role/gpu: ""
taints:
- key: node-role
value: gpu
effect: NoScheduleTimeSlicing
spec:
gpu:
sharing: TimeSlicing
timeSlicing:
partitionCount: 4MIG
spec:
gpu:
sharing: MIG
mig:
partedConfig: all-1g.5gbFor per-index custom partitioning use partedConfig: custom with customConfigs. See Diagnostics.
Verification run
apiVersion: batch/v1
kind: Job
metadata:
name: cuda-vectoradd
spec:
template:
spec:
restartPolicy: OnFailure
nodeSelector:
node-role/gpu: ""
tolerations:
- key: node-role
value: gpu
effect: NoSchedule
containers:
- name: cuda-vectoradd
image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda11.7.1-ubuntu20.04
resources:
limits:
nvidia.com/gpu: 1