Cases4 cases
1 to 4 of 4
IL-0100PostHog's feature flags pods were packed onto Kubernetes nodes that were too small for their CPU requests, and CPU saturation above 90% caused three outages in ten days through Redis overload, connection pool exhaustion and slow queriesPostHog2025- Symptoms
On 21 October 2025 at 21:45 UTC a change to timeout handling was deployed to the feature flags service, and two minutes later automated monitoring reported higher error rates. The change was rolled back by 21:49, but error rates stayed high: about 38% of flag evaluation requests in the US datacenter returned errors. At 22:30 Redis metrics showed memory exhaustion on ElastiCache, at 22:35 Postgres connections spiked, and at 22:45 the team found a massive data transfer from Postgres into Redis. The main PostHog application was affected as well, because it shares the Redis instance with the flags service.
- Trigger
On 21 October a deployment meant to reduce timeout errors (PR #39821); on 24 October the deployment of IP-based rate limiting (PR #40074) that saw all traffic as coming from the load balancer's IP; on 28 October an unrelated routine deployment that rolled the feature flag pods in the US region.
- Root cause
- Component
- Contributing factor
- Detection
On 21 October automated monitoring detected higher error rates two minutes after the deploy. On 24 October no alert existed for 429 errors, and the team learned of the incident from customer reports that began at 18:10 UTC, a 62-minute detection delay. On 28 October on-call received a high error count alert. On 29 October the incident was reported with higher error rates and latency. No alert existed for CPU pressure, so the CPU saturation behind all three incidents was not seen directly.
- Remediation
- rolled back the timeout handling change within 2 minutes on 21 October, which did not stop the errors
- throttled connections and Redis writes on 21 October
- halted the rollout on 28 October, scaled the US flags pods to zero until Redis recovered, then scaled them back gradually
- rolled back hardware changes on 30 October at 00:03 UTC, which removed most errors but not the latency
- increased the pod resource requests and adjusted the Kubernetes fleet size so fewer pods ran on each node
- added retry limits to Envoy between the load balancer and the service
- moved database connection timeouts and other critical settings to runtime configuration and raised the timeout values
- added per-node and per-pod CPU alerts at 80% sustained for 5 minutes that page on-call
- Action items
- Form a strike team from the flags, ingestion and infrastructure teams to review the application and infrastructure for remaining bottlenecks
- Investigate separating the flags Redis instance from the application Redis instance
- Before re-enabling ArgoCD sync, align the flags service chart configuration with the values in ArgoCD and define the deployment and Redis strategy
- Make the feature flags team hard code-owners for flags-related code
- Build a dashboard of key flag metrics with runbook links and update the feature flag runbooks
- Add missing alerts on existing service and infrastructure metrics
- Make readiness checks validate dependencies that degrade under load, for example by pinging the database
- Rate-limit cache population so it cannot overwhelm Redis
- Monitor connection pools with automatic throttling near exhaustion and limit concurrent connections
- Build a production-scale load testing framework
- Build progressive rollout infrastructure to limit blast radius
- Document Postgres-to-Redis data flows and write runbooks for data transfer storms
- Lessons
Nodes that are small relative to pod requests let the scheduler pack many pods on each node, and the resulting CPU saturation showed up three different ways: excessive parallelism, connection pool exhaustion and slow queries. Treating each symptom separately let the problem return; right-sizing the pods and nodes fixed all three. CPU must be alerted on from the start. Unbounded Envoy retries and unbounded cache population amplified the overload, and a Redis instance shared with the main application spread a flags problem to the main application. A rollback did not end the incident, because the data transfer and resource exhaustion it had started kept running.
IL-0082Losing one CoreDNS pod during a planned EKS node reroll overloaded the remaining CoreDNS pods, causing DNS timeouts and errors across multiple services at RebelMouseRebelMouse2025- Symptoms
At 13:42 UTC on 19 May 2025, RebelMouse's monitoring tools reported a higher error rate and degraded performance across services. A routine reroll of the EKS nodes had started 27 minutes earlier, at 13:15 UTC.
- Trigger
At 13:15 UTC RebelMouse started its regular reroll of EKS nodes to apply security patches. The planned, automatic termination of an EC2 instance terminated one of the CoreDNS pods.
- Root cause
- Component
- Contributing factor
- Detection
Monitoring tools detected an increased error rate and degraded service performance at 13:42 UTC, and the tech team started investigating at 13:44 UTC.
- Remediation
- rescheduled the affected CoreDNS pod onto a new EC2 instance
- scaled up the CoreDNS deployment to more replicas so DNS load was spread evenly across all pods
- Action items
- Add scale-in protection so CoreDNS pods are not terminated unexpectedly during peak load
- Review the CoreDNS configuration so that vertical scaling of the pods works
- Hold regular capacity reviews so the CoreDNS deployment is provisioned for peak load
IL-0190Cortex distributors kept a stuck connection to a dead etcd leader after a Kubernetes upgrade terminated its node, failing writes to Hosted Prometheus for 12 minutesGrafana Labs2020- Symptoms
About a minute after the etcd leader changed, two replicas of the Cortex distributor started logging "context deadline exceeded" when they tried to read keys from etcd. Writes from some customers that landed on those two replicas failed, while the other distributor replicas kept working, so the service saw an error rate of about 20% on writes to the London region of Hosted Prometheus.
- Trigger
A scheduled Kubernetes version upgrade abruptly terminated the node that ran the etcd leader at 11:19:00 UTC.
- Root cause
- Component
- Contributing factor
- Detection
An SLO-based alert paged the on-call engineer at 11:31, 11 minutes after the errors started. At a 20% error rate the monthly SLA would have taken about 18 hours to breach.
- Remediation
- Restarted the two affected Cortex distributor replicas at 11:32, which stopped the errors
- Action items
- Enable gRPC keepalive probes in the Cortex etcd client (DialKeepAliveTime 10s, DialKeepAliveTimeout, PermitWithoutStream)
- Make the Kubernetes upgrade process terminate pods and machines gracefully, including the etcd pods managed by the etcd operator
- Lessons
When a node dies abruptly, clients holding TCP connections to it are not told; without keepalive probes an etcd client can keep sending requests into a dead connection long after a new leader exists. A failover that works on the server side still needs clients that detect the dead peer. Node replacement during cluster upgrades should drain pods gracefully, including pods owned by operators that the upgrade scripts do not know about, and should give instances enough time to shut down.
IL-0013The conntrack table filled up on downsized GKE nodes and a high-traffic aggregation proxy saw climbing connection resetsloveholidays2020- Symptoms
Shortly after a round of changes, loveholidays saw connectivity problems and raised error rates on its aggregation service. The service is a proxy between two other services of more than 100 instances each, handles over 10,000 requests per second continuously and can spike to four times that.
- Trigger
Three changes together: a change in service architecture, halving the RAM of the nodes that run the aggregation service, and sharding a downstream service, which doubled the number of connections to track.
- Root cause
- Component
- Contributing factor
- Detection
Rising error rates and climbing connection reset errors in HAProxy, then node_exporter conntrack metrics compared with their limit.
- Remediation
- moved the aggregation service to nodes with more RAM
- limited the number of aggregation service pods per node
- Action items
- Alert when conntrack table use goes above 75%, with (node_nf_conntrack_entries / on (pod) node_nf_conntrack_entries_limit / on (pod) group_right kube_pod_info) > 0.75
- Lessons
The conntrack limit is tied to node memory, so resizing a node pool silently resizes the connection table, and on GKE the ratio did not match the commonly cited formula. A high-traffic proxy on small nodes can exhaust it, and the symptoms are connection resets and timeouts, so conntrack use needs its own metric and alert.
These 4 cases involve Node pool and In-memory cache. 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-0100PostHog's feature flags pods were packed onto Kubernetes nodes that were too small for their CPU requests, and CPU saturation above 90% caused three outages in ten days through Redis overload, connection pool exhaustion and slow queriesPostHog2025IL-0082Losing one CoreDNS pod during a planned EKS node reroll overloaded the remaining CoreDNS pods, causing DNS timeouts and errors across multiple services at RebelMouseRebelMouse2025IL-0013The conntrack table filled up on downsized GKE nodes and a high-traffic aggregation proxy saw climbing connection resetsloveholidays2020
Software defect1 case
- Contributing factor
- Organisation