SLO-safe density & overcommit

Kernel enforcement makes tight packing safe; the optional L1 layer converts that safety into capacity. Both components are off by default — complement mode — and each is one helm flag away.

Complement mode (the default)

Out of the box, Temper does not touch placement. Karpenter, Cast AI, Cluster Autoscaler, or the stock scheduler decide where pods go; Temper decides who gets the CPU once they share a node. This is deliberate: the node engine needs only Kubernetes-native inputs, so it works under any placer, and your existing tool’s aggressive mode stops being scary — the blast radius of a wrong prediction becomes batch throughput, not the p99 of a revenue service.

This composition has been measured with Karpenter running the autoscaling in both arms — Temper made the tighter packing hold at equal load and SLO (deep dive: sideloading).

# complement mode is simply the default:
helm install temper deploy/helm/temper -n temper --create-namespace
# scheduler.enabled=false, webhook.enabled=false

The density-aware scheduler plugin

When you do want Temper placing pods, the scheduler plugin extends kube-scheduler with awareness of L0’s enforcement state. It reads the per-tier load annotations every agent publishes (pod counts and CPU millis per tier) and scores nodes by where protection capacity actually exists — contention-aware for latency-critical pods, packing-aware for batch.

helm upgrade temper deploy/helm/temper --reuse-values \
  --set scheduler.enabled=true

The overcommit webhook

Kubernetes bin-packs by declared CPU requests, which are usually padded. The overcommit webhook shrinks that padding where it is safe:

helm upgrade temper deploy/helm/temper --reuse-values \
  --set webhook.enabled=true

kubectl label namespace batch temper.codes/overcommit=enabled

Why this is safe with Temper underneath and reckless without it: overcommitting requests means more runnable threads per node, which under CFS translates directly into latency-critical tail damage. With the kernel fence in place, the extra pressure lands on the Open layers — batch absorbs it, protected tiers do not.

Measured results

The packing, consolidation, and Karpenter-composition measurements — with their methodology and the caveats that travel with each number — are collected in deep dive: sideloading (“Turning protection into capacity”).

Undoing it

Remove the namespace label to stop new mutations; already-admitted pods carry their original request values in annotations and pick them back up on the next rollout. The whole layer can be stood down with webhook.enabled=false / scheduler.enabled=false without touching L0 enforcement.