Right Sizing 101 Requests Limits QoS and Scheduling Part 1
How to set Kubernetes resource requests and limits, QoS classes, and right-sizing workflow to improve scheduling, reduce costs, and prevent evictions and OOM failures
Beyond big-picture platform architecture, this lesson covers something that affects every Pod you deploy: how to tell Kubernetes what your workload actually needs. Here you’ll learn the difference between resource requests and limits, how to configure them correctly, how Kubernetes assigns QoS classes, and the eviction order under memory pressure. You’ll also get a practical right-sizing workflow to reduce cost and improve reliability.
Problem summary: developers must deploy services but often don’t know the right CPU/memory values. They guess—and guessing typically goes two ways: overprovision “just to be safe,” or underprovision and hope the workload holds.
Real-world example: an e‑commerce company with 200 microservices on Kubernetes saw a 40% quarterly AWS bill increase even though traffic and revenue didn’t grow proportionally. Investigation revealed many Pods requested 8 CPUs but used only ~0.2 CPU on average.
That’s 40× overprovisioning per Pod.Why that costs money: the scheduler uses resource requests (not instantaneous usage) when placing Pods. If a Pod requests 8 CPUs, the scheduler reserves those 8 CPUs on the node for placement decisions. Those reserved CPUs can’t be used by other Pods, and the autoscaler may add nodes to satisfy requested capacity—driving cloud spend up.
Conversely, omitting limits can be catastrophic during traffic spikes (Black Friday or viral campaigns). A container that consumes free memory can exhaust node RAM. When node memory runs out, the kernel may invoke the OOM killer and Kubernetes marks Pods as OOMKilled—often at the worst possible moment.
Without proper sizing you get three main operational problems:
The scheduler makes poor placement decisions because requests are inaccurate.
Pods are evicted unpredictably because limits/requests weren’t planned.
Nodes become either starved (no capacity) or idle (wasted capacity), increasing risk or cost.
Enforce a maximum resource limit per namespace with ResourceQuota.
Require memory limits for containers (memory overcommit is unforgiving).
Right-size using real usage metrics and iterate.
Important clarification: Kubernetes is not aware of your workload’s true needs unless you tell it. The scheduler relies entirely on resource requests for placement decisions. If you omit requests, the scheduler treats the container as claiming zero resources—potentially causing noisy-neighbor problems by scheduling Pods onto already highly utilized nodes. If you omit limits, a container can consume unbounded CPU (subject to CPU isolation behavior) or memory at runtime, affecting co-located workloads.A runaway process (memory leak or unbounded allocation) without limits can crash other workloads on the node. When a Pod has neither requests nor limits defined, it receives the BestEffort QoS class and is the first to be evicted under resource pressure.
Kubernetes needs explicit resource hints. Quick recap of why each field matters:
requests: used by the scheduler to decide Pod placement (affects packing and cluster autoscaler behavior).
limits: enforced by the kubelet via cgroups. For CPU, exceeding the limit results in throttling; for memory, exceeding the limit results in an OOM kill.
defaults: Kubernetes does not apply automatic sensible defaults; use LimitRange to inject defaults per namespace and ResourceQuota/admission controls to enforce policies.
Best practice: enforce platform-wide defaults using LimitRange and control consumption with ResourceQuota. Combine these with observability to make data-driven adjustments rather than guessing.
Quick reference: QoS class rules
QoS Class
Rule / How assigned
Eviction priority
Guaranteed
Every container sets both requests and limits, and for each resource the request equals the limit (e.g. cpu: "200m" and cpu: "200m").
Last to be evicted
Burstable
At least one container sets a request or limit, but Pod is not Guaranteed (requests < limits or only some containers define them).
Middle priority
BestEffort
No container specifies any requests or limits.
First to be evicted
Example Pod spec with sensible requests and limits:
Memory limits are critical. Exceeding memory triggers OOM kills that can cascade into customer-visible failures—so require memory limits and monitor tail latencies and OOM events.
Platform defaults: use LimitRange to inject conservative requests and limits automatically; add ResourceQuota per namespace to cap consumption.
Deploy and collect telemetry: gather CPU, memory, latency, and error-rate metrics over representative traffic patterns (including peaks).
Analyze percentiles: review P50/P95/P99 and tail behavior. Set requests to cover steady-state usage (e.g., P50/P95 depending on tolerance) and limits to protect the node and bound peak behavior.
Automate and iterate: use Horizontal Pod Autoscaler (HPA) for CPU or custom metrics; for memory patterns consider Vertical Pod Autoscaler or automated recommendations. Reassess after major releases and periodically.
In short: this is primarily a governance + observability problem. Provide explicit, sensible resource requests and limits and enforce them at the platform level. Use telemetry to right-size iteratively so the scheduler can make good placement decisions and your cluster remains stable and cost-effective.Links and references