Ordered by how often each one turns out to be the answer.
The limit is below what the workload actually needs
CommonThe most common case. The limit was set from a guess, a copied manifest or a tidy round number, and the application's real steady-state usage is higher. Nothing is broken; the ceiling is simply in the wrong place.
Confirm
kubectl top pod <pod> --containers
Usage sitting close to the limit even when the app is behaving. If steady-state usage is already near the ceiling, the limit is the problem.
Fix
- Observe usage over a normal cycle, including any startup spike, then set the limit above the observed peak with genuine headroom.
- Set the request to typical usage and the limit above peak. Requests drive scheduling; limits are the kill line.
kubectl set resources deployment <name> --limits=memory=512Mi --requests=memory=256Mi
Illustrative numbers only — use your own measurements. This triggers a rollout.
The application leaks memory
CommonUsage climbs steadily from start until the limit is hit, then the cycle repeats with almost mechanical regularity. The give-away is the rhythm: kills at consistent intervals under consistent load. Raising the limit here only lengthens the interval — it does not fix anything.
Confirm
kubectl top pod <pod> --containers
Sample repeatedly over several minutes. Monotonic growth under steady traffic is a leak; usage that rises and falls with load is not.
Fix
- Treat it as an application bug, not a configuration one. A higher limit buys time to investigate, nothing more.
- Check for unbounded caches, accumulating connections, or a runtime heap allowed to grow past the container limit.
- For JVM and Node workloads, make sure the runtime knows its own ceiling — a heap sized independently of the container limit will exceed it.
A workload spike, not a steady-state problem
OccasionalUsage is fine until a large request, a bulk import or a batch job briefly needs far more. The container is killed at the peak and looks healthy immediately afterwards, which makes this the hardest variant to catch — by the time you look, everything is normal.
Confirm
kubectl describe pod <pod> | grep -B2 -A5 'Last State'
A single kill, or kills clustered at particular times, rather than a steady cadence. Correlate the timestamp with what the system was doing.
Fix
- Size the limit for the peak the workload must survive, not the average.
- If the spike comes from batch work, isolate it into a Job with its own limits instead of sizing the whole service around it.
The node ran out of memory, not the container
RareDistinct from a container hitting its own limit: the node itself came under memory pressure and the kubelet evicted pods to protect it. The remedy is capacity or scheduling, not the container's limit.
Confirm
kubectl describe node <node> | grep -i pressure
MemoryPressure True, and eviction events referencing your pod
Fix
- Set requests accurately so the scheduler stops overcommitting the node.
- Add capacity, or move the workload to a node that can hold it.