Node-07 is hot, and everyone has a theory
A 24-node Kubernetes cluster runs 210 pods. node-07 has been at 90%+ CPU and 88% memory for four days. Over the same window three pods on that node were OOM-killed, and two latency-sensitive services that have replicas on node-07 show p95 inflated by roughly 300 ms, but only when those requests land on the replica there. CPU requests are set for every workload; limits are set on only about half. The platform team wants to cordon the node and rebuild it from 16 to 32 cores. The application team says the service is unchanged and blames the platform.
1. How do you decide whether node-07 is genuinely undersized or hosting a noisy neighbour?
Read the worked answer
Node-level CPU is an aggregate and cannot answer this. Decompose it:
- Per-container / per-pod CPU and memory on that node, summed, versus the sum of what those pods request. If a handful of pods account for most of the gap above their requests, it is a noisy neighbour - and adding 16 cores simply gives that workload more room to burst, so you will be back here in a month with a bigger bill.
- Non-application consumers. Check whether the consumption is app containers at all, or kubelet, the container runtime, a log-shipping daemon, or a system pod thrashing. A degraded system component is a third answer that neither team is currently considering.
- Scheduling. If the sum of requests across pods on node-07 is close to allocatable capacity, the scheduler packed it to the brim - that is capacity management, and resizing plus better spreading (topology/anti-affinity, PDB-aware scheduling) is right.
- Is the p95 delta real? Compare the same service's replicas across nodes for the same hour. If the other replicas are equally bad, node-07 is a red herring and the problem arrived with a deploy.
The decision rule: gap concentrated in a few unlimited pods โ fix requests/limits and QoS. Aggregate requests near capacity โ resize, but only after spreading is fixed, or you will re-pack the new cores the same way.
2. The three OOM kills: what distinguishes a container-limit kill from node-level memory pressure, and why does the fix differ?
Read the worked answer
They are different events with different owners.
- Container-limit kill (OOMKilled): the pod exceeded its own cgroup limit. The node may have been perfectly healthy. The pod's memory grew past the limit and the kernel killed it. The owner is the workload: the limit is too tight, or the workload leaks.
- Node memory pressure (Evicted): the node ran out and the kubelet evicted pods by QoS class - BestEffort first, then Burstable pods consuming above their requests, Guaranteed last. The owner is the node and the scheduling/capacity picture.
So read the termination reason and QoS class per pod before doing anything. Three pods dying with no limits set on a node at 88% is much more likely eviction under pressure than three coincidental limit breaches - and that changes the remedy entirely.
Why the fix differs: raising the node's RAM without setting limits just moves the cliff further away and lets the same workload grow into it. Setting limits on an unbounded workload without addressing node pressure may convert evictions into OOM kills. Right-sized requests (which drive scheduling and eviction ordering) plus limits (which cap blast radius) plus enough node headroom is the combination; picking one of the three is how you get a repeat incident next week.
3. What would justify cordoning and draining node-07 regardless of the sizing question?
Read the worked answer
Node health, not capacity:
- the node is NotReady, flaps, or reports DiskPressure, MemoryPressure or PID exhaustion;
- kernel, container-runtime or network-plugin errors on that node - the kind of thing a resize does not fix;
- hardware or hypervisor degradation signals (ECC, storage latency, degraded NIC) if the node is a VM or bare metal you also monitor;
- repeated unexplained kills spread across unrelated workloads on that node only.
If any of those hold, draining is correct and the capacity debate is a separate conversation that should happen afterwards, not as a precondition.
Before you drain, though: check pod disruption budgets, and check whether the latency-sensitive replicas can actually land somewhere with headroom. Draining into three nodes that are already at 85% turns a local problem into a cluster-wide one. And confirm the p95 delta follows the node and not the pod - if the slow pod lands on node-12 and stays slow, draining node-07 achieves nothing but a maintenance window.