Incident Library
  • Root cause
  • Component
  • Symptom
  • Contributing factor
  • Case

Cases9 cases

1 to 5 of 9

  1. Symptoms

    On a Saturday, an OpsGenie alert fired for a ClickHouse cluster in Altinity.Cloud that had gone silent: no queries, no metrics, and no logs from customers trying to connect. The pods were running and the nodes looked healthy, but no traffic reached the database. Other clusters soon showed the same thing, and external access was blocked across several GKE clusters.

    Trigger

    GKE automatically upgraded worker nodes to the ubuntu_containerd image 1.32.3-gke.1785003, which ships kernel 6.8.0-1022-gke.

    Root cause
    Component
    Contributing factor
    Detection

    An OpsGenie alert fired when one ClickHouse cluster stopped receiving queries, metrics and customer connection logs.

    Remediation
    • added maintenance exceptions to pause all upgrades on the GKE clusters that were not yet affected
    • changed the load balancer health check policy to ignore failed kube-proxy health checks, so traffic flowed to the nodes again
    • began migrating the affected clusters from the ubuntu_containerd to the cos_containerd node image by recreating nodes
    Action items
    • Expand image pre-testing pipelines to catch regressions earlier
    • Enable notifications for upcoming GKE auto-upgrades
    • Make GKE maintenance windows required across the fleet to control when upgrades roll out
    • Track Google's issue and wait for a patched Ubuntu image
    Lessons

    A managed node upgrade can break kube-proxy in a way that leaves pods and nodes looking healthy while the load balancer sends nothing, because the load balancer health check depends on kube-proxy. kube-proxy's own logs showed the cause. Altinity recommends that GKE users on ubuntu_containerd restore traffic by switching to externalTrafficPolicy: Cluster, which disables the kube-proxy health check in the load balancer, move production workloads to cos_containerd, and pause auto-upgrades where possible until a patched image has been confirmed and tested.

  2. Symptoms

    On a Tuesday morning a developer reported that some production logs were missing. Only the logs from a single node were gone; the other nodes kept shipping normally through fluent-bit, the log shipper the team had run for more than three years.

    Root cause
    Component
    Contributing factor
    Detection

    A developer reported missing production logs; no alert fired because fluent-bit's metrics showed no errors.

    Remediation
    • added CPU to the Elasticsearch virtual machines, which cleared the write queue rejections
    • rolled out Fluentd one node at a time, using node affinity to place Fluentd and anti-affinity to remove fluent-bit
    • lowered Fluentd's flush_thread_count to 1 and set flush_interval to 5 seconds so the backlog of old logs did not overflow the buffer
    • enabled Fluentd's Position DB so already-ingested data was skipped
    Action items
    • Build monitoring for Fluentd on its Prometheus integration, including a throughput alert with separate day and night thresholds or a black-box log check
    Lessons

    A log shipper can fail without an error message and with metrics that simply stop moving, so error-based alerts never fire; throughput alerts or end-to-end checks can catch it. Open source software can break in ways nobody expects, and sometimes the way out is to switch to a different shipper fast, node by node. A new shipper that starts from scratch replays every old log on the node and needs to be slowed down.

  3. Symptoms

    Services on Buffer's kops-managed cluster on AWS (about 60 nodes and 1500 containers) answered more slowly than they should have. The container throttling metric showed that many containers were being throttled whatever their CPU usage was, including containers that never came close to their CPU limit.

    Trigger

    CPU limits on user-facing services, enforced through CFS quota by a Linux kernel with a bug that throttled containers even when they were well under their limit.

    Root cause
    Component
    Contributing factor
    Detection

    While reviewing the container throttling metric, the team noticed many containers being throttled even though their CPU usage stayed far below their limits.

    Remediation
    • removed CPU limits from all services directly or indirectly on the users' critical path
    • moved those services to dedicated tainted nodes and gave them matching tolerations
    • set each service's CPU request to its peak usage over a few months plus a margin of more than 20%, and set memory requests the same way
    Action items
    • Move nodes to a kernel that contains the CFS throttling fix (4.19 or later), which for Buffer means a kops version whose host image is Ubuntu 20.04
    • After the kernel upgrade, check whether throttling is fully gone and update the post
    Lessons

    A CPU limit can slow a service down even when the service uses a small part of it, because of how the kernel enforces CFS quota on older kernels; the throttling metric shows it, the CPU usage graph does not. Upgrading the kernel is the safer fix. Removing limits works for latency, but only together with honest CPU and memory requests, isolation of the unbounded services, and monitoring of node usage, since unbounded containers can starve the kubelet.

  4. Symptoms

    For about six months, applications on Omio's Google Kubernetes Engine clusters stalled at random: they got stuck, stopped answering health check requests or lost network connections, and nothing the team looked at explained why.

    Trigger

    Multi-threaded workloads running with CPU limits on nodes whose kernel did not yet have the fix for a known CFS quota bug that causes unnecessary throttling.

    Root cause
    Component
    Contributing factor
    Detection

    Months of random stalls and failed health checks led the team to read the cgroup cpu.stat throttling counters inside the pods, which showed far more throttling than the limits should allow.

    Remediation
    • removed CPU limits until the kernel with the CFS bug fix was deployed across all clusters
    Action items
    • Deploy the kernel with the CFS quota bug fix across all clusters
    • Monitor utilisation, saturation and error metrics, API latency and error rates to confirm the change behaves as expected
    Lessons

    A CPU limit is a time quota per 100 ms period, not a share of cores, so a multi-threaded container can be stopped for most of each period long before it uses the cores it was given, and a kernel bug can make that worse. Throttling is invisible in standard Kubernetes metrics and has to be read from the cgroup counters. Removing limits trades away protection against a container that takes a whole node, which is only acceptable when runtimes are tuned.

  5. Symptoms

    An alert fired because some Metrictank instances could not drain their write queue, which meant they could not write to Cassandra. Google had not yet published an incident, but a team member's Discord server, also hosted on GCP, was down, which pointed at GCP; Google confirmed an SSD persistent disk incident about 90 minutes after it began.

    Trigger

    A Google Cloud incident in which SSD persistent disks performed so poorly that many I/O operations failed for an extended period.

    Root cause
    Component
    Contributing factor
    Detection

    An alert that Metrictank write instances could not flush their write queue to Cassandra. Error rates alone rose too slowly to notice quickly, because most queries were served from memory.

    Remediation
    • Added compute nodes hoping new nodes could attach the disks, which did not work
    • Deleted and recreated the Cassandra StatefulSet with an updated pod management policy, so all pods but one started
    • Raised Kafka topic retention to avoid data loss during the long downtime
    • Temporarily added nodes so Metrictank restarts were not slowed by CPU starvation
    • Restarted all Metrictank instances, which took more than 20 hours, so they connected to the new Cassandra IPs
    Action items
    • Re-instantiate the gocql connection in Metrictank when it is detected dead, so it reconnects even when all Cassandra IPs change
    • Fix the Metrictank write-queue deadlock by updating an internal data structure with atomics instead of a lock
    Lessons

    An OrderedReady StatefulSet cannot recover past a single pod whose volume will not attach; when every pod is down, the ordering that protects normal start-up blocks the whole cluster. A client that learns peer addresses only from live peers needs a way to go back to the service name when all peers are replaced at once. A long-tolerated bug with a config workaround can surface at the worst time; this one turned out to have a simple fix. Writing incoming data to a Kafka write-ahead log first meant all data could still be ingested after recovery, and Kafka on non-SSD disks escaped the disk incident. With both Metrictank bugs fixed, the team expects a similar event to take less than 3 hours to recover from instead of 23.

Check your cluster for this

These 9 cases involve Linux kernel and Node operating system image. 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 cause5

Breaking change in an upgrade1 case

Organisation
  1. IL-0079 A GKE node auto-upgrade to an ubuntu_containerd image with a kernel regression left kube-proxy unable to apply its ip6tables rules, so load balancer health checks failed and several clusters lost all ingress traffic

Software defect5 cases

  1. IL-0041 fluent-bit silently stopped shipping application logs from one node to Elasticsearch
  2. IL-0029 Slow user-facing services from CPU throttling on containers that used far less CPU than their limit
    Buffer2020
  3. IL-0012 CPU limits and an unpatched kernel CFS quota bug throttled multi-threaded services into stalls, failed health checks and timeouts
    Omio2020
  4. IL-0030 Most nodes of a cluster went NotReady together for 15 minutes while the API server sat behind an AWS ELB
  5. IL-0074 All AirMap platform services down as worker nodes went NotReady and pods crash-looped on network and DNS failures
    AirMap2018

Cloud provider outage1 case

Organisation
  1. IL-0193 A GCP persistent disk degradation took down a Cassandra StatefulSet whose OrderedReady policy blocked recovery, and Metrictank could not reconnect to the recreated pods, causing a 23-hour Graphite query outage

DNS or network fault1 case

Organisation
  1. IL-0057 Higher p99 latency after moving a reverse proxy to EKS, from outgoing connections delayed by a SNAT conntrack race
    Prezi2019

Dependency failure1 case

Organisation
  1. IL-0073 Intermittent Kafka connectivity overloaded Docker daemons, set off a node rescheduling cascade and poisoned the Consul gossip mesh
    Target2019