{"id":"IL-0101","org":"Wealthy","date":"2025-09-14","docs":[],"title":{"en":"After Google forced a GKE control plane upgrade to 1.33.2 at a deprecation deadline, no new node could initialise, so autoscaling and spot node replacement stopped for 15 hours","ko":"자동 업그레이드를 꺼 둔 GKE 클러스터의 컨트롤 플레인이 지원 종료 기한에 1.33.2 로 강제 업그레이드된 뒤 새 노드가 모두 초기화에 실패해, 오토스케일링과 스팟 노드 복구가 15시간 멈췄다."},"domain":["kubernetes","gcp"],"impact":{"scope":"Background workers, reporting services and order allocation completely down; APIs on existing nodes worked but could not scale; any workload needing a new node failed","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"GKE upgrades the control plane at a version's deprecation deadline even when auto-upgrade is disabled, so staying inside the supported version window is how to avoid a forced upgrade. A control plane upgrade can leave existing nodes healthy while every new node fails, and spot nodes that cannot rejoin after preemption turn this into cascading failures.\n\nRelying heavily on spot instances for critical workers turned a node join failure into a progressive outage. Kubernetes upgrades have to be planned together with dependent components such as Istio and cert-manager, and without a standby cluster on the same provider there was no immediate failover; the only recovery left was building a new cluster.","ko":"Google 은 자동 업그레이드를 꺼 두어도 버전 지원 종료 기한이 되면 컨트롤 플레인을 강제로 올린다. 강제 업그레이드를 피하려면 지원 버전 범위 안에 머물러야 한다. 기존 노드가 멀쩡해도 새 노드 초기화는 완전히 실패할 수 있다. 선점된 스팟 노드가 클러스터에 돌아오지 못하면 장애가 연쇄로 번진다. 컨트롤 플레인을 올린 뒤 노드 초기화가 되돌릴 수 없게 망가지면 클러스터를 통째로 다시 만들어야 할 수도 있다. 예측할 수 있고 검증된 릴리스 주기를 원하면 GKE stable 채널을 쓴다. 쿠버네티스를 올릴 때는 Istio, cert-manager 같은 의존 구성 요소를 함께 맞춰야 한다. 같은 클라우드에 대기 클러스터가 없으면 바로 넘어갈 곳이 없다. SRE 가 롤아웃을 단계적으로 관리하면 업그레이드 위험이 줄어든다."},"related":[],"sources":[{"url":"https://docs-6si.pages.dev/operations/rca/2025-09-14-gke-auto-upgrade-failure/","kind":"blog","license":"unknown","archived":null}],"summary":{"en":"The Wealthy production GKE cluster ran a Kubernetes version close to its deprecation deadline, with node pool auto-upgrade disabled. At the deadline Google upgraded the control plane from v1.32.x to v1.33.2 anyway. Existing nodes kept working, but from then on no new node could initialise properly: NodeLocalDNS crash-looped, the netd network plugin and the CSI driver did not start, and system ConfigMaps did not mount. Because critical background workers ran on spot instances that are preempted often, each preempted node was lost for good, and since no node could be added the cluster could not autoscale at all.\n\nRestarts, rolling back node versions, toggling the NodeLocalDNS addon and recreating the node pool all failed, and the team concluded the cluster could not be repaired. Bringing workloads up on a new cluster also needed component upgrades for Kubernetes 1.33: Istio had to move to 1.27.1 and the cert-manager configuration had to be updated. There was no standby cluster on GCP to fail over to; the dev cluster runs on another cloud provider. The incident lasted 15 hours and was rated Critical.","ko":"Wealthy 의 GKE 클러스터는 노드 풀 자동 업그레이드를 꺼 둔 상태였다. 그러나 쓰던 버전의 지원 종료 기한이 오자 Google 이 컨트롤 플레인을 v1.32.x 에서 v1.33.2 로 강제로 올렸다. 기존 노드는 계속 돌았지만, 그 뒤 새로 만든 노드는 v1.32 든 v1.33 이든 모두 제대로 초기화되지 않았다. 새 노드에서는 NodeLocalDNS 가 크래시 루프에 빠졌다. netd 가 초기화되지 않아 파드 네트워킹이 안 됐고, CSI 드라이버 문제로 영구 볼륨 마운트가 실패했으며, 시스템 ConfigMap 마운트도 실패했다.\n\n중요한 백그라운드 워커를 비용 때문에 스팟 인스턴스에 많이 올려 두어서 피해가 컸다. 스팟 노드가 선점되면 새 노드가 클러스터에 들어오지 못했고, 워커가 하나씩 사라지면서 서비스가 점점 나빠졌다. 일반 인스턴스도 같은 문제를 겪어 새 노드가 필요한 워크로드는 전부 멈췄다. 백그라운드 작업 처리, 리포트 생성, 주문 할당과 처리가 멈췄다. 클러스터는 GKE 지원 기한에 가까운 버전이었고, GCP 안에는 넘어갈 대기 클러스터가 없었다. 개발 클러스터는 다른 클라우드에 있었다.\n\n파드와 노드 재시작, 노드 버전 롤백, NodeLocalDNS 애드온 끄고 켜기, 노드 풀 재생성을 모두 해 봤지만 새 노드는 초기화되지 않았다. 팀은 강제 업그레이드와 같은 v1.33 으로 새 GKE 클러스터를 만들고 모든 운영 워크로드를 옮겼다. 이 과정에서 쿠버네티스 1.33 에 맞추려면 Istio 를 1.27.1 로 올리고 cert-manager 도 갱신해야 한다는 것을 알게 됐다. 장애는 모두 15시간 이어졌다."},"trigger":{"en":"Google upgraded the GKE control plane from v1.32.x to v1.33.2 at the version deprecation deadline, although auto-upgrade was disabled on the node pools.","ko":"노드 풀의 자동 업그레이드를 꺼 두었는데도 Google 이 버전 지원 종료 기한을 이유로 컨트롤 플레인을 v1.32.x 에서 v1.33.2 로 강제 업그레이드했다."},"severity":"sev1","symptoms":["autoscaler-scale-up-failed","crash-loop","service-unavailable","dns-resolution-failures"],"timeline":{"detected_after":null,"resolved_after":"15h"},"date_kind":"incident","detection":null,"components":["gke-control-plane","node-pool","dns-resolver","persistent-volume","configmap"],"root_cause":"upgrade-breaking-change","remediation":[{"text":{"en":"Created a new GKE cluster at v1.33, the version of the forced upgrade","ko":"강제 업그레이드와 같은 버전인 v1.33 으로 새 GKE 클러스터를 만들었다."}},{"text":{"en":"Upgraded Istio to 1.27.1 for Kubernetes 1.33 compatibility","ko":"쿠버네티스 1.33 과 호환되도록 Istio 를 1.27.1 로 올렸다."}},{"text":{"en":"Updated the cert-manager configuration for Kubernetes 1.33","ko":"쿠버네티스 1.33 에 맞게 cert-manager 설정을 갱신했다."}},{"text":{"en":"Migrated all production workloads to the new cluster and verified pod scheduling, DNS resolution, PVC mounting and external integrations","ko":"모든 운영 워크로드를 새 클러스터로 옮기고, 파드 스케줄링, DNS 조회, PVC 마운트, 외부 연동이 정상인지 확인했다."}},{"text":{"en":"Decommissioned the broken cluster","ko":"손상된 기존 클러스터를 폐기했다."}}],"action_items":[{"text":{"en":"Configure all clusters to use the GKE stable release channel","ko":"모든 클러스터를 GKE stable 릴리스 채널로 설정한다."}},{"text":{"en":"Implement a separate management cluster for Argo CD, monitoring and other control components (Q4 2025)","ko":"2025년 4분기까지 Argo CD 와 모니터링 같은 관리용 구성 요소를 따로 돌리는 관리 클러스터를 만든다."}},{"text":{"en":"Review spot instance usage for critical workloads and add on-demand fallback pools","ko":"중요한 워크로드의 스팟 인스턴스 사용을 다시 검토하고, 온디맨드 대체 노드 풀을 추가한다."}},{"text":{"en":"Document the SRE upgrade procedure: management cluster first, production after a monitoring period of several days","ko":"SRE 업그레이드 절차를 문서로 남긴다. 관리 클러스터를 먼저 올리고, 며칠 동안 지켜본 뒤 운영 클러스터를 올린다."}},{"text":{"en":"Document a Kubernetes, Istio and cert-manager compatibility matrix","ko":"쿠버네티스, Istio, cert-manager 사이의 호환 표를 문서로 남긴다."}},{"text":{"en":"Create an automated upgrade testing pipeline","ko":"업그레이드를 자동으로 시험하는 파이프라인을 만든다."}},{"text":{"en":"Reserve static IPs for quick migrations","ko":"빠르게 이전할 수 있도록 고정 IP 를 예약해 둔다."}},{"text":{"en":"Pin versions of Istio, cert-manager, CSI and DNS addons","ko":"Istio, cert-manager, CSI, DNS 애드온의 버전을 고정한다."}},{"text":{"en":"Stay current with stable releases and regularly check GKE alerts and announcements to avoid deprecation deadlines","ko":"지원 종료 기한에 몰리지 않도록 stable 릴리스를 따라 제때 올리고, GKE 알림과 공지를 정기적으로 확인한다."}}],"contributing":["skipped-upgrades","single-point-of-failure","revert-did-not-restore","no-spare-capacity"],"recurrence_of":null,"symptoms_text":{"en":"Nodes that already existed kept running, but every new node, spot or standard, on either v1.32 or v1.33, failed to initialise and could not join the cluster. Spot nodes that were preempted and recreated never came back, so services degraded progressively: background workers on spot instances, reporting services and order allocation stopped completely, and the APIs on existing nodes kept answering but could not scale for load spikes.\n\nOn the new nodes the system pods failed: NodeLocalDNS pods were stuck in crash loops, the netd network plugin could not initialise so pods had no networking, the CSI driver could not register so persistent volumes would not mount, and critical system ConfigMaps failed to mount. There were also API server connection errors. The CSI node-driver-registrar logged \"Still connecting to unix:///csi/csi.sock\" every 10 seconds and then \"error connecting to CSI driver: context deadline exceeded\".\n\nRestarting failed pods and nodes did nothing, and rolling node versions back still left new nodes unable to initialise. Disabling the NodeLocalDNS addon worked but slowed DNS resolution, and re-enabling it failed with \"INVALID_ARGUMENT: Node pool \\\"t2d-64gb-standard\\\" requires recreation\". Recreating the node pool failed with the same initialisation problems.","ko":"2025년 9월 14일, 이미 떠 있던 노드는 계속 돌았지만 새로 만들어지는 노드는 하나도 클러스터에 제대로 들어오지 못했다. 스팟 인스턴스에서 돌던 백그라운드 워커, 리포트 서비스, 주문 할당 시스템이 완전히 멈췄다. API 는 기존 노드에서 계속 응답했지만 부하가 늘어도 확장할 수 없었다.\n\n새 노드에서는 시스템 파드가 줄줄이 실패했다. NodeLocalDNS 파드는 크래시 루프에 빠졌고, 네트워크 플러그인 netd 는 초기화하지 못해 파드 네트워킹이 되지 않았다. CSI 드라이버가 초기화되지 않아 영구 볼륨이 마운트되지 않았고, 중요한 시스템 ConfigMap 도 마운트에 실패했다. API 서버 연결 오류도 보였다.\n\nCSI node-driver-registrar 는 07:11:29에 /csi/csi.sock 으로 gRPC 연결을 열려고 했다. 로그에는 그 뒤 10초마다 \"Still connecting to unix:///csi/csi.sock\" 이 이어졌고, 07:11:59에 \"error connecting to CSI driver: context deadline exceeded\" 로 끝났다.\n\n스팟 노드가 선점되어 다시 만들어질 때마다 클러스터에 돌아오지 못해 서비스가 점점 더 나빠졌다. 일반 인스턴스도 마찬가지여서 노드 오토스케일링이 모두 실패했다. 새 노드는 v1.32 로 만들어도 v1.33 으로 만들어도 똑같이 실패했다.\n\n처음에는 실패한 파드와 노드를 재시작해 봤지만 효과가 없었다. 노드 버전을 되돌려도 새 노드는 여전히 초기화되지 않았다. NodeLocalDNS 애드온을 껐다가 다시 켜 보려 했는데, 끄기는 됐지만 DNS 조회가 느려졌고 다시 켜기는 \"Error: INVALID_ARGUMENT: Node pool \"t2d-64gb-standard\" requires recreation\" 으로 실패했다. 노드 풀을 다시 만들어도 같은 초기화 문제로 실패했고, 팀은 클러스터 손상을 되돌릴 수 없다고 결론 내렸다."},"updated_at":"2026-11-10T00:00:33.173632Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0101","org_slug":"wealthy"}