Kubernetes Error Guide: 'MemoryPressure True' Node Condition and Eviction Taint
Fix Kubernetes MemoryPressure: memory.available eviction threshold, BestEffort pods evicted first, kube-reserved, the memory-pressure taint, and OOM avoidance.
- #kubernetes-helm
- #troubleshooting
- #errors
- #node
Exact Error Message
When available memory on a node falls below the kubelet’s eviction threshold, the node reports MemoryPressure=True, gains a taint, and starts evicting pods:
$ kubectl describe node worker-2
Conditions:
Type Status Reason Message
---- ------ ------ -------
MemoryPressure True KubeletHasInsufficientMemory kubelet has insufficient memory available
Taints: node.kubernetes.io/memory-pressure:NoSchedule
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning EvictionThresholdMet 30s kubelet Attempting to reclaim memory
Warning Evicted 28s kubelet The node was low on resource: memory. Threshold quantity: 100Mi, available: 84Mi.
The evicted pod shows:
$ kubectl get pod cache-x9 -o jsonpath='{.status.reason}'; echo
Evicted
What the Error Means
The kubelet watches memory.available on the node, computed as node capacity minus working-set memory (not raw free). When it drops below the eviction threshold — by default memory.available<100Mi — the kubelet sets MemoryPressure=True. It then taints the node node.kubernetes.io/memory-pressure:NoSchedule to keep new pods off, and begins evicting pods to reclaim memory.
Memory is an incompressible resource: unlike CPU it cannot be throttled, so the kubelet’s only lever is to kill pods. Eviction order follows QoS class: BestEffort first, then Burstable pods exceeding their requests, and Guaranteed pods last. This is distinct from a kernel OOM kill, though both can occur on a starved node.
Common Causes
- Pods without memory requests/limits — BestEffort workloads with no caps grow until the node is starved.
- Underprovisioned
kube-reserved/system-reserved— not enough memory carved out for the kubelet, runtime, and OS, so system daemons compete with pods. - A leaking or spiking workload — one container’s working set climbs and pushes node memory below threshold.
- Overcommit — sum of limits far exceeds node capacity and several pods peak together.
- Large page cache from heavy I/O counting toward working set.
- Too-dense scheduling because requests were set far below real usage.
How to Reproduce the Error
Run a BestEffort pod (no requests/limits) that allocates memory until the node crosses the threshold:
apiVersion: v1
kind: Pod
metadata:
name: mem-hog
spec:
containers:
- name: hog
image: polinux/stress
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "6G", "--vm-hang", "0"]
# no resources block => BestEffort QoS
kubectl apply -f mem-hog.yaml
kubectl describe node <NODE> | grep -A2 MemoryPressure
As the node’s memory.available drops under 100Mi, the kubelet flips MemoryPressure=True, taints the node, and evicts the BestEffort mem-hog pod first.
Diagnostic Commands
# Confirm the condition and taint
kubectl describe node <NODE> | grep -A2 'MemoryPressure\|Taints'
# Live memory usage per node and per pod (requires metrics-server)
kubectl top nodes
kubectl top pods -A --sort-by=memory
# Eviction events across the cluster
kubectl get events -A --field-selector reason=Evicted --sort-by=.lastTimestamp
# QoS class of pods on the node (BestEffort gets evicted first)
kubectl get pods -A -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,QOS:.status.qosClass,NODE:.spec.nodeName | grep <NODE>
# Reserved memory and allocatable on the node
kubectl describe node <NODE> | grep -A8 'Allocatable\|Capacity'
kubectl top plus the QoS column tell you which workload is driving pressure and which pods the kubelet will evict next.
Step-by-Step Resolution
1. Confirm pressure vs OOM. A MemoryPressure condition with an Evicted pod is kubelet eviction. A pod that died with OOMKilled is a cgroup/kernel kill. Both can stem from the same memory shortage but are fixed slightly differently.
2. Identify the heaviest pods. Use kubectl top pods -A --sort-by=memory to find the offenders on the affected node, and check their QoS class.
3. Set requests and limits. Give every workload a realistic memory request (so the scheduler reserves space) and a limit (so a leak is contained):
resources:
requests: { memory: "256Mi" }
limits: { memory: "512Mi" }
Requests below real usage are the root cause of overcommit — size them from observed peaks.
4. Protect critical pods with QoS. Make essential workloads Guaranteed (requests == limits) so they are evicted last. Leave only truly disposable jobs as BestEffort.
5. Reserve memory for the system. Configure kube-reserved and system-reserved so the kubelet and OS are not starved by pods, which prevents the whole node from destabilising.
6. Wait for the taint to clear, then rebalance. Once eviction frees memory above the threshold, the kubelet clears MemoryPressure and removes the taint. If the node is chronically tight, reduce density or add nodes.
Prevention and Best Practices
- Always set memory requests and limits; unbounded BestEffort pods are the number-one cause of node memory pressure.
- Aim for Guaranteed QoS on stateful and latency-critical services so they survive reclaim.
- Configure
kube-reservedandsystem-reservedso allocatable reflects real headroom and pods cannot crowd out system daemons. - Alert on
node_memory_MemAvailable_bytesapproaching the eviction threshold and on anyEvicted/OOMKilledevent. - Run a cluster autoscaler so sustained pressure adds capacity instead of repeatedly evicting pods.
- Right-size requests from observed working set, not guesses. More in our Kubernetes & Helm guides.
Related Errors
- The node was low on resource (Evicted) — the eviction this condition triggers.
- DiskPressure True — the disk-side sibling condition.
- FailedScheduling — pods refused by the memory-pressure taint.
Frequently Asked Questions
What is the difference between MemoryPressure eviction and OOMKilled? MemoryPressure eviction is a node-level decision by the kubelet to reclaim memory by deleting whole pods, ranked by QoS. OOMKilled is a container-level kill by the kernel when a process exceeds its cgroup memory limit. A node can OOM-kill a container without ever raising MemoryPressure, and vice versa.
Which pods get evicted first? BestEffort pods (no requests/limits) are evicted first, then Burstable pods using more than their requests (ranked by overage), and Guaranteed pods (requests == limits) last. Setting requests/limits is how you control your place in that order.
Will my Guaranteed pod ever be evicted by MemoryPressure? Only as a last resort, after all BestEffort and over-request Burstable pods are gone and the node is still over threshold. In practice, correctly sized Guaranteed pods are very rarely evicted for memory.
The node shows free memory in free -m but still reports MemoryPressure — why? The kubelet uses memory.available derived from working-set bytes, which excludes reclaimable cache differently than free. It is also offset by kube-reserved/system-reserved. Trust kubectl describe node allocatable and the kubelet’s threshold, not raw free.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.