MemoryPressure indicates a node is running critically low on available memory. The kubelet responds by tainting the node, stopping new pod scheduling, and evicting lower-priority pods to reclaim memory.
MemoryPressure is a node condition that indicates a Kubernetes node is running critically low on available memory. When the kubelet detects that available memory has dropped below its configured eviction threshold, it sets the MemoryPressure condition to True and applies the node.kubernetes.io/memory-pressure:NoSchedule taint to prevent new pods from being scheduled on that node. This condition triggers the kubelet's node-pressure eviction mechanism, which proactively terminates pods on the node to reclaim memory and prevent a system-level Out-Of-Memory (OOM) killer from becoming involved. The kubelet monitors memory continuously via cAdvisor and makes eviction decisions based on pod QoS class (Guaranteed, Burstable, or BestEffort), with BestEffort pods being evicted first. MemoryPressure can arise from legitimate high workloads, but often indicates resource overcommitment, memory leaks in applications, or insufficient node capacity for the scheduled pods. If eviction cannot reclaim memory quickly enough, the Linux kernel's OOM killer may still be invoked.
Confirm the node is actually under memory pressure:
kubectl describe node <NODE_NAME>Look for the Conditions section and check if MemoryPressure=True. Also inspect the Taints section to see if node.kubernetes.io/memory-pressure:NoSchedule is present.
Examine current memory consumption to understand the scope:
# View node resource usage
kubectl top nodes
# View pod memory usage on specific node
kubectl top pods --all-namespaces --sort-by=memory
# SSH into node and check kernel's view of memory
kubectl debug node/<NODE_NAME> -it --image=ubuntu
# Inside debug container:
cat /proc/meminfo
free -hNote: 'kubectl top' uses kubelet cgroup stats (the authoritative source), while 'free -h' may show different values.
Review pods on the affected node and identify which can be safely removed:
# List all pods on specific node
kubectl get pods --all-namespaces --field-selector spec.nodeName=<NODE_NAME>
# Check pod resource requests/limits
kubectl describe pod <POD_NAME> -n <NAMESPACE> | grep -A 5 'Limits\|Requests'
# Identify BestEffort pods (no resource requests/limits - evicted first)
kubectl get pods --all-namespaces -o custom-columns=NAME:.metadata.name,NAMESPACE:.metadata.namespace,QOS:.status.qosClass --field-selector spec.nodeName=<NODE_NAME>Pods with BestEffort QoS will be evicted first. Consider scaling down non-critical workloads.
Set kubelet eviction thresholds to reclaim memory before the system OOM killer engages. Edit the kubelet configuration:
# In /etc/kubernetes/kubelet-config.yaml
evictionHard:
memory.available: "500Mi"
evictionSoft:
memory.available: "1.5Gi"
evictionSoftGracePeriod:
memory.available: "1m30s"
systemReserved:
memory: "1.5Gi"
kubeletReserved:
memory: "100Mi"Restart the kubelet after changes. Set soft thresholds ~20-30% above hard thresholds to give time for graceful eviction.
Ensure pods declare realistic resource requests/limits:
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: my-app:1.0
resources:
requests:
memory: "256Mi"
limits:
memory: "512Mi"Run your application under load to measure realistic memory usage, then set requests to ~80% of peak observed usage. Consider using Vertical Pod Autoscaler (VPA) to analyze historical usage.
If memory pressure is persistent despite tuning, increase cluster capacity:
# Scale up node pool (cloud provider specific)
# GKE example:
gcloud container node-pools update <POOL_NAME> \
--machine-type n1-standard-4 \
--cluster <CLUSTER_NAME>Alternatively, distribute pods across more nodes using pod anti-affinity:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- my-app
topologyKey: kubernetes.io/hostnameThe kubelet's node-pressure eviction mechanism is designed to prevent system-level OOM events by proactively terminating pods. However, if memory spikes faster than the kubelet can detect it (cAdvisor polls at intervals, default ~10s), the kernel OOM killer may still be invoked. Enable --kernel-memcg-notification for immediate memcg notifications.
The kubelet respects QoS classes when evicting pods: BestEffort pods are evicted first, followed by Burstable pods, then Guaranteed pods. Non-BestEffort pods receive a toleration for the memory-pressure taint by default.
Hard eviction thresholds use a 0-second termination grace period (immediate kill), while soft thresholds respect eviction-max-pod-grace-period (default 30s). The kubelet does NOT respect PodDisruptionBudgets during eviction—pods are evicted regardless of budget constraints.
The kubelet calculates memory.available from cgroup stats, not from host-level tools. This can show different values than free -m because the kubelet excludes inactive_file (reclaimable file cache).
Failed to connect to server: connection refused (HTTP/2)
How to fix "HTTP/2 connection refused" error in Kubernetes
missing request for cpu in container
How to fix "missing request for cpu in container" in Kubernetes HPA
error: invalid configuration
How to fix "error: invalid configuration" in Kubernetes
etcdserver: cluster ID mismatch
How to fix "etcdserver: cluster ID mismatch" in Kubernetes
running with swap on is not supported
How to fix "running with swap on is not supported" in kubeadm