{"id":"IL-0437","org":"Gunosy","date":"2023-06-20","docs":["https://github.com/mocyuto/helm-clear"],"title":{"en":"Old pods from an unfinished Argo Rollouts canary could not start with a Helm-updated ConfigMap and died in a cascade","ko":"카나리 배포가 끝나지 않은 상태에서 구 버전 파드가 새 ConfigMap 으로는 시작하지 못해 연쇄적으로 죽었다"},"domain":["kubernetes"],"impact":{"scope":"Pods of the service failed to start and died in a cascade during a traffic surge from a breaking news alert","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"Gunosy holds that a review that only resolves to be careful next time would soon be followed by the same failure, because human attention cannot be relied on, so each incident gets a permanent fix built into the system. Keeping past ConfigMap versions also made it possible to roll back quickly without going through CI/CD, which a ConfigMap change had previously prevented.","ko":"옛 DB 를 없애는 일은 드무니 다음에 조심하자는 회고로는 장애가 곧 다시 난다. 사람의 주의력은 믿을 수 없으므로, 재발을 막으려면 사람의 주의에 기대지 않는 장치를 만들어야 한다. Argo Rollouts 도입 초기에는 사람의 손을 거치지 않고 자동으로 롤아웃되는 것을 걱정했다. 그러나 몇 년 운영해 보니 오히려 롤아웃을 잊는 일이 더 많았고, 큰 릴리스는 어차피 Datadog 같은 감시 화면을 지켜보므로 거의 잊지 않았다. 지난 ConfigMap 을 남기자 ConfigMap 이 바뀐 릴리스도 CI/CD 를 거치지 않고 빠르게 롤백할 수 있게 되었다."},"related":[],"sources":[{"url":"https://tech.gunosy.io/entry/configmap_system_trouble","kind":"blog","archived":"https://web.archive.org/web/20250227144910/https://tech.gunosy.io/entry/configmap_system_trouble"}],"summary":{"en":"The service runs on Kubernetes, keeps its settings in a ConfigMap, manages its YAML with Helm and releases through Argo Rollouts canaries: one pod is released first, and if it is fine all pods are rolled out. Earlier on the day of the incident, before the failure began, a release removed the settings of an old database, which was being retired, from both the ConfigMap and the code. The rollout after the first canary pod was forgotten, so only one pod ran the new version. With a Helm release the old and new pod versions both exist, but by default only the latest ConfigMap is kept. This normally causes no trouble because the server reads the ConfigMap only at startup.\n\nWhen a breaking news alert raised traffic, pods scaled out automatically, and because the rollout had not happened, the scaled pods were the old version reading the new ConfigMap. The old code needed the old database's settings, which no longer existed, so the new pods could not start. The existing pods were overloaded and restarted, reread the ConfigMap on restart, could not start either, and the pods died one after another.\n\nGunosy names two root causes: forgetting the manual rollout, and startup failures because only the latest ConfigMap was kept. Automatic rollout had not been configured when Argo Rollouts was introduced, out of concern that releases would go out without a person holding the lever, but over several years forgotten rollouts had become the more common problem.","ko":"Gunosy 의 이 서비스는 쿠버네티스 위에서 돌았다. 설정은 ConfigMap 으로, YAML 은 Helm 으로 관리했고, Argo Rollouts 로 파드 하나에 먼저 내보낸 뒤 문제가 없으면 전체로 롤아웃하는 카나리 배포를 했다. 장애 당일 그보다 앞서 옛 DB 를 폐기하려고 ConfigMap 과 코드에서 그 설정을 지우는 릴리스를 했지만, 파드 하나만 나간 상태에서 롤아웃 작업을 잊었다. Helm 으로 릴리스하면 파드는 새 버전과 구 버전이 함께 있어도 ConfigMap 같은 리소스는 기본으로 최신 것만 남는다. 서버는 시작할 때 ConfigMap 을 읽으므로 평소에는 문제가 드러나지 않았다.\n\n뉴스 속보로 트래픽이 늘자 파드가 자동으로 늘어났는데, 롤아웃이 끝나지 않았으므로 늘어난 것은 구 버전 파드였다. 구 버전 파드는 옛 DB 의 설정이 필요했지만 새 ConfigMap 만 있어 시작하지 못했다. 파드가 늘지 못해 기존 파드에 부하가 몰려 재시작이 일어났고, 재시작한 파드도 ConfigMap 을 다시 읽다가 시작하지 못해 파드가 연쇄적으로 죽었다.\n\nGunosy 는 근본 원인을 두 가지로 보았다. 하나는 손으로 하는 롤아웃을 잊은 것이고, 다른 하나는 ConfigMap 이 최신 것만 남아 파드가 시작하지 못한 것이다. Argo Rollouts 를 자동 롤아웃으로 바꾸고, Helm 의 \"helm.sh/resource-policy\": keep 주석으로 지난 버전의 ConfigMap 을 남기며, 남긴 버전을 정리하는 Helm 플러그인을 만들어 넣었다."},"trigger":{"en":"A breaking news alert increased traffic and pods were scaled out automatically while a release that removed an old database's settings from the ConfigMap had been rolled out to only one canary pod.","ko":"옛 DB 를 폐기하려고 ConfigMap 과 코드에서 그 설정을 지운 릴리스가 Argo Rollouts 카나리로 파드 하나에만 나갔고, 전체 롤아웃을 잊은 상태였다. 그때 뉴스 속보로 트래픽이 늘어 구 버전 파드가 늘어났다."},"severity":"unknown","symptoms":["crash-loop"],"timeline":{"detected_after":null,"resolved_after":null},"date_kind":"published","detection":null,"components":["configmap","helm","progressive-delivery"],"root_cause":"deploy-rollout","remediation":[],"action_items":[{"text":{"en":"Configure Argo Rollouts to roll out automatically, with setWeight 1, a one-hour pause and then setWeight 100","ko":"Argo Rollouts 의 canary 단계를 setWeight: 1 뒤 pause duration: 1h 를 거쳐 setWeight: 100 으로 자동 롤아웃하도록 설정을 바꿨다."}},{"text":{"en":"Add the \"helm.sh/resource-policy\": keep annotation so Helm keeps past versions of the ConfigMap","ko":"Helm 리소스에 \"helm.sh/resource-policy\": keep 주석을 달아 지난 버전의 ConfigMap 을 남기는 설정을 도입한다."}},{"text":{"en":"Build and use a Helm plugin, helm-clear, that keeps only the last few ConfigMap versions by the revision number in their names, set to keep 5 in CD","ko":"ConfigMap 이름에 넣은 리비전 번호로 최신부터 순서를 확인해 지난 버전을 정리하는 Helm 플러그인 helm-clear 를 만들었다. CD 에서 helm clear configmap 에 --history 5 를 주어 지난 다섯 버전만 남기게 했다."}}],"contributing":["partial-rollout","automation-amplified"],"recurrence_of":null,"symptoms_text":{"en":"During a traffic surge from a breaking news alert, pods of a Gunosy service on Kubernetes could not start because the containers could not read their settings from the ConfigMap. The pods that kept running took the extra load and were restarted, failed to start again, and pod after pod died.\n\nThe pods added by the automatic scaling were the old version of the application, still running because an earlier canary release had not been rolled out. The old code read an old database and needed the old settings, but only the new ConfigMap existed, so every new or restarted old pod failed at startup.","ko":"뉴스 속보로 트래픽이 늘어 파드가 자동으로 늘어나던 중, 새로 뜨는 파드가 설정을 읽지 못해 시작하지 못했다. 컨테이너가 재시작을 거듭하며 파드가 차례로 죽어 장애가 났다.\n\n새로 늘어난 파드는 구 버전이었다. 구 버전 코드는 폐기한 옛 DB 의 설정을 읽어야 했지만, ConfigMap 에는 그 설정을 지운 새 버전만 남아 있었다.\n\n파드가 늘지 못하자 기존 파드에 부하가 몰려 재시작이 일어났다. 재시작한 파드도 ConfigMap 을 다시 읽으면서 시작하지 못했고, 파드가 줄줄이 죽어 갔다."},"updated_at":"2026-11-14T12:34:08.677212Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0437","org_slug":"gunosy"}