- Kubernetes cluster 1.33.x (verified) — newer minors preferred; limited regression on 1.32/1.31
- Nodes with NVIDIA GPUs
- NVIDIA device plugin installed (for GPU discovery)
- Helm 3 installed
The admission webhook requires TLS certificates to function. Kubernetes mandates HTTPS for admission webhooks.
Quick Setup (Self-Signed):
NAMESPACE=default
# Download and run certificate generation script
curl -sL https://raw.githubusercontent.com/restack/gpu-scheduler/main/hack/gen-webhook-certs.sh | bash -s -- ${NAMESPACE}
# Or manually - see detailed guideProduction Setup (cert-manager):
# Install cert-manager first, then create Certificate resource
# See detailed guide below📖 For detailed certificate setup instructions, see Webhook Certificates Guide
The guide covers:
- Why certificates are required (port 443, HTTPS mandatory)
- Complete certificate generation scripts
- cert-manager setup for production
- Troubleshooting common certificate issues
helm install gpu-scheduler charts/gpu-schedulerOr with custom namespace:
export NAMESPACE=gpu-system
# Don't forget to create certificates in the custom namespace!
# Repeat Step 1 with NAMESPACE=gpu-system
./hack/dev.shCheck that all components are running:
# Check scheduler
kubectl get deploy gpu-scheduler
# Check webhook
kubectl get deploy gpu-scheduler-webhook
# Check agent (should be on each GPU node)
kubectl get daemonset gpu-scheduler-agentCreate a claim for one GPU:
# claim.yaml
apiVersion: gpu.scheduling/v1
kind: GpuClaim
metadata:
name: single-gpu
namespace: gpu-scheduler
spec:
devices:
count: 1
exclusivity: ExclusiveCreate a pod using the claim:
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: gpu-test
namespace: gpu-scheduler
annotations:
gpu.scheduling/claim: single-gpu
spec:
schedulerName: gpu-scheduler
restartPolicy: Never
containers:
- name: cuda-test
image: nvidia/cuda:12.4.1-runtime-ubuntu22.04
command: ["bash","-lc","echo CVD=$CUDA_VISIBLE_DEVICES; nvidia-smi -L && nvidia-smi --query-gpu=index,name,memory.total --format=csv"]
resources:
limits:
nvidia.com/gpu: "1"Apply both:
kubectl apply -f claim.yaml
kubectl apply -f pod.yamlCheck the allocation:
# See which GPU was assigned
kubectl get pod gpu-test -o jsonpath='{.metadata.annotations.gpu\.scheduling/allocated}'
# Output: node-a:0
# Check the pod logs
kubectl logs gpu-testFor workloads needing fast GPU-to-GPU communication:
apiVersion: gpu.scheduling/v1
kind: GpuClaim
metadata:
name: multi-gpu
spec:
devices:
count: 4
policy: contiguous # Prefer GPUs with adjacent IDs
exclusivity: Exclusive
topology:
mode: Preferred # Try to get GPUs in same NVLink island
---
apiVersion: v1
kind: Pod
metadata:
name: training-job
annotations:
gpu.scheduling/claim: multi-gpu
spec:
schedulerName: gpu-scheduler
containers:
- name: training
image: pytorch/pytorch:2.0.0-cuda11.7-cudnn8-runtime
resources:
limits:
nvidia.com/gpu: "4"If you need specific GPU IDs:
apiVersion: gpu.scheduling/v1
kind: GpuClaim
metadata:
name: pinned-gpus
spec:
devices:
count: 2
policy: preferIds
preferIds: [0, 1] # Try to get GPUs 0 and 1
exclusivity: ExclusiveTo target specific nodes:
apiVersion: gpu.scheduling/v1
kind: GpuClaim
metadata:
name: specific-node
spec:
selector:
matchLabels:
gpu-type: a100
topology: nvlink
devices:
count: 8
policy: contiguouskubectl get gpuclaim
# or short form
kubectl get gclaimExample output:
NAME REQ POLICY TOPOLOGY ALLOCATED
single-gpu 1 contiguous node-a:0
multi-gpu 4 contiguous Preferred node-b:0,1,2,3
kubectl get gpunodestatus
# or short form
kubectl get gnsExample output:
NAME NODE DEVICES
node-a node-a 4
node-b node-b 8
Get detailed GPU info for a node:
kubectl get gpunodestatus node-a -o yamlSee which GPUs are currently locked:
kubectl get leases | grep gpu-Example output:
gpu-node-a-0 25s
gpu-node-a-1 25s
gpu-node-b-2 1m
Check scheduler logs:
kubectl logs -l app=gpu-schedulerCommon reasons:
- No nodes with enough free GPUs
- Node selector doesn't match any nodes
- GPU leases stuck (manual cleanup needed)
Error message:
Internal error occurred: failed calling webhook "pods.gpu-scheduler.svc":
failed to call webhook: Post "https://gpu-scheduler-webhook.default.svc:443/mutate?timeout=10s":
no endpoints available for service "gpu-scheduler-webhook"
This usually means TLS certificates are missing or the webhook pod isn't running.
Quick diagnosis:
# Check webhook pod
kubectl get pods -l app=gpu-scheduler-webhook
# Check certificate secret
kubectl get secret gpu-scheduler-webhook-cert
# Check logs
kubectl logs -l app=gpu-scheduler-webhookFix: If the certificate secret is missing, generate certificates following Step 1.
📖 For detailed troubleshooting, see Webhook Certificates Guide - Troubleshooting
Key points:
- Port 443 is mandatory (Kubernetes requirement)
- HTTPS/TLS is required (not optional)
- API server calls the webhook (not the agent)
Check if the annotation was set:
kubectl get pod <pod-name> -o jsonpath='{.metadata.annotations}'Should see both:
gpu.scheduling/claim: <claim-name>gpu.scheduling/allocated: <node>:<gpu-ids>
Check webhook logs:
kubectl logs -l app=gpu-scheduler-webhookDescribe the pod and check environment variables:
kubectl get pod <pod-name> -o jsonpath='{.spec.containers[0].env}'Should see:
[{"name":"CUDA_VISIBLE_DEVICES","value":"0,1"}]If GPUs are locked but no pods are using them:
# List all GPU leases
kubectl get leases | grep gpu-
# Delete a specific lease
kubectl delete lease gpu-node-a-0
# Delete all GPU leases (caution!)
kubectl delete leases -l gpu.scheduling/managed=truespec:
devices:
count: 1
exclusivity: Shared # Multiple pods can share the GPUWarning: Shared mode doesn't enforce memory limits. Pods can interfere with each other.
For tight coupling requiring high bandwidth:
spec:
topology:
mode: Required # Fail if topology requirements not met
minBandwidthGBps: 600 # Require NVLink speedModes:
- Required: Pod won't schedule if requirements not met
- Preferred: Try to meet requirements, but schedule anyway (default)
- Ignore: Don't consider topology at all
- Always specify exclusivity: Use
Exclusiveunless you have a good reason - Use contiguous policy for multi-GPU: Better performance for workloads with GPU-to-GPU communication
- Set resource limits: Always include
resources.limits.nvidia.com/gpu - Name claims descriptively: Use names like
training-4gpunotclaim1 - Clean up claims: Delete GpuClaim resources when done to avoid confusion
# Delete the Helm release
helm uninstall gpu-scheduler
# Clean up CRDs (this deletes all GpuClaims and GpuNodeStatus)
kubectl delete crd gpuclaims.gpu.scheduling
kubectl delete crd gpunodestatuses.gpu.scheduling
# Clean up any remaining leases
kubectl delete leases -l gpu.scheduling/managed=true