Understanding Kubernetes: Requests, Limits & Resource Management
In the previous article we looked at where Kubernetes places workloads. Today we’ll take a look at how many resources a Pod is allowed to use - hello resource management. :)
Why resource management matters
Every Kubernetes node has a limited amount of CPU and memory. If workloads were allowed to consume as much as they wanted, a single misbehaving application could affect everything else running on the same node.
Resource management allows Kubernetes to make better scheduling decisions and protect workloads from each other. The most important concepts are:
- resource requests
- resource limits
- QoS (Quality of Service) classes
- eviction
- OOMKilled
Let’s look at them one by one.
Resource requests
A request tells Kubernetes how many resources a container is expected to need.
For example:
resources:
requests:
cpu: "250m"
memory: "128Mi"
This means:
- the container requests 250 millicores of CPU
- it requests 128 MiB of memory
These values are mainly used by the scheduler. Kubernetes will only schedule the Pod onto a node that has sufficient available resources to satisfy those requests.
A common misconception is that a request reserves resources in the sense that nobody else can ever use them. It doesn’t. Instead, requests are primarily used for scheduling and as a guarantee of the minimum resources Kubernetes tries to make available to the container.
Resource limits
A limit defines how many resources a container is allowed to consume.
For example:
resources:
requests:
cpu: "250m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
The container may now use up to:
- 500 millicores of CPU
- 256 MiB of memory
But what happens when those limits are reached? The answer depends on the resource.
CPU limits vs memory limits
CPU and memory behave quite differently.
If a container reaches its CPU limit, the Linux kernel throttles it using cgroups. The application keeps running, but it cannot use more CPU time.
Memory behaves differently. If a container exceeds its memory limit, the Linux kernel terminates the process. Kubernetes then reports the container as OOMKilled (“Out Of Memory Killed”).
This is one of the most common reasons why Pods suddenly restart. Increasing the memory limit might solve the symptom, but it’s also worth asking why the application consumed so much memory in the first place.
QoS classes
Based on requests and limits, Kubernetes automatically assigns every Pod to one of three Quality of Service (QoS) classes.
Guaranteed
Requests and limits are identical for every resource.
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "500m"
memory: "512Mi"
These Pods receive the strongest protection when the node is under memory pressure.
Burstable
The Pod defines both requests and limits, but the limits are higher.
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
This is probably the most common configuration for production workloads.
BestEffort
No requests and no limits are defined.
containers:
- name: app
image: nginx
These Pods have the lowest priority when Kubernetes needs to free resources.
Requests vs limits
To avoid a common confusion when dealing with requests and limits.
A Pod can use more CPU than its request if spare CPU capacity is available on the node. Requests define what the scheduler plans for — not a hard cap. CPU limits are what actually restrict CPU usage.
Eviction
Sometimes the problem is not a single container exceeding its own memory limit. Instead, the entire node may run out of resources.
When that happens, Kubernetes may decide to evict Pods from the node to keep the system healthy. And QoS classes influence this decision.
Generally speaking:
- BestEffort Pods are evicted first
- then Burstable Pods
- Guaranteed Pods are the last to be evicted under memory pressure, assuming they stay within their resource limits
This is one reason why defining requests is considered a best practice.
Demo time
Let’s create a small example.
apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: "100m"
memory: "64Mi"
limits:
cpu: "200m"
memory: "128Mi"
apply it via
kubectl apply -f pod.yaml
and inspect the Pod with
kubectl describe pod resource-demo
Among other information, we’ll find the configured requests and limits. To see the QoS class, we can run:
kubectl get pod resource-demo \
-o jsonpath='{.status.qosClass}'
which returns Burstable as the requests are lower than the limits.
Summing up
Resource management is Kubernetes’ way of making sure workloads can share a cluster without interfering with each other.
The most important ideas are:
- requests tell the scheduler what a workload needs
- limits define how much it may consume
- CPU is throttled, memory can trigger
OOMKilled - QoS classes influence eviction decisions
- defining sensible requests and limits improves cluster stability
Together with scheduling, Pod Security, Network Policies and RBAC, resource management is another important building block for running reliable workloads in Kubernetes. Next up in this series: Autoscaling. We’ll look at how Kubernetes can automatically adjust the number of running Pods based on demand. Stay tuned :)
header image created by buddy ChatGPT
