Green Computing and Container Efficiency: Carbon-Aware Clusters
Resource requests and limits are the foundation of Kubernetes efficiency — and of your power bill. A practical path from right-sizing and bin-packing to scale-to-zero and carbon-aware scheduling, with the trade-offs spelled out.
Published on • November 15, 2026
AI Assistant

Every idle core in a datacenter is still drawing power. The cloud-native industry spent a decade learning to pack workloads tightly and call the result “efficiency” — but efficiency is only half a metric: it is cost per unit of work and energy per unit of work, and for once those two point in the same direction. The interesting question in 2026 is no longer whether to right-size a Deployment, but whether your scheduler knows anything about the carbon intensity of the electricity it is spending. This post walks the ladder from the basics that every cluster already has — resource requests — up to carbon-aware scheduling, and is honest about what each rung costs you.
The foundation: requests, limits, and QoS
The Kubernetes resource management documentation is the canonical reference, and everything else in this article builds on it:
resources.requestsis what the scheduler uses to place the Pod (fitting it onto a node with room) and what the kubelet uses for cgroup reservations. It also determines the Pod QoS class: Guaranteed (requests == limits for every container), Burstable (some values set), BestEffort (none).resources.limitsis the hard cgroup ceiling. CPU limit throttles the container; memory limit OOM-kills it.
The two classic waste modes map directly onto power. Over-requested requests reserve capacity that sits idle — a fleet of Pods requesting 4 cores while using 0.6 means your nodes are full of reserved nothing, and full nodes of reserved nothing are still consuming watts. Missing limits means one runaway container evicts its neighbors (memory) or throttles them into latency violations (CPU), which in practice makes teams over-request “just to be safe,” and the waste compounds.
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"
Namespace-level guardrails — LimitRanges for defaults and min/max, ResourceQuotas per namespace — are the enforcement layer that keeps good intentions from decaying back into cpu: "4" on a sidecar.
Right-sizing: from guessing to measurement
Requests should be derived from observed usage, and the tooling ladder looks like this:
- Measure.
kubectl top pods(metrics-server) plus a real Prometheus stack withcontainer_cpu_usage_seconds_totalandcontainer_memory_working_set_bytes. Look at p95 usage over two weeks, not the mean. - Recommend. VPA’s recommender produces per-container request suggestions; run it in recommendation-only mode first so you can review what it would change.
- Apply. Historically, changing a request meant a restart. The in-place Pod resize API — documented under “Resize CPU and Memory Resources assigned to Containers” — now lets you grow (and, more cautiously, shrink) CPU and memory requests without recreating the Pod, which removes the biggest operational objection to aggressive right-sizing.
- Guard. Keep a limit above p99, or drop CPU limits entirely if you prefer burst behavior and rely on node-level fairness (a real, ongoing design debate — pick deliberately, don’t inherit by accident).
The payoff is compounding: smaller requests mean the scheduler fits more Pods per node, which means fewer nodes, which means less idle silicon.
Bin-packing: fewer, fuller nodes
The scheduler’s NodeResourcesFit plugin scores nodes on how much of their requested resources are already used. The default strategy favors spreading (LeastAllocated); for efficiency you explicitly configure MostAllocated — this is what the Resource Bin Packing documentation describes:
scoringStrategy:
type: MostAllocated
resources:
- name: cpu
weight: 2
- name: memory
weight: 1
Pair that with cluster autoscaler or Karpenter scaling down: consolidation only reclaims power if empty nodes actually get deleted. Topology spread constraints and PodDisruptionBudgets are the counterweights — packing harder shrinks your failure domain radius, and a node failure that takes out 30% of a service’s replicas is an efficiency win with an availability invoice attached.
Scale-to-zero
For anything with a traffic shape that includes real zeros — batch, staging, webhooks, internal tools — the biggest energy saving is not a smaller container, it is no container:
- KEDA scales a workload from
minReplicaCount: 0based on a trigger (Prometheus, cron, queues, cloud events). Scale-to-zero works cleanly for queue-driven work. - HTTP scale-to-zero (KEDA’s HTTP add-on, Knative’s activator pattern) needs an in-cluster component to hold connections and cold-start the workload — which is a latency trade, not a free lunch.
- Cron-shaped workloads should be
CronJobs or KEDA cron triggers, not Deployments with replicas pinned at 1 “because.”
Cold start is the tax: image pull (mitigated by pre-pulled images and smaller images), container start, and application warm-up. Measure it before promising anything to an SLO owner.
Carbon-aware scheduling
Everything above reduces joules per unit of work. Carbon-aware scheduling changes when and where the work runs, exploiting the fact that grid carbon intensity varies by region and by hour — a batch job at 2 p.m. in a coal-heavy region emits far more CO₂ than the same job at 3 a.m. when wind is running.
The patterns, in increasing order of invasiveness:
- Deferral. Batch and training jobs queue up and run when intensity is low (or price is low — the scheduling math is identical). Google’s carbon-intelligent computing platform has run this play in production at datacenter scale since 2020: shift interruptible load toward cleaner windows and grids.
- Placement. Feed carbon intensity as a scheduler score or a constraint. Community scheduler plugins do this against providers like Electricity Maps or WattTime; the PEAKS scheduler plugin takes the related route of scoring nodes by power efficiency using Kepler’s energy metrics.
- Topology and regions. If your fleet spans regions, make carbon part of the same decision you already make about latency and data residency — some workloads can simply move.
Tools like KEDA handle the scaling half; the deferral half usually means a queue with a carbon-aware consumer, or a job controller that checks intensity before admitting work.
Energy metrics: what you can actually measure today
Be warned: the Kubernetes metrics API reports usage, not watts. Millicores and bytes tell you utilization; they do not tell you joules. Power data comes from elsewhere:
- Kepler (sustainable-computing.io) models per-container power from RAPL counters, eBPF-observed cycles and hardware counters, exporting Prometheus metrics. Its granularity story matters: node-level estimates are solid, per-container attribution is modeled.
- Out-of-band telemetry — Redfish/IPMI/BMC power reading, plus vendor exporters — gives you ground truth for the racks.
- GPU power is measurable and often dominant in AI fleets:
nvidia-smi -pl(power capping) and DCGM metrics are where that work happens. - For reporting rather than scheduling, the Green Software Foundation’s Software Carbon Intensity (SCI) specification gives you a formula: carbon per functional unit, so you can put an efficiency number on a release instead of a cluster.
The gap — no standardized, in-tree power metric the scheduler can consume — is why carbon-aware scheduling today is a plugin or a queue discipline, not a flag.
The trade-offs nobody puts in the demo
- Bin-packing vs blast radius. Fuller nodes mean fewer failure domains and higher utilization; you are trading redundancy for watts. Encode the intent with topology spread and PDBs rather than hoping.
- Scale-to-zero vs latency. A cold-started webhook is a slow webhook. Keep warm replicas for anything on the request path; zero out the batch and the staging.
- Carbon deferral vs SLA. A deferral window is a promise you make to your own product team. Only shift work that is genuinely interruptible, and publish the window.
- BestEffort is a trap. Dropping requests to zero to “save power” puts you in BestEffort QoS — first in line for eviction under node pressure. Efficiency should move you to accurate requests, not absent ones.
- Consolidation vs spot churn. Aggressive consolidation plus spot capacity saves money and carbon per hour, then pays it back in replacement work when capacity is reclaimed. Measure net, not gross.
A practical sequence
- Fix requests/limits with two weeks of p95 data; add LimitRanges so the baseline cannot regress.
- Turn on VPA recommendations; adopt in-place resize for the steady-state fleet.
- Switch bin-packing scoring, enable autoscaler scale-down, and watch failure-domain metrics while you do.
- Identify workloads with real zeros; KEDA to zero for queue work, cron discipline for periodic work.
- Instrument what you can (Kepler or BMC power), then move one genuinely interruptible batch pipeline onto a carbon-intensity signal.
Steps 1–3 pay for themselves in cloud spend before you mention carbon to anyone. Steps 4–5 are where the sustainability story gets real.
Wrapping up
Green computing in Kubernetes is not a separate initiative bolted onto FinOps — it is the same discipline with a second unit attached. Requests and limits are the foundation because an accurately-sized fleet is both cheaper and less power-hungry; bin-packing and scale-to-zero turn that into fewer, fuller, sometimes empty nodes; and carbon-aware scheduling is the point where your cluster starts responding to the grid it is plugged into. The honest constraint is that every step trades against availability or latency, so the work is less “enable the feature” and more “decide, per workload, which trade you are willing to make.”
References
- Kubernetes: Resource Management for Pods and Containers
- Kubernetes: Resource Bin Packing
- Kubernetes: Vertical Pod Autoscaling
- KEDA documentation — scaling deployments, activation and scale to zero
- Kepler — Kubernetes-based power modeling
- Green Software Foundation — Software Carbon Intensity specification