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

Cases6 cases

3 to 6 of 6

  1. Symptoms

    After the switch to Traefik v2, functional tests indicated that everything was fine, and this was reported on Slack at 08:44 UTC. The first sign of trouble came at 09:26 UTC, when a developer reported a high count of HTTP 307 redirects, especially on the Okta service. At 09:32 UTC the team learned that the online booking system was down.

    Trigger

    At 08:22 UTC the AWS load balancers were updated to send requests to the new Traefik v2 reverse proxy as part of the migration away from Traefik v1.

    Root cause
    Component
    Contributing factor
    Detection

    A developer reported a high count of HTTP 307 redirects, in particular on the Okta service, at 09:26 UTC, 64 minutes after the change; six minutes later the team was told the online booking system was down. The functional tests run after the switch had not caught it.

    Remediation
    • Rolled back the switch to Traefik v2, putting rollback ahead of investigation because of how critical the booking system is
    Action items
    • Consider how critical announcements can be made more visible
    • Consider whether the ALBs used for testing should have been shared with the teams so they could test their own scenarios
    Lessons

    Cloud Engineering cannot test every application scenario on its own, even after testing its own applications for weeks. A header that changes value behind a new ingress controller, here x-forwarded-proto going from https to http, can break an authentication flow while basic functional tests still pass. DFDS asks whether diffing request headers before and after the migration would have shown the problem in advance.

  2. Symptoms

    On 25 August 2021, skyscanner.net was unavailable and the Skyscanner mobile apps could not work, for travellers and business partners everywhere at the same time. The full global outage lasted four and a half hours.

    Trigger

    A peer-reviewed change to a rarely changed root-level file of the cells templating configuration, intended as a no-op, that left out the {{ }} delimiters; it was submitted around 15:30 GMT, merged to master and rolled out automatically to every region at once.

    Root cause
    Component
    Contributing factor
    Remediation
    • restored the correct configuration for each cluster and let Argo CD reconcile the cluster back to it
    • restored services through the backup and restoration process
    • brought one region back first with the critical services and served all traffic from it from around 20:30 GMT
    • restored and verified the remaining regions and non-critical services over Thursday and Friday
    Action items
    • Avoid global configuration deploys, including rare change paths like this one
    • Treat templated configuration as code and add testing and linting
    • Plan and wargame more drastic failure scenarios in runbooks
    • Verify backup and restore processes, including access to the backups and the loss of a region
    • Refactor runbooks so they are clear and, where appropriate, idempotent for a stressed engineer in the early morning
    • Reconsider how much configuration is templated across regions, weighing configuration drift against automated global rollout
    Lessons

    Global configuration changes had been prevented in many cases, but not in this rarely used path. Configuration that gains templating and logic has become code and needs tests and at least linting. The failure scenarios and runbooks were not pessimistic enough, a backup only counts once it has been restored, and runbooks need care so they work for a stressed engineer at night. Automation that templates configuration across regions trades drift for the risk of rolling one mistake out everywhere. An experienced incident commander who kept the response calm and blameless made a large difference.

  3. Symptoms

    On Friday 19 July 2019 the Grafana Cloud Hosted Prometheus service, which is built on the Cortex project, was down for 26 minutes. New error-budget-based Prometheus alerts paged the on-call engineer within 4 minutes of the start.

    Trigger

    An engineer created a new dedicated Cortex cluster for a large customer. Its configuration did not include the new pod priorities, so all its pods got the default medium priority, and the Kubernetes cluster did not have enough free resources to fit it.

    Root cause
    Component
    Contributing factor
    Detection

    New error-budget-based Prometheus alerts paged the on-call engineer within 4 minutes of the start of the outage.

    Remediation
    • Scaled up the underlying Kubernetes cluster to fit both the new and the production Cortex clusters
    • Diagnosed and fixed the out-of-memory errors in the authenticating reverse proxies in front of Cortex
    Action items
    • Give the production ingesters the high priority class, which should have been done before medium became the default
    • Have more people review changes to configuration that is global to the cluster
    • Require a design document for every configuration change outside a namespace
    • Automate the sizing of the frontend authenticating reverse proxy so it does not run out of memory under overload
    • Investigate the default backoff and scaling behaviour of Prometheus to prevent a stampeding herd of retries
    Lessons

    Medium should not have become the default priority until the production ingesters had the high priority, and that designation should have reached production sooner. The change was considered too minor for a design document and was only discussed in a GitHub issue; cluster-global configuration needs more scrutiny. On the positive side, once Cortex had enough capacity it recovered by itself, and Grafana Loki helped confirm that the ingesters exited gracefully.

  4. Symptoms

    Terraform, applied from the shared cluster configuration repository after a merge, deleted Spotify's production GKE cluster in Asia. While the team tried to recreate it, Terraform deleted a second production cluster, so two of the three production clusters were gone.

    Trigger

    A feature team's pull request that added three users to an existing RBAC role binding file was merged before the cluster operators' pull request that imported the Asia cluster into Terraform state. The review build of the import pull request had already written the cluster into the shared state file, and the merged configuration had no definition of the Asia cluster, so Terraform removed it.

    Root cause
    Component
    Contributing factor
    Detection

    Internal service discovery could not reach the deleted cluster and the cluster operator team was paged.

    Remediation
    • removed the deleted clusters from the service discovery configuration and restarted service discovery so clients fell back to the instances outside Kubernetes
    • one team that ran half on Kubernetes and half on VMs created more VMs outside Kubernetes to handle the load
    • recreated the clusters, using the hourly backups
    • updated the places where the old clusters' master IPs were hardcoded
    Action items
    • Post the Terraform dry-run output as a comment on each pull request
    • Require a status check that the branch is up to date with master, so the dry run reflects what will actually happen
    • Require an approving review on pull requests
    • Fail reviews automatically when certain keywords such as destroy appear; cluster deletions are done manually outside this repository
    • Add linters and validators for the cluster configuration
    • Schedule and announce disaster recovery tests that cover a cluster going away and smaller failures
    Lessons

    Plan for failure from the start and migrate large infrastructure gradually, so there is redundancy and a way back. A backup whose restore has never been tested is not a backup. Practising disaster recovery paid off: restoring the first deleted cluster took three and a quarter hours, and the team can now restore a larger cluster in one hour. What matters is not who made the mistake but what was learned from it.

Check your cluster for this

These 6 cases involve Argo CD 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 change6 cases

  1. IL-0019 An EKS Terraform module upgrade shrank node root disks from 100 GB to 20 GB and image pulls failed with no space left on device
  2. IL-0009 A duplicated generated name made Argo CD replace the InfluxDB Cloud production Application and delete the whole production environment
  3. IL-0111 Switching the main Kubernetes ingress controller from Traefik v1 to v2 stopped X-Forwarded headers being passed, which broke the Okta login flow for every service using Okta and stopped DFDS online bookings for over an hour
    DFDS2021
  4. IL-0010 A templating change that dropped its {{ }} delimiters made Argo CD delete all 478 Skyscanner services in every region
  5. IL-0004 A new default pod priority let a new Cortex cluster preempt every production ingester in a cascade, taking Grafana Cloud Hosted Prometheus down
  6. IL-0061 A Terraform pull request merged out of order deleted a production GKE cluster, and recreating it deleted a second one