Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

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

Sponsored

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. Guaranteed pods are last to be evicted under pressure.

How it works step by step

  1. 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 stays Pending.
  2. 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.
  3. Eviction – Under node memory pressure, the kubelet evicts BestEffort pods first, then Burstable, then Guaranteed. Requests matter even when the node is fine.
  4. 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.memory to 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 pod and kubectl describe to 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=512Mi and limits.memory=512Mi (Guaranteed). Then deploy a stress container 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.memory lower than requests.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

  1. Instead of per-pod resources, you can use HorizontalPodAutoscaler to automatically adjust replica counts based on actual CPU/memory usage relative to requests.
  2. Namespace-scoped ResourceQuota objects enforce cumulative resource limits for all pods in a namespace, complementing per-pod requests and limits.
  3. 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 pod and kubectl describe pod to diagnose resource-related issues.
  • Equal requests and limits yields Guaranteed QoS — best for critical stateful services.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.