
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Misconfigured Kubernetes Resource Limits and Requests are the silent killers of production stability. You might see pods evicted randomly during traffic spikes, nodes running out of memory despite low CPU usage, or autoscalers failing to trigger because metrics don't match reality. This usually happens when teams treat resource specs as optional metadata rather than strict scheduling contracts. Getting these values right is the difference between a resilient platform and a fragile cluster that requires constant babysitting. For a deeper look at how automation can help manage this complexity, see my guide on using AI to write Terraform and Kubernetes YAML safely.
What is the difference between Kubernetes Resource Limits and Requests?
The distinction between requests and limits is fundamental to how Kubernetes manages workloads, yet it remains one of the most misunderstood concepts in the ecosystem. A request is a reservation. When the scheduler places a pod, it sums the requests of all containers and finds a node with sufficient unallocated capacity. If a node has 4Gi of allocatable memory and existing pods request 3.5Gi, only pods requesting ≤512Mi can land there, regardless of actual current usage. Requests determine where a pod runs.
A limit is an enforcement boundary enforced by the container runtime (containerd/CRI-O) via Linux cgroups. CPU limits throttle the process using CFS quotas; memory limits trigger an OOM kill if exceeded. Limits determine how much a pod can consume at runtime. Crucially, the scheduler does not consider limits when placing pods. You can set a limit higher than available node capacity, but if actual usage hits that limit on a packed node, you risk instability. In production, I always recommend setting requests equal to limits for critical services to eliminate this gap and guarantee resources end-to-end.
CPU vs Memory Behavior Differences
CPU and memory behave differently under constraint, and confusing them causes outages. CPU is compressible: if a container exceeds its CPU limit, the kernel throttles it. The application slows down but stays alive. This makes CPU limits relatively safe to set tightly, though aggressive throttling can increase latency tails. Memory is incompressible: there is no way to "slow down" memory allocation. If a container exceeds its memory limit, the kernel invokes the OOM killer immediately. The pod terminates with exit code 137. This asymmetry means memory requests must be accurate to prevent scheduling onto nodes that cannot satisfy actual demand, while memory limits must include headroom for legitimate spikes.
How do you configure Kubernetes Resource Limits and Requests correctly?
Correct configuration starts with measurement, not guessing. Before writing any YAML, profile your application under realistic load. Use tools like kubectl top pods, Prometheus metrics (container_memory_working_set_bytes, rate(container_cpu_usage_seconds_total)), or VPA in recommendation mode. Set requests to the observed P95 usage plus a safety margin (typically 10–20%). Set limits based on worst-case spike tolerance or business SLAs.
<!-- Production-ready resource spec -->
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "768Mi" # 1.5x request for burst headroom
cpu: "1000m" # Allow burst up to 1 core
Avoid common anti-patterns. Never set memory requests significantly lower than actual baseline usage; this leads to overcommitment and OOM kills during normal operation. Never set CPU limits below measured steady-state usage; this causes artificial latency. For Java/JVM applications, remember that heap size ≠ container memory. The JVM uses additional memory for metaspace, thread stacks, direct buffers, and GC overhead. A 512Mi heap typically needs 768Mi–1Gi container memory. Always use -XX:+UseContainerSupport (default in modern JDKs) and set -XX:MaxRAMPercentage=75.0 rather than fixed -Xmx values to respect container limits dynamically.
- Profile baseline usage under representative load for at least 24 hours
- Set memory request = P95 working set + 15% buffer
- Set memory limit = max observed spike + 25% headroom (or 1.5–2x request)
- Set CPU request = P95 usage + 10% buffer
- Set CPU limit = acceptable burst ceiling (often 2–4x request for web apps)
- Validate with load testing before promoting to production
How do QoS classes affect pod eviction priority?
Kubernetes assigns every pod a Quality of Service (QoS) class based solely on resource specifications. This class determines eviction order during node pressure. Understanding QoS is non-negotiable for reliable Kubernetes Resource Limits and Requests configuration.
| QoS Class | Criteria | Eviction Priority | Use Case |
|---|---|---|---|
| Guaranteed | Limits == Requests for both CPU & memory (or only limits set) | Last (lowest priority) | Databases, critical APIs, payment services |
| Burstable | At least one request/limit set, but not matching | Middle (evicted after BestEffort) | Web apps, workers, batch jobs |
| BestEffort | No requests or limits specified | First (highest priority) | Dev/test only, never production |
In practice, most production clusters should aim for Guaranteed QoS on tier-0 and tier-1 services. Burstable is acceptable for horizontally scalable stateless workloads where individual pod loss is tolerable. BestEffort pods are essentially free compute that vanishes first under pressure; they have no place in SLA-bound systems. During node memory pressure, kubelet evicts pods in reverse QoS order, then by usage relative to requests within the same class. This means a Burstable pod using 2x its request gets evicted before one using exactly its request. Setting accurate requests isn't just about scheduling—it directly impacts survival during resource contention.
How does resource management interact with autoscaling?
Autoscalers depend entirely on accurate resource specifications. The Horizontal Pod Autoscaler (HPA) calculates desired replicas using the formula: desiredReplicas = ceil[currentReplicas * (currentMetricValue / desiredMetricValue)]. If your requests are wrong, HPA scales incorrectly. Example: a deployment with 3 pods requesting 250m CPU each shows 60% utilization at 450m total usage. HPA targeting 70% sees headroom and doesn't scale. But if actual per-pod need is 400m, you're already overloaded. Conversely, inflated requests cause premature scaling and wasted spend. For advanced scenarios, explore predictive autoscaling with machine learning to anticipate demand patterns.
Vertical Pod Autoscaler (VPA) recommends request/limit adjustments based on historical usage. Run VPA in recommendation mode first—never auto-update production workloads without validation. Cluster Autoscaler adds nodes when pending pods cannot be scheduled due to insufficient resources. If requests are too high, CA provisions excess nodes. If too low, pods schedule but fail at runtime. Always align resource specs with observability data. Tools like anomaly detection for metrics help identify drift between configured values and actual behavior before it causes incidents.
Namespace-Level Governance with LimitRanges and ResourceQuotas
Individual pod specs aren't enough. Platform teams must enforce guardrails. LimitRange sets default requests/limits for containers that omit them and enforces min/max bounds per container or pod. ResourceQuota caps total namespace consumption. Without these, a single misconfigured deployment can starve an entire team or blow budgets. In multi-tenant environments—common in Nepal's growing tech sector where startups share clusters—these objects are mandatory for isolation and cost control.
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
spec:
limits:
- default: # Applied if container omits limits
memory: 512Mi
cpu: 500m
defaultRequest: # Applied if container omits requests
memory: 256Mi
cpu: 250m
max: # Hard ceiling per container
memory: 4Gi
cpu: 4
min: # Floor per container
memory: 64Mi
cpu: 50m
type: Container
Implementing Reliable Kubernetes Resource Limits and Requests
Getting Kubernetes Resource Limits and Requests right is an ongoing discipline, not a one-time task. Start by auditing existing workloads with kubectl describe pod and Prometheus queries to find gaps between config and reality. Implement LimitRanges and ResourceQuotas in every namespace before onboarding teams. Use VPA recommendations as input, not gospel. Review values quarterly as applications evolve. Most importantly, treat resource specs as first-class infrastructure code—versioned, reviewed, and tested like any other production artifact. If your team needs help establishing these practices or auditing existing clusters, reach out to discuss your specific environment.