Configure resource requests and limits
Configure resource requests and limits for Kubernetes pods. This hands-on tutorial covers core concepts, step-by-step setup, best practices, and troubleshooting to optimize cluster performance.
Focus: configure resource requests and limits
You’ve spent hours crafting the perfect Dockerfile, your pod is running—and then the node runs out of memory. Without resource requests and limits, Kubernetes treats every container like it can hog as much CPU and RAM as it wants, turning your carefully scheduled cluster into a chaotic free-for-all. In this lesson, you’ll learn how to configure resource requests and limits to guarantee every pod gets the resources it needs without starving its neighbors—a critical skill for any production-grade Kubernetes deployment.
The problem this lesson solves
Picture this: you deploy a memory-hungry microservice next to your main API. The API runs fine for hours, then suddenly latency spikes, requests time out, and the node starts evicting pods left and right. Without explicit resource constraints, Kubernetes cannot prevent one noisy container from consuming the entire node’s CPU or memory. This manifests as:
- Pod throttling – CPU-starved containers run at a crawl.
- OOM kills – The Out-Of-Memory killer terminates processes, causing crashes.
- Node pressure – The scheduler may place too many pods on one node, leading to resource contention.
- Unpredictable billing – In cloud environments, burstable instances cost more than you planned.
Resource requests and limits give you a contract between your pod and the node. They tell the scheduler exactly how much to reserve (request) and the maximum the container is allowed to burst to (limit).
Core concept / mental model
Think of a pod as a tenant in an apartment building.
- Resource request is the rented space – the minimum amount of CPU and memory that the node must guarantee. If the building has 10 apartments, each requesting 1 CPU core, the landlord (scheduler) will never overbook beyond 10 pods.
- Resource limit is the maximum occupancy – your container can temporarily use more than its request, but only up to the limit. If you try to host 20 people in a 2-person apartment, the fire marshal (kubelet) will evict the extra people (or kill the container).
Key definitions
requests.cpu– Guaranteed CPU (in millicores, e.g.,500m). Scheduler uses this for placement.requests.memory– Guaranteed memory (e.g.,256Mi). Used for Quality of Service (QoS).limits.cpu– Hard ceiling for CPU time; throttling above this.limits.memory– Hard ceiling for memory; OOM kill if exceeded.
Pro tip: A pod is assigned a QoS class (Guaranteed, Burstable, BestEffort) based on whether requests == limits.
Guaranteedpods are last to be evicted under pressure.
How it works step by step
- Scheduler admission – When you create a pod with
resources.requests, the scheduler checks if a node has enough allocatable resources to meet the sum of all requests already placed. If not, the pod staysPending. - kubelet enforcement – Once on a node, the kubelet uses cgroups to enforce limits. CPU is throttled (slowed) above the limit; memory is hard-killed if usage exceeds the limit.
- Eviction – Under node memory pressure, the kubelet evicts BestEffort pods first, then Burstable, then Guaranteed. Requests matter even when the node is fine.
- Horizontal Pod Autoscaler (HPA) – If you set resource requests, HPA can scale pods based on actual usage vs. request, giving you elastic scaling.
Understanding the units
| Unit | CPU | Memory |
|---|---|---|
| Base | 1 CPU = 1 vCPU/core (GCP, AWS, Azure) | bytes (B) |
| Common | 500m = 0.5 CPU |
256Mi = 256 mebibytes |
| Examples | 1 = 1 CPU, 100m = 0.1 CPU |
512Mi, 1Gi, 0.5Gi not valid—use 512Mi |
Hands-on walkthrough
Let’s create a pod with explicit resource requests and limits using a simple nginx deployment.
Step 1: Create a pod manifest
Save the following as resource-pod.yaml:
apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: nginx
image: nginx:1.25
resources:
requests:
memory: "256Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "1"
Step 2: Apply and inspect
kubectl apply -f resource-pod.yaml
kubectl get pod resource-demo -o yaml | grep -A 10 resources
Expected output (abridged):
resources:
limits:
cpu: 1
memory: 512Mi
requests:
cpu: 500m
memory: 256Mi
Step 3: Verify QoS class
kubectl get pod resource-demo -o jsonpath='{.status.qosClass}'
# Output: Burstable
Because requests (500m CPU, 256Mi) are not equal to limits (1 CPU, 512Mi), the pod is Burstable.
Step 4: Simulate memory pressure (optional)
Install stress in the container to test limits:
kubectl exec -it resource-demo -- /bin/bash
apt update && apt install -y stress-ng
stress-ng --vm 2 --vm-bytes 300M --timeout 30s
If you exceed the 512Mi memory limit, the container will be killed with OOMKilled.
kubectl get pod resource-demo
# NAME READY STATUS RESTARTS AGE
# resource-demo 0/1 OOMKilled 1 2m
Pro tip: Always set
limits.memoryto protect against memory leaks. CPU limits are optional—throttling is usually less harmful than OOM kills.
Compare options / when to choose what
| Configuration | QoS Class | Use Case | Risk |
|---|---|---|---|
Request and limit equal (requests == limits) |
Guaranteed | Critical database, stateful services | Predictable but can be wasteful if never peaks |
| Request < limit | Burstable | Stateless web servers, APIs with occasional spikes | Best balance for most workloads |
| No requests or limits | BestEffort | Batch jobs, test pods, CI runners | Highest eviction risk; avoid in production |
When to prefer each
- Guaranteed – For pods that must not be evicted (e.g., etcd, control-plane components). Costs are higher because you reserve resources even when idle.
- Burstable – Default for most user workloads. Set requests to typical consumption and limits to peak. Works well with HPA.
- BestEffort – Use sparingly for low-priority jobs or when you want maximum bin packing. Expect restarts under pressure.
Troubleshooting & edge cases
1. Pod stuck in Pending with Insufficient memory
Cause: No node has enough allocatable memory to meet the sum of all pod requests. Fix: Either reduce requests, add nodes, or scale down other pods.
kubectl describe pod pending-pod
# ...
# Events:
# Type Reason Age From Message
# ---- ------ ---- ---- -------
# Warning FailedScheduling 10s default-scheduler 0/3 nodes are available: insufficient memory.
2. Container OOMKilled repeatedly
Cause: Memory limit too low for actual usage. Fix: Use kubectl top pod to observe real memory usage over time, then adjust limits.
kubectl top pod resource-demo
# NAME CPU(cores) MEMORY(bytes)
# resource-demo 10m 320Mi
3. CPU throttling during burst
Cause: CPU limit set too low for peak load. Fix: If your app is CPU-bound, set request == limit to avoid throttling spikes. Monitor with kubectl top pod.
4. limits.memory must be >= requests.memory
Cause: Exceeding memory limit forces immediate kill. Fix: Always keep limits.memory > requests.memory unless you absolutely need strict equality.
5. Using kubectl explain for reference
kubectl explain pod.spec.containers.resources
Shows all nested fields with descriptions—a lifesaver when debugging.
What you learned & what's next
You now understand how to configure resource requests and limits to enforce predictable pod behavior in Kubernetes. Key takeaways:
- Requests guarantee allocation for scheduling; limits cap maximum usage.
- QoS classes (Guaranteed, Burstable, BestEffort) determine eviction priority.
- CPU limits throttle; memory limits kill.
- Always set memory limits; CPU limits are optional but recommended for noisy neighbors.
- Use
kubectl top podandkubectl describeto diagnose resource issues.
Next up: In the following lesson, you’ll learn how LimitRanges and ResourceQuotas enforce resource constraints at the namespace level, ensuring no team can monopolize the cluster. Master that, and you’ll be ready to manage multi-tenant production clusters with confidence.
Practice recap: Try creating a second pod with
requests.memory=512Miandlimits.memory=512Mi(Guaranteed). Then deploy astresscontainer that attempts to use 600Mi – it will be OOMKilled. Observe the QoS class and the restart count.
Practice recap
Practice recap: Create a Burstable pod with requests.memory=256Mi, limits.memory=512Mi and a Guaranteed pod with both set to 512Mi. Use stress-ng to push memory to 600Mi in the Burstable pod — it will be OOMKilled. Observe the QoS class change in kubectl get pod -o yaml and note how the Guaranteed pod remains unaffected.
Common mistakes
- Setting
limits.memorylower thanrequests.memory— the pod will be OOMKilled immediately because it cannot even meet its own request. - Forgetting to set memory limits at all — a memory leak can consume all node RAM and cause kubelet evictions across the cluster.
- Using CPU request and limit values that are too small (e.g.,
10m) for latency-sensitive workloads — throttling will cause visible performance degradation.
Variations
- Instead of per-pod resources, you can use HorizontalPodAutoscaler to automatically adjust replica counts based on actual CPU/memory usage relative to requests.
- Namespace-scoped ResourceQuota objects enforce cumulative resource limits for all pods in a namespace, complementing per-pod requests and limits.
- Use vertical pod autoscaler (VPA) to automatically adjust resource requests based on historical usage — ideal for stateful workloads.
Real-world use cases
- E-commerce checkout microservice: set CPU request 500m, memory request 256Mi, memory limit 512Mi to handle Black Friday traffic spikes without OOM.
- Background image processing job: use BestEffort QoS (no requests) for low-priority batch tasks that can be retried if evicted.
- Central etcd cluster: configure Guaranteed QoS with requests == limits to prevent eviction under node memory pressure.
Key takeaways
- Resource requests guarantee minimum allocation for scheduling; resource limits cap maximum usage — always set memory limits.
- QoS class (Guaranteed, Burstable, BestEffort) determines pod eviction priority under node pressure.
- CPU limits throttle the container; memory limits cause an OOM kill when exceeded.
- Use
kubectl top podandkubectl describe podto diagnose resource-related issues. - Equal requests and limits yields Guaranteed QoS — best for critical stateful services.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.