Kubernetes Requests, Limits, and Scheduling

Resource settings are the most common source of quiet Kubernetes trouble. Pods sit in Pending because no node has room for what they asked for. A latency-sensitive service slows down under load even though its node is half idle, because its CPU limit throttles it. A Java process restarts every few hours with OOMKilled. During a busy afternoon, the kubelet evicts a batch of pods to protect a node. All of these come from two small fields on every container — requests and limits — and how the scheduler and the kubelet interpret them.

This page explains what each field does, how they combine into quality-of-service classes, and how to find the cause when workloads will not schedule, run slowly, or get killed.

TL;DR

Quick Example

A container with explicit requests and limits:

Diagnosing why a pod is not running:

A FailedScheduling event such as 0/6 nodes are available: 4 Insufficient memory, 2 node(s) had untolerated taint says exactly which constraint failed on how many nodes.

Core Concepts

Requests and Limits

The scheduler only looks at requests, never at actual usage. A node full of pods that request a lot but use little looks full to the scheduler; pods that request little but use a lot overload nodes the scheduler thinks are empty.

CPU Throttling and Memory OOM Kills

CPU is compressible: a container that hits its CPU limit is throttled — paused for the rest of each scheduling period — which shows up as latency, not errors. Memory is incompressible: a container that exceeds its memory limit is killed by the kernel's OOM killer, reported as OOMKilled with exit code 137. Runtimes such as the JVM, Node.js, and Go need their heap or memory settings aligned with the container limit, or they will be killed before they garbage collect.

QoS Classes and Eviction

When a node runs low on memory or disk, the kubelet evicts pods to protect the node, starting with pods using the most above their requests. Evicted pods show status Evicted with a reason such as The node was low on resource: memory.

Namespace Guardrails

Scheduling Constraints

Pending pods often fail several constraints at once; the event message lists them all. Cluster autoscalers add nodes only when a pending pod would fit on a new node — pods with impossible constraints stay pending forever. See Kubernetes Autoscaling.

Choosing Values

Best Practices

Always Set Requests

Without requests, the scheduler packs pods blindly and the pods become BestEffort — first to be evicted.

Always Set Memory Limits

Unbounded memory lets one leaking pod destabilize a whole node. A memory limit contains the damage to that container.

Watch Throttling, Not Just Utilization

A container can be throttled at 40% average CPU if it bursts. Track container_cpu_cfs_throttled_periods_total against total periods for latency-sensitive services.

Use Quotas and Defaults Per Namespace

Give every team namespace a LimitRange and ResourceQuota so forgotten settings get sensible defaults and no team can consume a cluster. See Kubernetes Multi-Tenant Isolation.

Common Mistakes

Requests Copied From a Template

JVM Heap Larger Than the Limit

Tight CPU Limits on Latency-Sensitive Services

FAQ

What is the difference between requests and limits in Kubernetes?

Requests are the resources the scheduler reserves for a container when placing it on a node. Limits are the maximum resources the container may use at runtime; exceeding the CPU limit causes throttling, and exceeding the memory limit causes the container to be killed.

Why is my pod stuck in Pending?

Usually because no node satisfies its requests or scheduling constraints — insufficient CPU or memory, untolerated taints, affinity rules, topology spread, or volume zone restrictions. kubectl describe pod shows the scheduler's reason in Events.

What does OOMKilled mean?

The container exceeded its memory limit and the kernel killed it. Check memory usage trends, raise the limit if usage is legitimate, or fix leaks and runtime memory settings.

Should I set CPU limits?

It depends. CPU limits cause throttling even when nodes have idle CPU, which hurts latency-sensitive services. Many teams set accurate CPU requests and omit limits, while others require limits for fairness in shared clusters. Monitor throttling whichever you choose.

What are QoS classes?

Guaranteed, Burstable, and BestEffort, derived from requests and limits. They decide which pods the kubelet evicts first when a node runs out of memory or disk: BestEffort first, Guaranteed last.

Related Topics

References