What are Kubernetes resource requests and limits?
A resource request is the amount of CPU and memory Kubernetes reserves for a container when it places the Pod on a node. A resource limit is the maximum the container may use: the kernel throttles CPU above the limit and kills the container with an out-of-memory (OOM) error when memory goes above it. The scheduler places Pods by their requests, not their actual usage, so requests decide how many nodes a cluster needs and what it costs.
Requests vs limits
Both are set per container under resources:
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
memory: 256Mi| Request | Limit | |
|---|---|---|
| Used by | The scheduler, to pick a node with enough unreserved capacity | The kernel on the node, at run time |
| CPU | Reserved share. Under contention, CPU time is split in proportion to requests | Hard cap. Above it, the container is throttled |
| Memory | Reserved amount | Ceiling. Above it, the container can be OOM-killed |
| If unset | Copied from the limit when a limit is set, otherwise zero | No cap: the container can use whatever is free on the node |
A container can use more than its request when the node has spare capacity. The Kubernetes documentation describes memory limits as enforced reactively: the kernel kills a container over its limit when it detects memory pressure, not the moment usage crosses the line. CPU is compressible, so going over a CPU limit slows the container down but never kills it.
CPU and memory units
One CPU unit is one physical core or one virtual core (vCPU), depending on the node. 100m means 100 millicores, a tenth of a core, and 1000m equals 1. Kubernetes accepts no precision finer than 1m.
Memory is in bytes with decimal or binary suffixes. M is a megabyte (1,000,000 bytes) and Mi is a mebibyte (1,048,576 bytes), so 256Mi is about 268 MB. The case matters: 400m of memory is 0.4 bytes, a common typo for 400Mi.
Why requests set the bill
The scheduler adds up the requests of every Pod on a node and only places a new Pod if its requests fit in the remaining allocatable capacity. It does not look at real usage. A Pod that requests 2 vCPU and uses 0.1 vCPU still blocks 2 vCPU, and the cluster autoscaler adds nodes when pending Pods’ requests do not fit.
That makes requests the main lever for cost. Oversized requests leave nodes full on paper and idle in practice; rightsizing is the practice of setting them from measured usage. Limits do not reserve capacity, so they do not change the bill.
Quality of service classes and eviction
Kubernetes assigns every Pod a quality of service (QoS) class from its requests and limits. When a node runs short of memory or disk, the kubelet evicts Pods in this order.
| QoS class | Criteria | Eviction order |
|---|---|---|
BestEffort |
No container sets any CPU or memory request or limit | First |
Burstable |
At least one request or limit set, but not Guaranteed |
Second |
Guaranteed |
Every container sets CPU and memory limits equal to its requests | Last |
Under resource pressure, only Pods using more than their requests are candidates for eviction. A container whose memory limit equals its memory request is stopped by its own limit before it can grow far past the request, so many teams set the two to the same value.
OOM kills vs CPU throttling
A container killed for exceeding its memory limit shows OOMKilled as the termination reason and restarts according to the Pod’s restart policy. A container that hits its CPU limit keeps running but receives less CPU time in each scheduling period, which shows up as higher latency. Throttling can happen even when average CPU usage looks low, which is why many teams skip CPU limits for latency-sensitive services. The trade-offs are in should you set CPU limits in Kubernetes.
Namespace defaults with LimitRange and ResourceQuota
A LimitRange sets default requests and limits for containers in a namespace that do not declare them, plus minimum and maximum values per container. A ResourceQuota caps the total requests and limits across a namespace. When a quota covers CPU or memory, Pods that do not specify those values can be rejected, so quotas are usually paired with a LimitRange that fills in defaults.
Requests and autoscaling
The Horizontal Pod Autoscaler measures CPU and memory utilization as a percentage of the request. A target of 70% on a container that requests 500m scales out at 350m of use. If a container has no request for the metric, the autoscaler takes no action on it. Changing requests therefore changes when the autoscaler adds replicas. How Kubernetes autoscaling works covers the autoscalers in more detail.
Changing requests without restarting Pods
Before in-place resize, changing a request meant replacing the Pod. In-place Pod resize, first available in Kubernetes 1.27, is stable since Kubernetes v1.35. It lets you change CPU and memory requests and limits on a running Pod. Each container’s resizePolicy decides whether a change applies live (NotRequired, the default) or restarts the container (RestartContainer). A resize cannot change the Pod’s QoS class, and the kubelet only makes a best-effort attempt to avoid OOM kills when lowering memory limits.
How Cloudfleet uses requests
In Cloudfleet Kubernetes Engine (CFKE), node auto-provisioning reads Pod resource requests, labels and affinity rules to choose the number and size of nodes, so accurate requests translate directly into smaller nodes and a lower bill.