Cases4 cases
1 to 4 of 4
IL-0110A Grafana Agent pod's high memory use and crash-looping Hangfire pods drove a Kubernetes node into system OOM and NotReady, twice in one dayDFDS2024- Symptoms
At 10:01 UTC on 2024-03-13 a Kubernetes node entered NotReady state, with CPU requests at 78% and memory requests at 82%. An alert fired in Slack at 10:03 and was picked up at 10:05. An attempt to SSH into the node at 10:13 failed because it was unresponsive; it started responding again at 10:19.
- Trigger
Pods of a dev container that used Hangfire to trigger jobs failed with OOM and crash-looped on a node where a Grafana Agent pod was already using a lot of memory.
- Root cause
- Component
- Contributing factor
- Detection
A Slack alert fired two minutes after the node went NotReady and was picked up two minutes later; the second node's NotReady at 15:03 also raised a Slack alert.
- Remediation
- marked the EC2 instance unhealthy so a new node started
- cordoned and force-drained the NotReady node and terminated its EC2 instance
- removed the new LimitRange from the Grafana Agent namespace and restarted the Grafana Agent pod
- scaled the dev container to 0 replicas, after which EC2 network traffic returned to normal
- after the second NotReady, scaled the dev container to 0 replicas again and added a new node
- emailed the team that owns the dev container, which confirmed it was working on a fix
- Action items
- Move grafana-agent to the monitoring node group
- Add alerts for when bandwidth across the cluster reaches a certain threshold
- Investigate whether memory limits can be set on the grafana-agent Helm chart
- Investigate grafana-agent memory usage
- Ask Grafana support whether grafana-agent should use a PVC
- Consider pushing node logs to Loki with limited retention
- Create a wiki page with common metrics and log queries to check when investigating issues with Kubernetes nodes
- Lessons
Dev workloads mixed with production let one crash-looping dev container take down nodes that production also used, and a monitoring agent outside its dedicated node group added to the memory pressure. Scaling the suspect container back up before its owners had fixed it brought the failure back on the replacement node. The team also noted that action items from earlier post-mortems need follow-up, and that knowledge of useful CloudWatch metrics had not been shared, which made the diagnosis harder.
IL-0176Prometheus in a 235-node Kubernetes cluster crash-looped because over two million series exhausted host memory and the kernel OOM killer chose it first, as Burstable QoS gave it oom_score_adj 999LINE2020- Symptoms
One Monday morning the author opened the Prometheus dashboard to check a Kubernetes cluster for alerts and could not reach it. The Prometheus pod was in CrashLoopBackOff: kubectl get pods showed it 1/2 ready with 950 restarts over 3d20h on worker3.
- Trigger
After start, the Prometheus time series count rose to 2,162,256 within five minutes and its memory use filled the 8GB host.
- Root cause
- Component
- Contributing factor
- Detection
The author found it on a Monday morning when the Prometheus dashboard, opened to check the cluster for alerts, could not be reached.
- Remediation
- removed most of the unnecessary settings from the Prometheus ConfigMap, after which the container stopped crashing
- Action items
- Set appropriate resource requests and limits on the Prometheus pod
- Reduce unneeded metrics by adjusting scrape targets or scrape interval
- Estimate Prometheus memory needs, provide dedicated hosts with a node label such as deploy-topology: Prometheus, and pin the Prometheus pod to them with a nodeSelector
- Lessons
Exit code 137 together with an OOM event in the kubelet log means the kernel killed the container, not kubelet. Under node memory pressure the kernel kills the process with the highest score, and kubelet derives each container's oom_score_adj from the pod's QoS class: a container without a memory request in a pod where another container has one ends up Burstable with a score near 1000, so it is killed first. In a large cluster, Prometheus memory needs to be estimated from the expected series count and requested explicitly.
IL-0026Kubernetes nodes hit SystemOOM because fluentd-sumologic log shipper pods had no memory limitsBlue Matador2019- Symptoms
On a Saturday at 5:12 pm, Blue Matador's own monitoring raised a SystemOOM event for one node in the production Kubernetes cluster. Four minutes later a second warning reported a low EBS Burst Balance on that node's root volume. CloudWatch data showed the burst balance had actually bottomed out at 5:02 pm, before the memory event; the warning arrived late because EBS metrics lag 10 to 15 minutes.
- Trigger
Memory use of the fluentd-sumologic log shipper pods grew until the node ran out of memory; log volume in Sumo Logic had been steady, so a burst of logs was not the cause.
- Root cause
- Component
- Contributing factor
- Detection
Blue Matador's own monitoring product alerted on the SystemOOM event, followed minutes later by a low EBS Burst Balance warning for the same node.
- Remediation
- restarted all fluentd-sumologic pods so they started with low memory
- set RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR to 0.9 on the fluentd-sumologic pods
- added memory requests of 128Mi and limits of 1024Mi, and CPU requests of 100m and limits of 250m, to the fluentd-sumologic pods
- Action items
- Apply default resource limits and resource quotas so that every pod runs with requests and limits
- Lessons
When checking for restarted pods, look in every namespace, not only the application one. Set resource requests and limits on every pod, third-party ones in particular, so that one workload cannot exhaust a node. Investigate side signals such as the disk I/O spike while the logs still exist.
IL-0035Worker nodes went NotReady after a new ElastAlert rule without memory limits used up node memoryNU.nl2019- Symptoms
The NU.nl development team got reports that several services on one of its Kubernetes clusters behaved erratically: occasional error pages, slow responses and timeouts. The affected services were mostly internal tools and dashboards.
- Trigger
A new ElastAlert rule, deployed shortly before from the command line, that fired if the Cloudfront-* Elasticsearch indexes stopped receiving documents; those indexes take a few million requests per hour, and the rule made ElastAlert's memory grow without bound.
- Root cause
- Component
- Contributing factor
- Detection
Users reported error pages, slow responses and timeouts from several services; no alert fired.
- Remediation
- terminated the NotReady nodes one by one so the auto-scaling group replaced them (the new nodes also went NotReady, but Prometheus and Grafana landed on a stable node)
- found the ElastAlert pods' memory growth on the Grafana pod memory dashboard
- fixed the ElastAlert problem that caused the memory growth
- Action items
- Define alerts on resource usage such as CPU, memory and disk space
- Keep researching an alerting strategy that combines Elasticsearch, Prometheus Alertmanager and New Relic
- Consider exporting metrics out of the cluster and running Grafana outside it, on EC2 or a separate Kubernetes cluster
- Either visualise the important metrics in the ELK stack or make Prometheus and Grafana more available, and improve the metrics strategy
- Set resource limits for ElastAlert through the Helm values
- Configure namespaces with default memory requests and limits
- Isolate customer-facing workloads from build, logging and monitoring workloads (a dedicated node group, or later a separate tools cluster)
- Deploy everything through automation such as Jenkins pipelines, and consider a GitOps approach
- Deploy through a pipeline that includes a smoke test step
- Make Kubernetes and cloud infrastructure work part of the team's sprints, picked up by all team members while pairing with more experienced members, and hold workshops that go deep into specific topics
- Lessons
Fixing the root cause covers only a small part of what an incident can teach; the chain of smaller failures around it is where most of the learning is. A pod without a memory limit can take whole nodes down, so limits need defaults at the namespace level. Monitoring that runs inside the cluster it watches goes blind with it. Changes installed by hand from the command line leave the rest of the team without a record of what changed.
These 4 cases involve Container memory limit and kubelet. kubegap audits a Kubernetes cluster for gaps like these, read-only, from Claude Code or Codex; its checks cite public reports like the ones in this library.
By root cause2
Capacity exhaustion3 cases
- Component
- Contributing factor
- Organisation
IL-0110A Grafana Agent pod's high memory use and crash-looping Hangfire pods drove a Kubernetes node into system OOM and NotReady, twice in one dayDFDS2024IL-0176Prometheus in a 235-node Kubernetes cluster crash-looped because over two million series exhausted host memory and the kernel OOM killer chose it first, as Burstable QoS gave it oom_score_adj 999LINE2020IL-0026Kubernetes nodes hit SystemOOM because fluentd-sumologic log shipper pods had no memory limitsBlue Matador2019
Configuration change1 case
- Contributing factor
- Organisation