BlogKubernetes

Kubernetes requests and limits: stop OOMKills, noisy pods

Set CPU and memory requests and limits that keep the scheduler honest, stop one pod from starving the node, and avoid needless OOMKills under load.

Sep 9, 2025·4 min readBeginner·By the SecOpsLog team · command-tested

A pod with no resource block looks free on paper and expensive on the node. Requests tell the scheduler how much CPU and memory to reserve — they decide where a pod lands and whether it fits at all. Limits cap what a container can actually consume — they decide whether a memory spike becomes an OOMKill or a CPU hog gets throttled. Confusing the two produces pods stuck in Pending forever, or pods that restart every few minutes for no apparent application bug.

The fix is not guessing from the Dockerfile. Measure production usage, set requests near your steady-state (p50), set memory limits near your spike (p99), and understand which QoS class Kubernetes assigns — Guaranteed, Burstable, or BestEffort — because that determines eviction order when the node runs out of memory. The Kubernetes administration track covers scheduling and resource mechanics end to end.

Right-sizing workflow

Measure before you limit. A limit set without data is either useless (too high) or an outage (too low).

1Deployrequests only first2Observekubectl top + metrics3Set requestsnear p50 usage4Set mem limitnear p99 spike5CPU limitoptional — see warn6Load testconfirm no OOMKill7VPA recommendrefine over time

When limits lie to you

OOMKilled is Kubernetes telling you the truth: the container exceeded its memory limit and the kernel killed it. The application logs may show nothing — the process simply vanished. Before you open a code ticket, check whether the limit is lower than what the JVM or runtime actually needs.

bash — the OOMKill signaturelive
kubectl get pod api-7c9 -o wide
STATUS: OOMKilled RESTARTS: 6
kubectl describe pod api-7c9 | grep -A3 "Last State"
Reason: OOMKilled
kubectl describe pod api-7c9 | grep -A2 Limits
Limits: memory: 128Mi
app needs ~200Mi — the limit is killing it, not a bug

Requests vs limits — two different jobs

Two different jobs
Requests
reserve capacity on the node
scheduler uses for placement
guaranteed floor (mostly)
too high → unschedulable
Limits
hard ceiling on usage
memory over → OOMKilled
CPU over → throttled (CFS quota)
too low → restarts or slowness

Set memory requests equal to limits when you want Guaranteed QoS — the highest priority during eviction. Many teams deliberately omit CPU limits so bursty workloads can use spare cycles on the node; a CPU limit only ever slows you down, it never protects neighbors the way a memory limit does.

deploy-resources.yaml
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
memory: 256Mi # requests == limits → Guaranteed QoS
# omit cpu limit → burst freely, throttle-free
A CPU limit throttles; a memory limit kills
CPU limits use CFS quota and can silently cap throughput under load — latency goes up, nobody gets paged, and you chase the wrong problem. Memory limits protect the node from a leak; when exceeded, the container dies immediately. Do not copy the same number to both without understanding the consequence.

Right-size from real usage

Deploy with requests only, run under normal and peak load, then read kubectl top pods or your metrics stack. Set requests slightly below steady usage so the scheduler packs efficiently; set memory limits above your observed peak with headroom for GC spikes. Vertical Pod Autoscaler in recommendation mode is a safe way to refine numbers without auto-applying a change that restarts production.

bash — measure, do not guesslive
kubectl top pods -n shop --containers
NAME CPU(cores) MEMORY(bytes)
api-7c9 142m 198Mi
kubectl get pod api-7c9 -o jsonpath="{.status.qosClass}"
Guaranteed
requests near p50, limits near p99 — let VPA refine

Where this goes next

Resource limits stop one pod from eating a node; they do not stop a compromised pod from talking to every other pod. Pair sizing with LimitRanges (namespace defaults), ResourceQuotas (team budgets), and admission policy that rejects BestEffort pods in production. The Kubernetes administration path covers scheduling, quotas, and operating clusters reliably.

Go deeper in a courseKubernetes administrationScheduling, resources, quotas, and operating clusters end to end.View course

Related posts