{"id":"IL-0109","org":"DFDS","date":"2023-02-14","docs":[],"title":{"en":"A 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 nodes","ko":"로그 수집을 고치려던 EKS 노드 롤오버가 꼬이면서 Auto Scaling 그룹이 정상 워커 노드를 모두 종료해 클러스터에 노드가 하나도 남지 않았다."},"domain":["kubernetes","aws"],"impact":{"scope":"The EKS cluster had no worker nodes, so all workloads on it were down","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"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.\n\nThe 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.","ko":"상황이 심각해져도 침착해야 한다. 서둘러 고치다 피해를 키우기보다 알려진 정상 설정으로 롤백하는 편이 낫다. 새 워커 노드를 띄우는 일은 cloudinit 스크립트의 어느 단계도 실패하지 않는다는 전제에 크게 기대고 있다."},"related":[],"sources":[{"url":"https://github.com/dfds/postmortems/blob/master/PM2023-001%20-%20Total%20node%20failure.md","kind":"github","license":"unknown","archived":null}],"summary":{"en":"A scheduled node rollover on 13 February 2023 set containerd as the default container runtime by mistake, and as a result Kubernetes logs stopped being shipped to CloudWatch. To fix the logs, the team started an unscheduled node rollover the next morning that swapped the runtime back. The value used in the eks-bootstrap script was believed to be docker-shim but needed to be dockerd, so the new nodes never joined the cluster and the rollover timed out with them still in the Auto Scaling group.\n\nThe team then ran the EKS pipeline without a rollover to apply a launch template with dockerd. Terraform saw the desired size of the Auto Scaling group still at the rollover value of 30 and set it back to 15. The group's default termination policy removes the instances that use the oldest launch template first, and the oldest ones were the healthy nodes, not the faulty new ones that had not been removed yet. All healthy worker nodes were terminated and the cluster was left with none.\n\nA first run of the node rollover script at 10:49 failed on a timeout from Docker Hub; a second run at 10:52 added new nodes from 10:57, and at 11:01 the load balancer marked them healthy and traffic flowed again. Recovery took 13 minutes. A Sev1 ticket was raised at 11:07 and closed at 11:59.","ko":"DFDS 의 EKS 클러스터는 2023-02-13 07:30 UTC 정기 노드 롤오버 때 실수로 containerd 를 기본 컨테이너 런타임으로 쓰게 됐다. 다음 날 09:33 UTC, 최종 사용자들이 CloudWatch 로그가 이상하다고 알려 왔고, 팀은 fluentd 를 따라가다 런타임이 docker-shim 이 아니라 containerd 라는 것을 찾았다.\n\n팀은 eks-bootstrap 스크립트의 런타임을 당시 기본값이라고 생각한 docker-shim 으로 되돌리고, 10:29 UTC 에 예정에 없던 노드 롤오버를 시작했다. 런타임 설정이 잘못돼 새 노드는 클러스터에 합류하지 못했다. 10:39 UTC 에 롤오버가 타임아웃으로 실패하면서 새 노드는 좀비로 남았고, ASG 의 desired capacity 도 원래대로 돌아가지 않았다.\n\n10:45 UTC 에 롤오버 없이 EKS 파이프라인을 돌려 dockerd 를 런타임으로 쓰는 새 시작 템플릿을 적용했다. Terraform 은 ASG 의 desired capacity 가 30인 것을 보고 15로 되돌렸다. 고장 난 좀비 노드는 아직 지워지지 않은 상태였고, ASG 의 기본 종료 정책은 가장 오래된 시작 구성이나 시작 템플릿을 쓰는 인스턴스부터 없앤다. 그래서 10:46 UTC 에 정상 노드가 전부 종료됐고, 10:48 UTC 에는 클러스터에 노드가 하나도 없었다.\n\n10:49 UTC 에 노드 롤오버 스크립트로 새 노드를 추가하려 했지만 Docker Hub 타임아웃으로 실패했다. 10:52 UTC 에 다시 시도하자 10:57 UTC 부터 새 노드가 클러스터에 합류하기 시작했고, 11:01 UTC 에 로드밸런서가 새 노드를 정상으로 보고 트래픽을 보냈다. 11:07 UTC 에 Sev 1 티켓이 열렸고 11:59 UTC 에 해결로 닫혔다. 사후 분석은 QA 설정이 운영과 다르고 스테이징 환경이 없었다는 점, QA 시험이 fluentd 로그 수집을 다루지 않았다는 점, 롤오버가 잘못됐을 때 할 일을 적은 문서가 없었다는 점을 기여 요인으로 꼽았다."},"trigger":{"en":"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.","ko":"쿠버네티스 로그가 CloudWatch 로 가지 않는 문제를 고치려고 예정에 없던 노드 롤오버를 시작했다."},"severity":"sev1","symptoms":["service-unavailable","resources-deleted","monitoring-down"],"timeline":{"detected_after":"2m","resolved_after":"13m"},"date_kind":"incident","detection":{"en":"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.","ko":"로그 문제는 최종 사용자들이 CloudWatch 로그가 이상하다고 알려 오면서 드러났다. 노드가 사라진 장애는 사후 분석 기준으로 2분 만에 감지됐다."},"components":["container-runtime","launch-template","node-pool","terraform","telemetry-agent"],"root_cause":"config-change","remediation":[{"text":{"en":"ran the node rollover script to add new nodes, which failed on a timeout from Docker Hub","ko":"10:49 UTC 에 노드 롤오버 스크립트로 새 노드를 추가하려 했지만 Docker Hub 타임아웃으로 실패했다."}},{"text":{"en":"ran the node rollover script a second time, which added new nodes that the load balancer marked healthy at 11:01 UTC","ko":"10:52 UTC 에 노드 롤오버 스크립트를 다시 돌려 새 노드를 추가했고, 11:01 UTC 에 로드밸런서가 새 노드를 정상으로 판단해 트래픽을 다시 보냈다."}}],"action_items":[{"text":{"en":"Document the rollover process, especially what can be done when it goes wrong","ko":"롤오버 절차를 문서로 남기고, 특히 롤오버가 잘못됐을 때 할 수 있는 일을 적는다."}},{"text":{"en":"Investigate options for improving the rollover process","ko":"롤오버 절차를 개선할 방법을 찾는다."}},{"text":{"en":"Add fluentd log collection to the QA test suite so logs are covered end to end","ko":"QA 시험에 fluentd 로그 수집을 넣어 로그가 처음부터 끝까지 전달되는지 확인한다."}},{"text":{"en":"Add alarms for fluentd when too little or no log data is sent","ko":"fluentd 가 보내는 로그 데이터가 부족하거나 없을 때 울리는 경보를 추가한다."}},{"text":{"en":"Implement a staging environment","ko":"스테이징 환경을 만든다."}},{"text":{"en":"Implement guards against selecting an invalid container runtime","ko":"잘못된 컨테이너 런타임을 고르지 못하게 막는 장치를 넣었다."}}],"contributing":["automation-amplified","default-config-unchanged","staging-not-representative","no-config-tests","no-runbook","manual-action-worsened"],"recurrence_of":null,"symptoms_text":{"en":"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.\n\nAn unscheduled node rollover to switch the runtime back started at 10:29 and failed on a timeout at 10:39. The runtime value used was wrong, so the new nodes never joined the cluster and were left as \"zombies\".\n\nAt 10:45 the EKS pipeline was run again without a node rollover, to apply the new launch template with dockerd as the runtime. Because the failed rollover had never set the Auto Scaling group's desired size back, Terraform changed it from 30 to 15. At 10:46 all the healthy nodes were terminated, since the group's default termination policy removes the instances with the oldest launch configuration or template first. By 10:48 the cluster had no worker nodes.","ko":"2023-02-14 09:33 UTC, 최종 사용자들이 CloudWatch 로그가 제대로 들어오지 않는다고 알려 왔다. 팀은 fluentd 를 조사하다가 컨테이너 런타임이 docker-shim 이 아니라 containerd 로 바뀌어 있다는 것을 찾았다. 전날 07:30 UTC 의 정기 노드 롤오버 때 containerd 가 실수로 기본 런타임으로 설정돼 있었다.\n\n10:29 UTC 에 런타임을 되돌리는 노드 롤오버를 시작했지만 10:39 UTC 에 타임아웃으로 실패했다. 런타임 설정이 잘못돼 새 노드가 클러스터에 합류하지 못했고 좀비 노드로 남았다. 팀은 되돌릴 값을 dockershim 으로 알았지만 실제 값은 dockerd 였다.\n\n10:45 UTC 에 노드 롤오버 없이 EKS 파이프라인을 돌리자 Terraform 이 ASG 의 desired capacity 를 30에서 15로 되돌렸다. 10:46 UTC 에 정상 노드가 모두 종료됐고, 10:48 UTC 에는 클러스터에 노드가 하나도 없었다. 10:49 UTC 에 다시 돌린 노드 롤오버 스크립트는 Docker Hub 타임아웃으로 실패했다."},"updated_at":"2026-11-10T00:00:33.655667Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0109","org_slug":"dfds"}