KubeOn GPU
Every GPU busy, shared or switched off
KubeOn GPU measures every GPU-hour, then its opt-in optimizer acts on what it finds: MIG and time-slicing for workloads that need part of a card, GPU nodes that scale and pack with demand, burst capacity from other regions, clouds or your data center, and idle GPUs scaled to zero. Each policy runs as a proposal, with an approval, or automatically within limits you set.
The problem
Allocated is not used
GPUs are the fastest-growing line on many cloud bills, and published research on shared clusters shows how much of that capacity sits idle or barely busy.
14%
of EC2 compute spend went to GPU instances across Datadog's customers, up from 10% a year earlier
Datadog, State of Cloud Costs 2024~52%
average utilization of the GPUs in use in a large multi-tenant training cluster at Microsoft
Jeon et al., USENIX ATC 20190.042
of a GPU: the median task's use in Alibaba's production cluster of over 6,000 GPUs
Weng et al., USENIX NSDI 202274% / 18%
of GPUs allocated, against average GPU utilization, on one group of Alibaba machines
Weng et al., USENIX NSDI 2022The optimizer
Four ways it puts GPUs to work
Step through each one on sample clusters: what the optimizer saw, what it did, and what it logged.
Whole GPUs, barely used
- dc1-gpu-07embed-svc6%
- dc1-gpu-08classify-svc9%
- dc1-gpu-09ocr-svc5%
GPU optimizer
Policy dc1-mig, Approve mode
- 1Find GPUs under 10%
- 2Choose the slice that fits
- 3Wait for your approval
- 4Repartition in the change window
After
- dc1-gpu-07Three services on MIG slicesShared
- dc1-gpu-08Back in the poolFree
- dc1-gpu-09Back in the poolFree
- SavedTwo A100s at the rate card-$1,723/mo
An inference pool at its peak
- GPU pods waitingprod-use1-a, ml-inference
- Two nodes, fullOn-demand L40S82%
- Your limits1 to 6 nodes, under $40,000 a month
GPU optimizer
Policy ml-inference-autoscaling, Automatic
- 1Demand outgrows the pool
- 2Add Spot first
- 3On-demand if Spot is reclaimed
- 4Pack and shrink after the peak
After
- Spot node addedPods stop waiting
- On-demand steps inWhen Spot is reclaimed
- Packed in the eveningOnly in its window
- SavedOne node removed after the peak-$8,433/mo
A region out of GPUs
- eu-west-1, homeNo L40S available
- Pods waitingOnly those that tolerate the burst taint4
- Allowed locationsEU only: eu-central-1, dc1
GPU optimizer
Policy inference-burst-eu, Approve mode
- 1The home region runs out
- 2Compare allowed locations
- 3Wait for your approval
- 4Attach, then return
After
- GPU nodes attachedIn an allowed EU location
- Pods servedWhile eu-west-1 is out of L40S4
- Back homeBurst nodes go when capacity returns
Notebooks left running
- ml-notebooksUnder 2% GPU for 30 minutes
- Only what you listNamespaces in your policy
GPU optimizer
Policy notebooks-scale-to-zero, Automatic
- 1Find idle workloads
- 2Scale them to zero
- 3Remove empty nodes
- 4Wake on schedule
After
- Idle hours offEvery week103
- Awake againMonday to Friday, 07:00 UTC
- SavedWithout touching busy work-$1,042/mo
Control
You choose how far each policy goes
Every policy starts as a proposal. Move it to Approve, then Automatic, when its proposals have earned your trust.
- Installed only in clusters you choose, as its own Helm release, separate from the read-only agent
- Acts only on the node pools and namespaces a policy names; everything else is out of reach
- Hard limits per policy: minimum and maximum nodes, monthly cost, GPU-hour price
- Disruptive steps such as drains and repartitions run only in the policy's change window
- Evicts through the Eviction API, so PodDisruptionBudgets are always respected
- No access to Secrets or ConfigMaps outside the GPU Operator config it manages
- Pulls policies and approvals from the hub over HTTPS; the hub never connects into your cluster
- Every action in the audit log with the policy that allowed it, and a one-click revert where the change can be undone
Mode 1
Recommend · A proposal, nothing else
The optimizer writes the change as a proposal with its evidence and patch. Your pipeline applies it, like other KubeOn proposals. Every policy starts here.
Mode 2
Approve · Approve once, the optimizer applies
Each change waits for a named reviewer. Once approved, the optimizer applies it in the policy's change window and records the outcome.
Mode 3
Automatic · Acts within the limits you set
The optimizer acts on its own, but only on the node pools and namespaces the policy names, within its node, cost and time limits.
Where the GPU savings are
saved by removing one GPU node after the peak at our sample company
Sample company, not a customer result
KubeOn GPU modules
Five areas, one GPU optimizer
Part of KubeOn
MIG partitions and time-slicing, applied for workloads that use part of a GPU
GPU nodes added on demand, spot first, packed tight and scaled to zero when idle
GPUs from other regions, clouds or your data center when the home region runs out
GPU node cost by team, idle GPU time and real utilization
GPU-hour rates for servers you own, shared and used before you buy more
Where it works
Cloud GPUs and the ones you own
Cloud GPUs are priced from your billing export, owned GPUs from a rate card. The optimizer drives Karpenter or your cloud's node groups and the NVIDIA GPU Operator, and reports every action to KubeOn.
- Amazon EKS
- Azure Kubernetes Service
- Google Kubernetes Engine
- Red Hat OpenShift
- Kubernetes on VMware or bare metal
- NVIDIA GPU Operator and device plugin
- NVIDIA DCGM exporter
- Karpenter and managed node groups
Published permissions
What the optimizer may change, in the open
The optimizer is the only KubeOn component with write access, and only in clusters where you install it. Its ClusterRole is published here and on the security page, so your security team can review it first. It never reads Secrets.
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: kubeon-gpu-optimizerrules: # Read what it optimizes - apiGroups: [""] resources: [nodes, pods, namespaces] verbs: [get, list, watch] - apiGroups: [apps] resources: [deployments, statefulsets, replicasets] verbs: [get, list, watch] - apiGroups: [policy] resources: [poddisruptionbudgets] verbs: [get, list, watch] # Label, taint and cordon GPU nodes; drain through the Eviction API - apiGroups: [""] resources: [nodes] verbs: [patch] - apiGroups: [""] resources: [pods/eviction] verbs: [create] # Add and remove GPU capacity through Karpenter - apiGroups: [karpenter.sh] resources: [nodepools, nodeclaims] verbs: [get, list, watch, create, patch, delete] # Its own policies, synced from the hub, and their status - apiGroups: [gpu.kubeon.io] resources: [gpupolicies, gpupolicies/status] verbs: [get, list, watch, create, update, patch, delete]---# Created only in namespaces named by a ScaleToZero policykind: Rolerules: - apiGroups: [apps] resources: [deployments/scale, statefulsets/scale] verbs: [get, patch]---# In the gpu-operator namespace, for time-slicing onlykind: Rolerules: - apiGroups: [""] resources: [configmaps] resourceNames: [time-slicing-config] verbs: [get, patch]KubeOn GPU: your questions answered
See what KubeOn GPU does for your fleet.
Tell us about your GPU fleet and we will plan the rollout with you, starting with what the optimizer would propose.