Graph
Cases4 cases
1 to 4 of 4
IL-0500UToronto JupyterHub logins and server starts returned 500 errors when the hub's sqlite database disk filled up2i2c2022- Symptoms
On 31 October 2022 at 6:27 PM Pacific time, users of the UToronto JupyterHub run by 2i2c could no longer log in or start their servers, and the hub answered with 500 errors. Users who were already logged in could keep using the hub.
- Trigger
The JupyterHub log file, written to the same 10G disk as the hub's sqlite database, grew until the disk was completely full.
- Root cause
- Component
- Contributing factor
- Detection
A user emailed 2i2c support at 7:13 PM that users could not log in; the team acknowledged the issue at 8:33 PM. There was no alert for the problem.
- Remediation
- Compressed the hub log file into /tmp from a shell in the hub pod, because it could not be compressed in place on the full disk
- Copied the compressed log to a local machine so the hub pod could be restarted without losing it
- Resized the hub database disk (the hub-db-dir PVC) from 10G to 60G
- Restarted the hub pod, which came back with the larger disk and restored service
- Action items
- Stop keeping hub logs on the same disk as the hub database
- Add a Grafana graph of free space on the JupyterHub database disk
- Alert on elevated error rates
- Lessons
Kubernetes dynamic volume resizing let the hub database disk grow from 10G to 60G without much effort. The risk of keeping logs on the database disk had been identified during the earlier migration, but the team had no solid process for following it through, and because no alert existed the team had to wait for a person to report the outage.
IL-0009A duplicated generated name made Argo CD replace the InfluxDB Cloud production Application and delete the whole production environmentInfluxData2022- Symptoms
Right after a pull request to the infrastructure-as-code repository was merged, every API endpoint of one InfluxDB Cloud production cluster began returning 404 errors. Writes and reads failed alike: no one could collect data, scheduled tasks failed to run and external queries did not work.
- Trigger
A merged pull request whose rendered YAML added a new Argo CD Application and AppProject that an automation error had named app01-cluster01, the name of the existing production Application, instead of app02-cluster01; reviewers did not notice the app01 and app02 difference.
- Root cause
- Component
- Contributing factor
- Detection
Monitoring and alerting did not detect the issue right away, so the team's first response was to try to roll the change back rather than plan a recovery. The write-up does not say how the team found out.
- Remediation
- stopped the revert of the merged pull request
- restored the etcd metadata cluster
- recreated the missing Kubernetes objects so the retained PersistentVolumes became available, then recreated the StatefulSets
- restored the Zookeeper volumes from an hourly Velero backup
- rebuilt the Kafka StatefulSet one pod at a time with health and readiness checks disabled
- accepted writes into the Kafka write-ahead log and scaled up the write path with more replicas and higher memory requests and limits
- recreated the storage pods, which downloaded data from object storage, reindexed it and replayed the write-ahead log
- re-enabled Argo CD, queries, dashboards and scheduled tasks, restored replica counts and ran final QA checks
- Action items
- Write runbooks for restoring state when Kubernetes objects such as PersistentVolumeClaims are deleted but the data on the underlying volumes is preserved
- Set every volume in every environment to retain data when its PersistentVolumeClaim is deleted
- Improve the process for handling public-facing incidents
- Store generated YAML as one object per file, so an overwrite of an existing object shows up as such in review
- Detect duplicate objects when generating YAML and warn before review, treating objects with the same group, namespace and name as the same even when the apiVersion string differs
- Add the Argo CD Prune=false annotation to all stateful resources and to Namespace objects managed by Argo CD
- Set FailOnSharedResource=true on Argo CD Applications so Argo CD fails before changing an object another Application manages or managed
- Lessons
The biggest gap was that monitoring did not notice the deletion quickly, which pushed the team toward a reflex rollback; in a stateful system a revert can create a new, empty instance instead of bringing the old one back. Retained volumes and clients that retry writes are what kept data loss at zero. Rendering many objects into one file let an overwrite of an existing object look like an addition, so generated configuration needs one object per file and duplicate detection that compares objects the way Kubernetes does. Stateful resources need protection from pruning, and that protection must cover their Namespace too, or deleting the namespace removes everything inside it.
IL-0193A 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 outageGrafana Labs2019- 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.
IL-0518gitlab.freedesktop.org on GKE ran short of volume space and a planned 30-minute storage upgrade became a 4-hour outagefreedesktop.org2018- Symptoms
Shortly after 9am UTC on 17 July 2018, the disk space of the GitLab cluster behind gitlab.freedesktop.org was critical, and some API requests were failing because of the shortage. The administrator first learned of the failure when people mentioned it on IRC.
- Trigger
Many recently created forks of Mesa, each about 2.1GB, filled the disk space of the GitLab cluster.
- Root cause
- Component
- Contributing factor
- Detection
People mentioned the failure on IRC. Monitoring and alerting on disk usage and API error rate had not been set up yet.
- Remediation
- Dropped all inbound traffic to GitLab at the firewall except from the administrator's IP
- Took a manual backup by streaming tar over SSH to an encrypted partition on a local machine
- Snapshotted all GCE disks behind the PersistentVolumes
- Copied the data from the old disk snapshots to new enlarged volumes through a temporary GCE VM
- Re-did the copy into new empty volumes with the correct directory structure and checked repositories, users and workflows
- Restored public access to GitLab
- Action items
- Set up monitoring, logging and alerts
- Find ways to communicate outages much better; this one was announced only on IRC, and the lists were not told when it dragged on
- Use the Cloud console clients instead of the slow Cloud Console web UI
- Add more GitLab administrators, ideally someone familiar with Kubernetes deployments
- Move from the single Omnibus container to GitLab's cloud native deployment with one container per service
- Move storage to resizeable volumes or to Google Cloud Storage
- Lessons
The backup step alone used up the outage window; backups had grown along with the disk problem, and a test run before announcing the window could have measured it. The changes had been tested on a scratch cluster, but not exactly as run, and tests of steps such as disk snapshots could have been more realistic. A single GitLab administrator who was new to Kubernetes was a single point of failure. Keeping at least three copies of the data from the first destructive step meant no data was lost.
These 4 cases involve Persistent volumes and stateful sets and Database. 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 cause3
Capacity exhaustion2 cases
- Contributing factor
- Organisation
Configuration change1 case
- Contributing factor
- Organisation
Cloud provider outage1 case
- Contributing factor
- Organisation