Cases2 cases
1 to 2 of 2
IL-0094Student pods filled the shared nodes of a JupyterHub cluster and starved the hub's core pods, freezing the hub2i2c2020- Symptoms
At 08:52 PM IST a report came in from WER that many students could not access the JupyterHub and that it was frozen; pages were stuck and nothing was usable. A rise in activity was visible by 09:02 PM, but the usual fixes, such as opening an incognito window and restarting servers, did not help.
- Trigger
WER students' pods used a good chunk of their memory limit (tests had shown they almost always use just under 1G of their 2G limit, against a 512M guarantee) on nodes shared with the hub's core pods.
- Root cause
- Component
- Contributing factor
- Detection
WER reported stuck pages and students unable to reach the hub in a GitHub issue (2i2c-org/docs#27).
- Remediation
- removed memory overcommit for the WER students
- raised resource guarantees for all core pods, which restarted them and moved some to a new node
- Action items
- Put user pods in a separate pool so they do not create pressure on the core pods (infrastructure#89)
- Set limits on the support infrastructure (Prometheus, Grafana, ingress) as well (infrastructure#90)
- Document and think about overcommit ratios for memory usage (infrastructure#91)
- Set up better Grafana dashboards to monitor resource usage (infrastructure#92)
- Document how people can get kubectl access to the cluster so others can look into issues too (infrastructure#87)
- Lessons
Core pods without resource guarantees get whatever is left on a node, so when user pods on the same nodes fill the CPU and memory, the hub that serves everyone freezes. The memory overcommit ratio has to come from measured use: WER students used just under 1G against a 512M guarantee, which a 4x overcommit could not hold.
IL-0052A cryptocurrency miner ran on every node of the development and staging clusters through a public, unauthenticated Weave Scope dashboardJW Player2019- Symptoms
Datadog alerted the DevOps team to a high normalised load average, first on the staging cluster (Day 0, 21:06 EST) and the next day on the development cluster (Day 1, 16:53 EST). The load was first put down to a legitimate service that kept scaling up and down in both environments, and because of the volume of identical alerts they were muted until things settled.
- Trigger
An automated crawler found the Weave Scope dashboard on a public load balancer that required no authentication. Weave Scope can open a shell in running containers, and its scope-agent containers ran privileged, as root and with the host's root filesystem mounted, so a command started there could run on the host.
- Root cause
- Component
- Contributing factor
- Detection
Datadog alerts on high normalised load average, muted at first as noise from a legitimate service; on Day 3 an engineer ran top on a node and found the gcc process at 100% CPU.
- Remediation
- stopped Weave Scope and removed its deployment from all Kubernetes clusters
- checked access logs for unauthorised access to the instances
- confirmed the miner's outbound connections went only to a mining pool
- isolated one affected node for later investigation
- rotated out every node in each cluster so all affected hosts were destroyed and rebuilt
- Action items
- Audit all Kubernetes and deployment YAML files and security groups for services that are unintentionally public or misconfigured
- Replace load-average alerts with more meaningful monitors and tune them to signal a real anomaly
- Research tools such as falcon or sysdig for behavioural monitoring and anomaly and intrusion detection
- Evaluate Istio and Linkerd for observing and controlling end-to-end network traffic
- Analyse the cost of scanning Docker images and containers for known vulnerabilities
- Set aside time in architecture discussions to revisit older choices such as running containers as root
- Share knowledge of large projects, such as Kubernetes version migrations, across the whole team
- Lessons
Load average was not a useful signal for spotting a problem in the clusters, and muted noisy alerts nearly hid the miner. A load balancer that Kubernetes creates belongs to Kubernetes: a manual security group edit in the AWS console is reverted, so internal exposure must be declared in the Kubernetes YAML. A dashboard that can open shells, in front of privileged agents that mount the host's root filesystem, gives whoever reaches it root on every node.
These 2 cases involve Cloud load balancer and Cluster dashboard. 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 exhaustion1 case
- Component
- Contributing factor
- Organisation
Configuration change1 case
- Component
- Contributing factor
- Organisation