IL-0232 Wikimedia Foundation · 2024-10-09kubernetesnetworking
codfw WikiKube 클러스터에서 Calico 구성 요소가 자원 한도에 걸려 calico-node 파드가 하나씩 죽고 노드가 차례로 빠지면서 MediaWiki 지연과 오류가 났다
한 운영자가 새 mwscript-k8s 도구로 TimedMediaHandler 의 requeueTranscodes.php 를 돌려 동영상 트랜스코딩을 일괄 정비했다. 작업은 몇 시간 동안 문제없이 돌았지만, mwscript-k8s 는 설계상 스크립트를 실행할 때마다 helm 릴리스 하나를 통째로 배포했다. 그 결과 Calico NetworkPolicy 가 2천 개 가까이 생겼고 그 밖의 리소스도 많이 생겼다. WikiKube 의 모든 Calico 구성 요소가 늘어나는 정책에 맞춰 일을 더 해야 했고, 그중 일부가 자원 한도에 닿아 스로틀링되다가 실패했다. 그러자 하드웨어 노드가 하나씩 서비스에서 빠지는 장애가 천천히 번졌다.
2024-10-09 05:01:36 UTC 부터 주 데이터센터 codfw 의 MediaWiki 노드가 과부하에 걸려, 로그인 사용자의 요청, 편집, API 호출처럼 캐시되지 않은 요청이 약 한 시간 동안 높은 지연이나 오류를 겪었다. 자동 모니터링의 알림을 받은 당직 SRE 가 대응했고, calico-kube-controllers 의 크래시 루프와 쿠버네티스 API 타임아웃, 줄어드는 calico-node 파드를 확인했다. 05:50 UTC 에 장애를 선언했다. 대응자들은 calico 와 typha 파드가 자원 한도에 닿은 것을 보고 한도를 올리는 변경을 CI 를 기다리지 않고 바로 반영해 06:05 UTC 에 helmfile 로 적용했다. 06:07 UTC 에 ready 인 calico-node 가 212개로 돌아왔고, 06:10 UTC 에 Calico 가 회복되어 사용자 영향이 끝났다. 대응자 중 한 사람은 한도를 올린 것보다 모든 calico 파드를 한꺼번에 다시 배포한 것이 회복에 더 도움이 되었을 수 있다고 보았다.
회복 뒤 원인을 찾았다. etcd 의 configmap 객체가 몇 시간 사이에 두 배로 늘었고, 이는 jobs.batch 객체와 그 NetworkPolicy 의 증가와 정확히 맞았다. mw-script 네임스페이스의 job 은 1791개였다. 대응자 한 사람은 calico 가 내려가면 파드가 다시 배치되고, 다시 배치된 파드가 calico 에 부담을 더 주는 되먹임이 생겼다고 추정했다. 이 장애는 2024-04-03 calico/typha 장애와 비슷하다고 기록되었다.
- 심각도
- –
- 영향 범위
- For about one hour after 05:00 UTC some uncached MediaWiki requests, such as those from logged-in users, edits and API calls, saw high latency or errors from overloaded MediaWiki nodes in the primary datacenter
- 영향 사용자
- Logged-in users, editors and API clients making uncached requests
- 지역
- codfw
- 감지까지
- –
- 복구까지
- 1h 8m
증상
2024-10-09 05:01:36 UTC 에 codfw 의 rest-gateway 에서 page-analytics_cluster 의 5xx 오류가 늘었다는 GatewayBackendErrorsHigh 알림이 울렸다. 05:03:32 UTC 에는 KubernetesCalicoDown 알림이 16건 묶여 울렸고, 알림 문구는 kubernetes2037.codfw.wmnet is not running calico-node Pod 였다. 05:04:15 UTC 에는 MediaWiki memcached 오류율이 전 세계에서 올랐다는 MediaWikiMemcachedHighErrorRate 알림이 울렸다.
KubernetesCalicoDown 알림 수가 꾸준히 늘었다. kubectl -n kube-system get po -l k8s-app=calico-kube-controllers 로 보니 calico-kube-controllers-57c75d4867-cgzpc 가 0/1 CrashLoopBackOff 였고 21번 재시작한 상태였다. calico-node 파드도 많은 수가 calico-node-s89nl 0/1 CrashLoopBackOff 처럼 크래시 루프에 빠지거나, Running 이지만 ready 가 아니었다. calico-node 파드의 liveness probe 도 실패했다. 06:04 UTC 에는 calico-node 파드가 온전히 동작하는 노드가 25대뿐이었다.
calico-kube-controllers 로그에는 쿠버네티스 API 호출이 타임아웃되는 줄이 찍혔다. 그 줄은 [ERROR][1] client.go 272: Error getting cluster information config ClusterInformation="default" error=Get "https://10.192.72.1:443/apis/crd.projectcalico.org /v1/clusterinformations/default": context deadline exceeded 과 [FATAL][1] main.go 124: Failed to initialize Calico datastore error=Get "https://10.192.72.1:443/apis/crd.projectcalico.org/v1/clusterinformations/default": context deadline exceeded 였다. typha 는 사용할 수 있는 상태로 보였다. calico-node 로그에는 눈에 띄는 것이 거의 없었고, 가장 이상한 줄은 bird: I/O loop cycle took 7808 ms for 6 events 였다. 나중에는 felix/health.go 211: Reporter is not ready. name="int_dataplane" 경고도 나왔다.
지표에서는 calico 와 typha 파드가 자원 한도에 닿아 있었다. 쿠버네티스 API 의 get 과 list 호출은 03:00 과 04:00 UTC 사이부터 크게 늘어 있었다. calico typha 가 도는 노드의 수신 트래픽도 04:00 쯤부터 급격히 늘었고, 그 크기는 초당 약 7MB 였다. etcd 의 configmap 객체는 02:00 과 06:00 사이에 6천 개에서 1만 2천 개로 두 배가 되었고, jobs.batch 객체와 그에 딸린 NetworkPolicy 도 같이 늘었다. kubectl -n mw-script get jobs |wc -l 의 결과는 1791 이었다.
MediaWiki 쪽 영향은 application-servers-red-k8s 대시보드에서 잘 드러나지 않았다. 가장 뚜렷한 신호는 200 응답이 약 5분 동안 4천에서 3천으로 25% 줄어든 것이었고, 지연도 잠깐 늘었다.
대응자들은 처음에 etcd 문제를 의심했다. 호스트별 CPU 사용량은 조금 늘었지만 CPU 가 꽉 찬 서버는 없었다. 대응자들은 이 증가가 파드 재시작 때문이라고 보았다. 앞서 울린 KubernetesAPILatency 알림이 관련 있는지도 따져 보았다. 자원 한도를 올리는 수정이 듣지 않으면 트래픽을 eqiad 로 되돌리자는 의견이 나왔다. 하지만 데이터베이스 팀이 먼저 할 일이 있는지 몰라 대응자들은 바로 전환할 수 있을지 확신하지 못했다.
원인
- 촉발
- 한 운영자가 새 mwscript-k8s 도구로 TimedMediaHandler 의 requeueTranscodes.php 를 돌려 동영상 트랜스코딩을 일괄 정비했다. mwscript-k8s 는 스크립트를 실행할 때마다 helm 릴리스를 통째로 배포하므로, 이 작업이 몇 시간 동안 리소스를 계속 만들었다.
감지
자동 모니터링이 알아채고 당직 SRE 가 대응했다. 05:01:36 UTC 에 GatewayBackendErrorsHigh, 05:03:32 UTC 에 KubernetesCalicoDown 16건, 05:04:15 UTC 에 MediaWikiMemcachedHighErrorRate 알림이 울렸다.
조치
- calico 와 typha 의 자원 한도를 올리는 변경을 CI 를 기다리지 않고 반영하고, helmfile -e codfw --selector name=calico apply -i --context 5 로 적용했다. 적용 중 새 calico 파드가 정상으로 떴고, 06:10 UTC 에 Calico 가 회복되었다.
후속 조치
- mwscript-k8s 가 리소스를 너무 많이 만드는 문제를 해결한다.
교훈
완전한 장애 직전까지 갔다. 자동 모니터링이 장애를 잡았다. 새로 들어온 여러 사람이 함께 본 덕에 근본 원인을 찾았다. 미주 SRE 에서 EMEA SRE 로 장애 대응을 문제없이 넘겼다. 반면 최종 사용자에게 영향이 갔고, 비상시에 eqiad 로 전환할 수 있는지 확신하지 못했다.
운도 따랐다. 장애는 미주 SRE 근무가 끝나고 EMEA SRE 근무가 시작되기 바로 전에 발견되었다. 이 시간대는 오래전부터 대응 인력이 비는 때로 알려져 있었다. 트랜스코딩 작업을 미국의 금요일 저녁에 넣지 않은 것도 다행이었다.
출처
참고 문서
관련 사례
같은 원인 · 공통 잡과 크론잡
IL-0518GKE 위 gitlab.freedesktop.org 의 디스크가 모자라 저장소를 늘리려던 30분 작업이 GitLab 전체의 4시간 장애가 됐다freedesktop.org · 2018같은 원인 · 공통 Helm
같은 원인 · 공통 잡과 크론잡
IL-0040비운영 쿠버네티스 클러스터에 Helm 차트를 한꺼번에 설치하자 작은 gp2 루트 볼륨의 IOPS 가 바닥나, 워커 노드 세 대에서 kubelet 이나 Docker 가 내려가 세 대 모두 NotReady 가 됐다Saltside · 2017같은 원인 · 공통 Helm
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0232
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0232/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.