Kubernetes Requests, Limits, and Scheduling
Resource settings are the most common source of quiet Kubernetes trouble. Pods sit in Pending because no node has room for what they asked for. A latency-sensitive service slows down under load even though its node is half idle, because its CPU limit throttles it. A Java process restarts every few hours with OOMKilled. During a busy afternoon, the kubelet evicts a batch of pods to protect a node. All of these come from two small fields on every container — requests and limits — and how the scheduler and the kubelet interpret them.
This page explains what each field does, how they combine into quality-of-service classes, and how to find the cause when workloads will not schedule, run slowly, or get killed.
TL;DR
- Requests are what the scheduler reserves on a node; limits are what the kubelet enforces at runtime.
- Exceeding a CPU limit causes throttling; exceeding a memory limit causes an OOM kill (exit code 137).
- Requests and limits determine the QoS class — Guaranteed, Burstable, or BestEffort — which sets eviction order under node pressure.
- Pods stay Pending when no node satisfies their requests, taints, affinity, or topology rules; events say which.
- LimitRanges set defaults per namespace; ResourceQuotas cap a namespace's total.
- Base requests on measured usage, set memory limits, and treat CPU limits as a deliberate choice rather than a default.
Quick Example
A container with explicit requests and limits:
Diagnosing why a pod is not running:
A FailedScheduling event such as 0/6 nodes are available: 4 Insufficient memory, 2 node(s) had untolerated taint says exactly which constraint failed on how many nodes.
Core Concepts
Requests and Limits
The scheduler only looks at requests, never at actual usage. A node full of pods that request a lot but use little looks full to the scheduler; pods that request little but use a lot overload nodes the scheduler thinks are empty.
CPU Throttling and Memory OOM Kills
CPU is compressible: a container that hits its CPU limit is throttled — paused for the rest of each scheduling period — which shows up as latency, not errors. Memory is incompressible: a container that exceeds its memory limit is killed by the kernel's OOM killer, reported as OOMKilled with exit code 137. Runtimes such as the JVM, Node.js, and Go need their heap or memory settings aligned with the container limit, or they will be killed before they garbage collect.
QoS Classes and Eviction
When a node runs low on memory or disk, the kubelet evicts pods to protect the node, starting with pods using the most above their requests. Evicted pods show status Evicted with a reason such as The node was low on resource: memory.
Namespace Guardrails
- LimitRange sets default requests and limits for containers that omit them, plus minimums and maximums.
- ResourceQuota caps total requests, limits, and object counts in a namespace. When a quota applies, pods without requests are rejected — a frequent surprise in new namespaces.
Scheduling Constraints
Pending pods often fail several constraints at once; the event message lists them all. Cluster autoscalers add nodes only when a pending pod would fit on a new node — pods with impossible constraints stay pending forever. See Kubernetes Autoscaling.
Choosing Values
- Measure first: use metrics of actual CPU and memory over representative periods, including peaks, or the Vertical Pod Autoscaler in recommendation mode.
- Memory: set requests near typical usage and limits with headroom above observed peaks; set runtime heap sizes relative to the limit.
- CPU requests: set them to the sustained usage you need guaranteed under contention.
- CPU limits: many teams omit them for latency-sensitive services to avoid throttling while still relying on requests for fairness; others require them for multi-tenant fairness or predictable billing. Decide per cluster, and watch throttling metrics either way.
- Revisit after changes: new features, traffic growth, and runtime upgrades shift resource profiles.
Best Practices
Always Set Requests
Without requests, the scheduler packs pods blindly and the pods become BestEffort — first to be evicted.
Always Set Memory Limits
Unbounded memory lets one leaking pod destabilize a whole node. A memory limit contains the damage to that container.
Watch Throttling, Not Just Utilization
A container can be throttled at 40% average CPU if it bursts. Track container_cpu_cfs_throttled_periods_total against total periods for latency-sensitive services.
Use Quotas and Defaults Per Namespace
Give every team namespace a LimitRange and ResourceQuota so forgotten settings get sensible defaults and no team can consume a cluster. See Kubernetes Multi-Tenant Isolation.
Common Mistakes
Requests Copied From a Template
JVM Heap Larger Than the Limit
Tight CPU Limits on Latency-Sensitive Services
FAQ
What is the difference between requests and limits in Kubernetes?
Requests are the resources the scheduler reserves for a container when placing it on a node. Limits are the maximum resources the container may use at runtime; exceeding the CPU limit causes throttling, and exceeding the memory limit causes the container to be killed.
Why is my pod stuck in Pending?
Usually because no node satisfies its requests or scheduling constraints — insufficient CPU or memory, untolerated taints, affinity rules, topology spread, or volume zone restrictions. kubectl describe pod shows the scheduler's reason in Events.
What does OOMKilled mean?
The container exceeded its memory limit and the kernel killed it. Check memory usage trends, raise the limit if usage is legitimate, or fix leaks and runtime memory settings.
Should I set CPU limits?
It depends. CPU limits cause throttling even when nodes have idle CPU, which hurts latency-sensitive services. Many teams set accurate CPU requests and omit limits, while others require limits for fairness in shared clusters. Monitor throttling whichever you choose.
What are QoS classes?
Guaranteed, Burstable, and BestEffort, derived from requests and limits. They decide which pods the kubelet evicts first when a node runs out of memory or disk: BestEffort first, Guaranteed last.
Related Topics
- Kubernetes — Cluster concepts and architecture
- Kubernetes Workloads — Deployments, StatefulSets, and Jobs
- Kubernetes Autoscaling — HPA, VPA, and cluster autoscaling
- Kubernetes Troubleshooting — Diagnosing failing workloads
- Capacity Planning — Sizing clusters for demand
- Linux Performance Troubleshooting — CPU and memory at the node level