Cases4 cases
1 to 4 of 4
IL-0153DOKS worker nodes went NotReady at 06:00 UTC on three days because a systemd timer in the Debian image ran apt upgrade and killed it mid kernel upgrade, breaking node networkingDigitalOcean2023- Symptoms
Customers of DigitalOcean Managed Kubernetes (DOKS) saw worker nodes go NotReady between 06:00 and 07:00 UTC and stay unavailable, taking down the services on them, until the nodes were replaced or rebooted; some nodes needed several replacements or reboots. The first sporadic reports on October 8 said replacing the node fixed it. The same thing happened again around 06:00 UTC on October 9, more widely and across many regions, and again on October 10. Only clusters on versions 1.27.6-do.0 and 1.28.2-do.0 were affected.
- Trigger
A systemd timer in the DigitalOcean Debian image started apt upgrade daily at 06:00 UTC, with a random delay of up to 60 minutes.
- Root cause
- Component
- Contributing factor
- Detection
Sporadic customer reports of failed worker nodes arrived at 07:43 UTC on October 8; internal incident response started at 07:10 UTC on October 9 after broader impact across regions.
- Remediation
- Advised customers to replace or reboot affected worker nodes
- Arranged SSH and console access to worker nodes while they were healthy, and live-debugged an affected node on October 10
- Released a DaemonSet to all affected clusters that disables the apt upgrade systemd timer on every worker node
- Released new node images without the auto-update process
- Action items
- Disable the timer during node provisioning, then remove the DaemonSet from all clusters
- Add a check to the internal conformance test suite for new cluster versions that the auto-upgrade process and other unwanted timers stay disabled
- Support logging into worker nodes even when normal access paths are broken
- Lessons
An operating system auto-update timer left enabled in a node image can change the kernel and systemd underneath Kubernetes, and a timeout that kills the upgrade half-way can leave a node without networking. Failures that start at the same time every day point to a scheduled job on the nodes, and systemd timers belong on that list next to cron jobs. When the failure takes out a node's network, an investigation that depends on logging into the node stalls; access paths that work while the node is broken shorten diagnosis.
- Symptoms
At 09:33 UTC on 14 February 2023 end users told the platform team that Kubernetes logs were not arriving in CloudWatch as expected. The investigation went through fluentd and found that the nodes were running containerd as their container runtime instead of docker-shim. A scheduled node rollover the day before, at 07:30 UTC on 13 February, had set containerd as the default runtime by accident.
- Trigger
A scheduled node rollover had accidentally made containerd the default container runtime, which stopped log shipping to CloudWatch; the unscheduled rollover to revert it timed out, and the pipeline run that followed reduced the Auto Scaling group from 30 to 15 instances.
- Root cause
- Component
- Contributing factor
- Detection
End users reported the missing CloudWatch logs that started the work. The postmortem lists 2 minutes as the time to detection of the node failure.
- Remediation
- ran the node rollover script to add new nodes, which failed on a timeout from Docker Hub
- ran the node rollover script a second time, which added new nodes that the load balancer marked healthy at 11:01 UTC
- Action items
- Document the rollover process, especially what can be done when it goes wrong
- Investigate options for improving the rollover process
- Add fluentd log collection to the QA test suite so logs are covered end to end
- Add alarms for fluentd when too little or no log data is sent
- Implement a staging environment
- Implement guards against selecting an invalid container runtime
- Lessons
When a change goes wrong, rolling back to a known working configuration is safer than rushing a fix, which can make the damage worse. Launching new worker nodes depends on the cloud-init script not failing in any way. The QA configuration differed from production, there was no staging environment, the QA tests did not cover fluentd log collection, and the rollover process had no documentation for when it fails.
IL-0191A label selector accidentally added to the Loki distributor Service matched only the new pods of a rollout, which took all write traffic, were OOM-killed and stalled the rolloutGrafana Labs2022- Symptoms
During a rollout of the Grafana Loki distributor Deployment in one Grafana Cloud Logs environment, the write path went down for about 25 minutes. The newly started distributor pods were OOM-killed over and over, never passed their health and readiness checks, and the rollout stopped making progress.
- Trigger
Step 1 of moving the Loki ring off a separately deployed key-value store onto embedded memberlist added a new label, gossip_ring_member: 'true', to the distributor pods and Service, together with a small config change, and the change required a rollout of the distributors.
- Root cause
- Component
- Contributing factor
- Detection
The first clue was kubectl get pods and the kube_deployment_status_replicas_updated metric showing that only 16 of 140 distributor pods had been updated.
- Remediation
- scaled the distributor Deployment out horizontally so the load spread over more pods with the new label and the rollout could continue
- reverted the migration step to end the outage
- set service_ignored_labels:: [$._config.gossip_member_label] and passed it to k.util.serviceFor so the label is no longer copied into the Service selector
- Action items
- Update the function that generates a Service from a Deployment or StatefulSet to handle edge cases, including this one
- Lessons
A Service whose selector is built by copying every label of a workload changes which pods it matches as soon as a new label is added. During a rollout it then matches only the new pods, which receive all the traffic before there are enough of them. A few errors during a rollout in other environments hid the problem, because those environments gave distributors more memory and could absorb the shift. Manifest diffs kept for every pull request made it possible to see that the Service selector had changed.
IL-0055A failing CronJob with the default concurrency policy piled up thousands of restarting pods and took down a clusterTarget2018- Symptoms
A Kubernetes cluster went down after one CronJob kept failing and its pods piled up. Because each failed run kept restarting instead of being replaced by the next one, the pods accumulated into the thousands. The speaker's arithmetic for a job scheduled every minute that fails for three days is 4,320 restarting pods.
- Trigger
A CronJob kept failing.
- Root cause
- Component
- Contributing factor
- Lessons
When deploying a CronJob, set its concurrency policy to Replace or Forbid; with the default, failing runs accumulate and restart together. An application should handle a missing dependency with probes and bounded back-off rather than crash in a loop, which also keeps it from hammering a dependency that is already struggling.
These 4 cases involve Node pool and Configuration templating. 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 cause1
Configuration change4 cases
- Component
- Contributing factor
- Organisation
IL-0153DOKS worker nodes went NotReady at 06:00 UTC on three days because a systemd timer in the Debian image ran apt upgrade and killed it mid kernel upgrade, breaking node networkingDigitalOcean2023IL-0109A retried node rollover on a DFDS EKS cluster set the Auto Scaling group back to 15 instances, and the default termination policy removed every healthy worker node, leaving the cluster with no nodesDFDS2023IL-0191A label selector accidentally added to the Loki distributor Service matched only the new pods of a rollout, which took all write traffic, were OOM-killed and stalled the rolloutGrafana Labs2022IL-0055A failing CronJob with the default concurrency policy piled up thousands of restarting pods and took down a clusterTarget2018