- metrics-server (pod usage via
metrics.k8s.io) - Kubernetes cluster with in-place Pod resize support (
pods/resizesubresource). The operator checks capability and degrades gracefully if unsupported.
helm install resize-operator oci://ghcr.io/iamhalje/charts/resize-operator -n resize-operator-system --create-namespaceOn each reconcile loop the operator:
- selects candidate Pods (namespace selector + pod label selector)
- fetches
PodMetricsfrommetrics.k8s.io - computes desired requests based on the policy
- executes
pods/resize(dry-run + apply) - writes annotations and emits
Resizedevents
%%{init: {'flowchart': {'nodeSpacing': 60, 'rankSpacing': 80}}}%%
flowchart TB
subgraph METRICS["Metrics API"]
MS[metrics-server]
end
subgraph OPERATOR["Resize Operator"]
SEL[Select candidate Pods]
CALC[Compute desired requests]
REC[Write annotations<br/>and emit Resized events]
end
subgraph CONTROL_PLANE["Kubernetes Control Plane"]
APIS[kube-apiserver]
SCHED[scheduler]
end
subgraph NODE["Node"]
KUBELET[kubelet]
end
SEL -->|fetch PodMetrics| MS
MS -->|PodMetrics| CALC
CALC -->|pods/resize<br/>dry-run + apply| APIS
APIS --> KUBELET
KUBELET -->|resource update| SCHED
APIS --> REC
The operator computes new requests based on the current resource usage from metrics.k8s.io, using headroomPercent.
- Target:
target = usage * (1 + headroomPercent/100) - Rounding: CPU is rounded to
50msteps, memory to64Misteps - Small changes are skipped based on:
- relative thresholds
upPercent/downPercent - absolute minimum change
minChangeCPU/minChangeMemory
- relative thresholds
- Bounds: computed
requestsare clamped to configured min/max - Limits behavior is controlled by
limitsMode:Unchanged: keep limits as-isEqualRequests: set limits equal to requests
- Anti-thrash:
stabilizationWindow: the desired target must stay stable before applycooldown: skip pods shortly after a resize
- Grafana dashboard: docs/grafana/resize-operator-dashboard.json
- CRD reference: docs/crd.md