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

Cases25 cases

16 to 20 of 25

  1. Symptoms

    From April 11, 2022 at 13:17 UTC customers and Gitpod staff reported that Gitpod workspaces were intermittently becoming unresponsive. CPU usage of nodes and pods looked normal, with nothing maxed out, and at 13:58 UTC the team found that the workspaces were IO bound rather than CPU bound.

    Trigger

    The ws39 generation of workspace clusters, released to all regional clusters on April 8th at 20:08 UTC and to the XL clusters on April 9th at 17:45 UTC, split the 1TB disk into smaller RAID0 disks, changed CPU limiting and workspace networking, and moved to faster machine types.

    Root cause
    Component
    Contributing factor
    Detection

    Customers and Gitpod staff reported on April 11th at 13:17 UTC that workspaces were intermittently unresponsive, and the team opened an incident in Slack through its incident.io integration. On April 17th the team noticed increased CPU load on the workspace nodes and opened an internal incident.

    Remediation
    • Shifted workspace starts back to the ws38 clusters on April 11th
    • Built ws39a clusters with c2d machines and local SSDs and moved traffic to them
    • Requested a limit increase from Let's Encrypt
    • Routed EU XL traffic to the regional EU cluster and built ws-eu39bxl to replace the crashed ws-eu39xl
    • Cleaned up workspaces stuck in a stopping state so users could start them again
    • Released ws40 with 1TB boot disks to get more IO bandwidth
    • Removed the workspaces that consumed excessive CPU time for crypto-mining
    • Blocked the fraudulent users behind the crypto-mining from using Gitpod
    • Rolled back the ws-daemon change that broke CPU limiting and shipped the fix in the ws34 clusters
    • Blocked ACME HTTP requests to workspace ports so Let's Encrypt rate limits would not be hit again
    • Rolled out IO limiting with the ws41xl and ws41 clusters and moved traffic to them step by step
    Action items
    • Invest in test automation so that test results stop releases like this one
    • Vary the interval between traffic shifts to new clusters, with more time for larger releases
    • Add a risk assessment stage, to be automated, that governs changeset size and rollout speed of workspace cluster rollouts
    • Reduce the impact teams have on each other
    • Add review criteria that find backwards incompatible changes before pull requests are merged, and split such pull requests
    • Recommend rollback as the primary means of mitigation in the incident procedures, and look at automating it
    • Make the status page show the workspace service as down when it is, and update the playbooks
    • Keep incident communication in a single Slack channel and Google Meet
    • Put 10% of the engineering staff on the on-call rotation from May 9th and use that time on observability, alerting and stability
    Lessons

    Gitpod concluded that it should have committed to rolling back on April 11th instead of building and shipping fixes, which kept customers on degraded workspaces longer than necessary. A large release so soon after the previous one needed a risk assessment and slower traffic shifts, and backwards incompatible changes that block a rollback need to be found before pull requests are merged. Failure-free operations require experience with failure.

  2. Symptoms

    KubeSpawner, which starts JupyterHub user containers on Kubernetes, failed to create containers with an error the author had never seen, saying an SSL certificate had expired.

    Root cause
    Component
    Contributing factor
    Detection

    KubeSpawner failed to create a container and logged an SSL certificate verification error.

    Remediation
    • checked certificate expiry with kubeadm alpha certs check-expiration
    • moved the old certificates and /etc/kubernetes/*.conf files to a backup directory
    • regenerated all certificates with kubeadm init phase certs all
    • regenerated the kubeconfig files with kubeadm init phase kubeconfig all
    • copied /etc/kubernetes/admin.conf to ~/.kube/config and restarted kubelet
    • restarted the kube-system containers with docker restart so they picked up the new credentials
    Lessons

    kubeadm clusters run on certificates that expire, and when the API server certificate expires kubectl cannot be used to fix it, so renewal has to happen on the control plane node with kubeadm. After renewal, the kubeconfig files and the running control plane containers must also pick up the new certificates, or kubectl returns Unauthorized.

  3. Symptoms

    In 2020 Chatwork moved its legacy system from EC2 to EKS, running both sides in parallel with Route53 weighted records. Once more than a certain share of requests was sent to the EKS side, the service suddenly became unstable. On some nodes the conntrack table had gone past its limit and connections to the application were being dropped.

    Trigger

    During the migration from EC2 to EKS, Chatwork sent more than a certain share of requests to the EKS side. Later, applying node-local-dns with force_tcp in its configuration made DNS unstable again.

    Root cause
    Component
    Contributing factor
    Remediation
    • Raised the conntrack maxPerCore value in the kube-proxy configuration
    • Installed dns-autoscaler so CoreDNS ran with more pods
    • Installed node-local-dns as a DaemonSet on every node
    • Replaced force_tcp with prefer_udp in the node-local-dns configuration
    Lessons

    On EKS, dns-autoscaler and node-local-dns made DNS stable, but node-local-dns must not use force_tcp there. Stable DNS also matters for sizing the number of pods correctly, since blocked DNS queries had made the pod count grow.

  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

    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.

Check your cluster for this

These 25 cases involve CoreDNS and Client-side DNS resolver and 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 cause7

Capacity exhaustion15 cases

  1. IL-0071 Worker node running out of inodes while disk space looked fine, because containerd kept a full node_modules tree in each of several image layer snapshots
  2. IL-0155 Some DOKS clusters in NYC1 saw intermittent DNS timeouts and NodeNotReady events because CoreDNS ran on shared-CPU Droplet worker nodes
  3. IL-0581 29CM product display servers lost pods and saturated Netty event loops on the first day of the Igu Week sale
  4. IL-0048 DNS lookups timed out in a large EKS cluster when CoreDNS hit the 1024 packets-per-second link-local limit, driven by sudo hostname lookups
  5. IL-0085 A control plane node of Magic Pages' Kubernetes cluster on Hetzner Cloud ran out of memory, the cluster's own calls then used up the Hetzner API rate limit, and all customer websites were down for about 7.5 hours
  6. IL-0044 Prometheus OOMKilled in a loop while replaying its write-ahead log after a kube-prometheus-stack upgrade
  7. IL-0046 Prometheus restarted again and again because its WAL replay took longer than the startup probe allowed
  8. IL-0194 After a kube-apiserver restart, pod LIST requests from every pod of a Vector DaemonSet nearly tripled etcd memory and restarted all master nodes
    Palark2023
  9. IL-0445 Chatwork's service on EKS became unstable as conntrack tables on some nodes overflowed and connections were dropped
  10. IL-0013 The conntrack table filled up on downsized GKE nodes and a high-traffic aggregation proxy saw climbing connection resets
  11. IL-0015 A GKE cluster's /16 pod address range ran out at 256 nodes, leaving new pods Pending and node scale-ups failing
  12. IL-0037 Image registry rate-limited a whole region after a crash-looping DaemonSet with imagePullPolicy Always pulled through three NAT instances
  13. IL-0075 Kubernetes API servers pegged on CPU when the cluster grew to about 290 nodes, traced to Datadog agents polling the API
  14. IL-0001 Cluster-wide DNS outage after CoreDNS pods were OOM-killed again and again under a burst of DNS queries
  15. IL-0468 New JupyterHub student pods stuck Pending on MaxVolumeCount after a memory limit cut with node size unchanged

DNS or network fault2 cases

Organisation
  1. IL-0448 Requests from Uzabase's Kubernetes Job pods to an LLM agent randomly never got responses when they ran past 15 minutes
  2. IL-0083 Intermittent 5xx errors in a multi-tenant Kubernetes cluster came from internal DNS: the node-local dnsmasq hit its 150 concurrent query limit, did not cache cluster.local answers, and ndots search lookups flooded CoreDNS

Configuration change2 cases

Organisation
  1. IL-0499 Discord voice and video calls hung at Awaiting Endpoint for three hours after 17% of sessions stopped at once
  2. IL-0461 Every rollout of Datadog's metrics query service on Kubernetes raised errors that the logs blamed on DNS

Dependency failure2 cases

  1. IL-0103 During an EKS node AMI update, Istio sidecars crash-looped because hundreds of pods restarting at once overloaded the external certificate authority behind istiod
  2. IL-0159 Docker Hub rate-limited Linode's IPv6 address space with 429 Too Many Requests, breaking image pulls for LKE and LKE-E clusters
    Linode2025

Software defect2 cases

  1. IL-0151 A latent defect in the AWS Lambda Frontend, set off when one us-east-1 cell scaled past a size never reached before, raised errors for Lambda and for services that depend on it, including new EKS cluster provisioning
  2. IL-0012 CPU limits and an unpatched kernel CFS quota bug throttled multi-threaded services into stalls, failed health checks and timeouts
    Omio2020

Faulty deployment1 case

Organisation
  1. IL-0591 Gitpod workspaces in all regions became IO bound and unresponsive for days after the ws39 workspace cluster release
    Gitpod2022

Certificate or credential expiry1 case

Organisation
  1. IL-0184 JupyterHub's KubeSpawner could not create containers and kubectl was refused because the API server and other internal certificates of a kubeadm cluster had expired
    dbhang2021