Understanding Kubernetes: Requests, Limits & Resource Management

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