Set Kubernetes Resource Requests and Limits
Choose CPU and memory requests from measured usage, set limits that prevent noisy neighbors, and verify QoS, throttling, and OOM behavior.
Task
Give the scheduler enough information to place pods correctly and bound each container's resource use without causing avoidable throttling or evictions.
When to use this
Pods have no requests or limits. One leaking container consumes a node's memory, other pods are evicted, and the scheduler cannot tell how much capacity the workload needs.
Prerequisites
- A Kubernetes deployment with measured CPU and memory usage
- A namespace with a LimitRange or a team policy for resource defaults
- A load test that represents expected traffic
Steps
1. Set memory requests close to steady-state usage and limits above the observed peak, with a safety margin.
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"
Expected output: The scheduler reserves 250m CPU and 256Mi per pod; the container cannot exceed 512Mi memory.
2. Choose a QoS class deliberately: requests equal to limits gives Guaranteed; memory-only equality gives Burstable; no requests gives BestEffort.
kubectl get pod POD -o jsonpath='{.status.qosClass}'Expected output: The pod's QoS class matches the intended isolation level.
3. Load-test and observe throttling, OOM kills, and scheduling behavior.
kubectl top pod POD && kubectl describe pod POD | grep -A3 'Last State'Expected output: CPU throttling and memory OOM events are visible and within the design.
Troubleshooting
Problem
Pods are OOMKilled under load
Solution
The memory limit is below the real peak or the application leaks. Profile memory and set the limit from evidence, not from a guess.
Problem
CPU throttling despite low average usage
Solution
CPU limits are enforced per period; a bursty workload can be throttled at the limit. Raise the limit or remove the CPU limit if the policy allows.
Limitations
- Limits do not replace application-level backpressure or memory bounds.
- Guaranteed QoS consumes more reserved capacity and may reduce bin-packing efficiency.
Requests schedule, limits enforce
Requests tell the scheduler how much CPU and memory to reserve. Limits tell the kernel and kubelet the maximum a container may use. Without requests, the scheduler is blind; without limits, one container can consume a node. Set both from measurements, not from a generic template.
resources:
requests: { cpu: "250m", memory: "256Mi" }
limits: { cpu: "1", memory: "512Mi" }
Memory limits are hard: exceeding them triggers an OOM kill, often with exit code 137. CPU limits are enforced by throttling, which can add latency to bursty workloads even when average usage is low. Understand the difference before copying a template.
Choose QoS intentionally
Requests equal to limits for both CPU and memory gives Guaranteed QoS. Memory-only equality gives Burstable. No requests gives BestEffort, which is the first to be evicted under node pressure. A mixed policy is fine, but document which workloads get guaranteed capacity and why.
Verify under load
Run the workload at expected peak, watch kubectl top, CPU throttling metrics, and OOM events. A pod that runs close to its memory limit will fail during a traffic spike or a large request. Use a HorizontalPodAutoscaler for variable load, and a PodDisruptionBudget to protect availability during voluntary disruptions.