{"id":"IL-0010","org":"Skyscanner","date":"2021-08-25","docs":["https://en.wikipedia.org/wiki/Ishikawa_diagram"],"title":{"en":"A templating change that dropped its {{ }} delimiters made Argo CD delete all 478 Skyscanner services in every region","ko":"템플릿 중괄호가 빠진 설정 변경으로 ArgoCD 가 전 세계 모든 클러스터의 서비스를 지웠다"},"domain":["kubernetes","aws"],"impact":{"scope":"whole product, all regions","users":"all travellers and partners","region":"global"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"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.","ko":"설정에 템플릿과 로직을 넣는 순간 그 설정은 코드가 된다. 팀은 설정의 복잡도를 높이면서도 이 파일을 설정으로만 여겨 테스트도 린트도 두지 않았다. 전역 설정 배포를 막으려고 오래 공을 들였지만, 이 경로로 변경이 나가는 일은 아주 드물어서 미처 떠올리지 못했다. 시나리오와 런북은 이 정도 규모의 장애를 상정하지 않았다. 백업은 복원해 보기 전까지 백업이 아니다. 장애 대응을 지휘하는 인시던트 커맨더를 가장 경험 많은 사람이 맡아 누구도 탓하지 않고 상황을 이끈 것이 복구에 큰 도움이 됐다."},"related":[],"sources":[{"url":"https://medium.com/@SkyscannerEng/how-a-couple-of-characters-brought-down-our-site-356ccaf1fbc3","kind":"blog","license":"unknown","archived":"http://web.archive.org/web/20220508172800/https://medium.com/@SkyscannerEng/how-a-couple-of-characters-brought-down-our-site-356ccaf1fbc3"}],"summary":{"en":"Skyscanner runs its services in cells. A cell sits in one region and consists of several Kubernetes clusters in each availability zone, traffic is prioritised inter-AZ, then inter-region, before going cross-region in a failure mode, and services run in an n+2 configuration so that 100% of traffic can be served with one cluster down and one drained. All of it runs on AWS spot instances. Clusters are kept in shape by GitOps: they reconcile themselves to the configuration in Git through Argo CD rather than a central system pushing changes.\n\nAt around 15:30 GMT an engineer submitted a change to the templating of this configuration. It was peer reviewed, merged and rolled out automatically. The edited file sat at the root of the cells configuration and rolls out regional configuration, so it went everywhere at once. Without the {{ }} delimiters the templating did not run, and every namespace that used the file was reapplied and corrupted. At 16:00 GMT Argo CD reconciled the clusters to this configuration and, finding no valid namespaces, deleted all 478 services worldwide.\n\nGitOps also made the recovery possible: once the correct configuration was back in place for a cluster, the cluster reconfigured itself and came back up. The team knew the backup and restoration process well, although an IAM policy change had made the backups hard to obtain at a critical moment. They restored a single region first and gave priority to critical services, so that by around 20:30 GMT skyscanner.net was serving travellers again with all traffic coming from that one region. Engineers were then sent home to rest, and over Thursday and Friday the other regions and the non-critical services were brought back and verified.","ko":"Skyscanner 는 셀 아키텍처로 서비스를 운영한다. 셀 하나는 리전 하나에 있고, 가용 영역마다 쿠버네티스 클러스터 여러 개로 이뤄진다. 셀 안의 서비스는 n+2 구성으로 배포한다. 클러스터 하나가 고장 나고 하나가 유지 보수로 빠져도 트래픽 전부를 처리할 수 있다는 뜻이다. 모든 서비스는 AWS 스팟 인스턴스에서 돈다.\n\n바뀐 파일은 셀 설정의 루트에 있어 거의 바뀌지 않는 파일이었다. 이 파일은 리전 설정을 배포하는 파일이라, 시스템은 이 변경을 전 세계에 곧바로 밀어 넣었다. {{ }} 가 빠지자 템플릿이 더는 적용되지 않았고, 이 설정을 쓰는 네임스페이스가 모두 다시 적용되면서 망가졌다. GMT 16:00 에 ArgoCD 가 클러스터를 이 설정에 맞추면서 서비스 478개를 모두 지웠다.\n\nSkyscanner 는 GitOps 로 클러스터가 스스로 설정을 맞추게 한다. 그래서 클러스터마다 올바른 설정을 되돌려 놓자 클러스터가 스스로 원래 상태로 돌아왔다. 팀은 리전 하나와 핵심 서비스를 먼저 복구해 GMT 20:30 무렵 리전 하나에서 모든 트래픽을 받으며 skyscanner.net 을 다시 열었다. 나머지 리전과 핵심이 아닌 서비스는 목요일과 금요일에 걸쳐 되살리고 확인했다."},"trigger":{"en":"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.","ko":"GMT 15:30 무렵 한 엔지니어가 앞으로 할 큰 변경을 준비하면서 템플릿 시스템에 변경을 올렸다. 시스템 동작은 바꾸지 않으려던 변경이었다. 셀 설정 루트 파일의 cell: {{ default $cluster.name $cluster.unique_name }} 줄을 cell: $cluster.name 으로 바꿨다. 변경은 동료 리뷰를 거쳐 master 에 머지됐고 자동으로 배포됐다."},"severity":"unknown","symptoms":["service-unavailable","resources-deleted"],"timeline":{"detected_after":null,"resolved_after":"4h 30m"},"date_kind":"incident","detection":null,"components":["argocd","config-templating"],"root_cause":"config-change","remediation":[{"text":{"en":"restored the correct configuration for each cluster and let Argo CD reconcile the cluster back to it","ko":"클러스터마다 올바른 설정을 되돌려 놓고, GitOps 로 클러스터가 스스로 올바른 상태로 돌아오게 했다."}},{"text":{"en":"restored services through the backup and restoration process","ko":"팀이 익숙하게 다루던 백업과 복원 절차로 서비스를 복원했다."}},{"text":{"en":"brought one region back first with the critical services and served all traffic from it from around 20:30 GMT","ko":"리전 하나와 핵심 서비스를 먼저 복구해 GMT 20:30 무렵 리전 하나에서 모든 트래픽을 받았다."}},{"text":{"en":"restored and verified the remaining regions and non-critical services over Thursday and Friday","ko":"목요일과 금요일에 걸쳐 나머지 리전과 핵심이 아닌 서비스를 되살리고 확인했다."}}],"action_items":[{"text":{"en":"Avoid global configuration deploys, including rare change paths like this one","ko":"이번처럼 드물게 쓰이는 변경 경로에서도 설정 변경을 전 세계에 한꺼번에 배포하지 않게 한다."}},{"text":{"en":"Treat templated configuration as code and add testing and linting","ko":"템플릿과 로직이 들어간 설정을 코드로 다루고, 테스트와 린트를 도입한다."}},{"text":{"en":"Plan and wargame more drastic failure scenarios in runbooks","ko":"시나리오와 런북이 최악의 재해 규모까지 다루게 하고, 더 극단적인 상황을 워게임으로 연습한다."}},{"text":{"en":"Verify backup and restore processes, including access to the backups and the loss of a region","ko":"백업과 복원 절차를 검증한다. 필요할 때 백업을 실제로 꺼낼 수 있는지, 리전 하나가 내려간 경우에도 되는지 확인한다."}},{"text":{"en":"Refactor runbooks so they are clear and, where appropriate, idempotent for a stressed engineer in the early morning","ko":"새벽에 긴장한 엔지니어가 읽어도 맥락과 단계가 분명하고, 필요하면 여러 번 실행해도 결과가 같도록 런북을 고쳐 쓴다."}},{"text":{"en":"Reconsider how much configuration is templated across regions, weighing configuration drift against automated global rollout","ko":"이 설정을 리전마다 템플릿으로 찍어 낼 필요가 있었는지 다시 따지고, 리전마다 설정이 어긋날 위험과 자동화로 변경이 여러 리전에 한꺼번에 퍼질 위험 사이에서 균형을 찾는다."}}],"contributing":["review-missed","no-staged-rollout","no-config-tests","backup-unverified","automation-amplified","blast-radius-too-wide"],"recurrence_of":null,"symptoms_text":{"en":"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.\n\nUnderneath, from 16:00 GMT, Argo CD, the deployment tool that keeps each Kubernetes cluster in line with the configuration in Git, was deleting workloads. The configuration it had just received contained no valid namespaces, so it began deleting all 478 services in all namespaces, across every availability zone and every region. Skyscanner's cells architecture is designed to keep serving with one cluster failed and another drained for maintenance, and to shift traffic between availability zones and regions on failure, but the same deletion ran in every cluster.\n\nThe change behind it had been submitted about half an hour earlier, at around 15:30 GMT, then peer reviewed, merged and rolled out automatically. It was an edit to a root-level file of the cells templating configuration, meant as a no-op in preparation for a later change. The edit left out the {{ }} template delimiters, so the templating no longer applied and every namespace built from that file, which was all of them, was reapplied in a corrupted form. The file was rarely changed, but because it rolls out regional configuration, the system pushed it to every region immediately.","ko":"2021년 8월 25일 Skyscanner 는 네 시간 반 동안 전 세계에서 완전히 멈췄다. skyscanner.net 웹사이트에 접속할 수 없었고 모바일 앱도 동작하지 않았다. 여행자와 비즈니스 파트너 모두 Skyscanner 를 쓸 수 없었다.\n\nGMT 16:00 에 배포 시스템 ArgoCD 가 클러스터를 설정에 맞추는 동기화를 시도했다. 새 설정에는 유효한 네임스페이스가 하나도 없었고, ArgoCD 는 전 세계 모든 리전과 가용 영역의 모든 네임스페이스에서 서비스 478개를 지우기 시작했다.\n\n백업은 준비돼 있었지만, 그 전에 바뀐 IAM 정책 때문에 정작 필요한 순간에 백업을 꺼내기가 어려웠다."},"updated_at":"2026-11-10T00:00:31.704646Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0010","org_slug":"skyscanner"}