IL-0230 CircleCI · 2023-03-14kubernetesnetworking
쿠버네티스 업그레이드 도중 메인 운영 클러스터의 서비스 간 통신이 끊겨 모든 고객의 작업이 시작되지 않았다
CircleCI 인프라 팀은 사고 전 일주일 동안 메인 운영 쿠버네티스 클러스터를 조금씩 업그레이드하고 있었다. 3월 13일 몇몇 구성 요소를 올린 뒤 일부 서비스의 지표가 빠져 변경을 되돌렸고 지표는 돌아왔다. 팀은 영향 범위를 줄이도록 계획을 고친 뒤 3월 14일 17:40 UTC 쯤 다른 방식으로 업그레이드를 다시 했다. 18:00 UTC 부터 서비스 간 통신이 실패해 모든 고객의 파이프라인이 늦어지다가 작업이 돌지 않았고, 장애는 3월 15일 01:27 UTC 쯤까지 이어졌다. 보고서는 진행 중이던 업그레이드가 kubelet 과 kube-proxy 의 버전을 어긋나게 만들어 넓은 네트워크 장애가 났다고 요약했다.
kube-proxy 는 노드마다 돌면서 Service 와 Endpoints 객체를 지켜보고, 바뀐 내용을 노드의 iptables 규칙에 반영한다. 이 일은 Proxier.syncProxyRules() 가 맡는다. 이 함수는 iptables-save 로 상태를 읽고 새 규칙을 만든 뒤 iptables-restore 로 다시 쓴다. 팀이 다루던 두 쿠버네티스 버전 사이에 kube-proxy 규칙 집합의 처리 방식과 형식이 바뀌어 있었다. 3월 13일 kube-proxy 버전을 되돌린 뒤로 동기화 실패가 조금씩 나왔고, 업그레이드로 파드가 늘고 Endpoints 가 바뀔 때마다 실패가 늘었다. 3월 14일 업그레이드를 이어 가자 동기화 오류가 치솟아 여러 노드의 iptables 가 크게 망가졌다.
팀은 node-local-dns-cache 와 core-dns 를 재시작했고, 그러자 DNS 조회가 완전히 실패했다. 노드 하나를 재시작하자 그 노드의 요청이 통과해, 모든 노드를 재시작하기로 했다. 노드를 재시작하면 iptables 규칙 집합이 새로 만들어졌다. 23:00 까지 모든 노드를 교체하자 contexts 나 machine executor 를 쓰는 작업을 빼고 모두 회복되었다. 팀은 별도의 의존성 풀을 재시작했고, 3월 15일 01:15 UTC 에 모든 작업이 정상으로 돌았다. 클러스터 전체를 재시작하자 동기화 오류가 사라졌다.
복구 과정에서 장애 두 건이 더 났다. 팀은 RabbitMQ 로그가 빠져 있는 것을 알고 나머지 인프라를 모두 다시 띄웠다. 그 뒤 02:50 UTC 쯤 RabbitMQ 연결 오류로 모든 파이프라인이 다시 늦어졌다. 03:35 UTC 에 완화했고 05:14 UTC 에 해결했다. 이어서 팀은 망가진 큐 몇 개를 고치려고 RabbitMQ 노드를 재시작했다. 보고서는 09:50 UTC 부터 GitHub checks 가 최대 30분 늦어진 두 번째 성능 저하도 함께 적었다. 11:08 UTC 에 완화했고 지켜본 끝에 13:15 UTC 에 해결했다.
- 심각도
- –
- 영향 범위
- Pipelines of all customers started late and then jobs did not run; Docker, Machine, macOS and Windows jobs, the CircleCI UI and Runner were affected. Two follow-on RabbitMQ incidents delayed all pipelines from 02:50 to 05:14 UTC and GitHub checks by up to 30 minutes from 09:50 to 13:15 UTC on 15 March.
- 영향 사용자
- all customers
- 지역
- –
- 감지까지
- –
- 복구까지
- 7h 27m
증상
2023-03-14 18:00 UTC 쯤 한 서비스에서 통신 오류가 늘기 시작했다. 곧 모든 고객의 파이프라인이 늦게 시작하다가 끝내 작업이 돌지 않았고, 18:19 UTC 에 상태 페이지에 작업 시작 지연이 올라왔다.
장애 통화에 엔지니어와 팀이 더 들어오면서 영향이 여러 서비스와 애플리케이션의 모든 기능에 퍼져 있다는 것이 드러났다. 작업 처리 지연이 계속 늘었고 여러 서비스의 작업 대기열이 쌓였다. 한 시간이 안 되어 처음의 성능 저하가 큰 장애가 되었다. 영향을 받은 것은 Docker, Machine, macOS, Windows 작업과 CircleCI UI, Runner 였다.
사고 뒤 분석에서 보니, 장애가 시작될 때 모든 노드에서 도는 kube-proxy 의 로그에 "Sync failed" 오류가 치솟아 있었다. 로그 줄은 "Failed to execute iptables-restore" err="exit status 1 (iptables-restore: line 8022 failed\n)" 과 "Sync failed" retryingTime="30s" 였다.
전날인 3월 13일에도 조짐이 있었다. 몇몇 구성 요소를 올린 뒤 일부 서비스에서 지표가 빠졌다. 변경을 되돌리자 지표가 돌아와 회복된 것처럼 보였다. 하지만 이때 kube-proxy 를 되돌린 뒤부터 로그에 Sync 실패 오류가 아주 적게 나오기 시작했고, 팀은 이를 알아채지 못했다.
팀은 먼저 증상을 줄이려고 서비스 몇 개를 재시작했다. 로그와 지표를 뒤지고 파드 안에서 내부 쿠버네티스 도메인 이름으로 서비스에 직접 붙어 본 끝에 kube-proxy, core-dns, node-local-dns-cache 중 하나를 의심했다. 하지만 세 워크로드 모두 정상으로 보여 확인하기 어려웠다. 20:00 에서 21:00 UTC 사이에 node-local-dns-cache 와 core-dns 를 재시작하자 DNS 조회가 완전히 실패했다.
노드 하나를 재시작하자 그 노드와 관련된 요청은 통과하기 시작했다. 팀은 이것을 보고 kube-proxy 를 주된 원인으로 좁혔다.
원인
- 촉발
- 3월 14일 17:40 UTC 쯤 인프라 팀이 전날 되돌렸던 구성 요소들을 다른 방식으로 다시 업그레이드했다. 전날 kube-proxy 를 되돌린 뒤로 iptables 동기화가 조금씩 실패하던 상태에서 업그레이드를 이어 가자 동기화 오류가 한꺼번에 치솟았다.
감지
팀은 3월 14일 18:00 UTC 에 한 서비스의 통신 오류가 늘어나는 것을 보고 장애를 알아챘다. 장애 통화에 사람이 더 들어오면서 영향이 여러 서비스로 퍼진 것을 확인했다. 3월 13일 롤백 뒤에 로그에 나온 소수의 Sync 실패 오류는 그때 알아채지 못했다.
조치
- 모든 노드를 차례로 재시작해 노드마다 iptables 규칙 집합을 새로 만들었고, 23:00 까지 모든 노드 교체를 마쳤다.
- contexts 나 machine executor 를 쓰는 작업이 회복되지 않아 별도의 의존성 풀을 재시작했고, 3월 15일 01:15 UTC 에 모든 작업이 정상으로 돌았다.
- 작업이 다시 돌기 시작하자 쌓인 작업을 처리하려고 용량을 늘렸다.
- 망가진 큐 몇 개를 고치려고 RabbitMQ 노드를 재시작했다.
후속 조치
- 앞으로의 업그레이드에서 이런 위험을 크게 줄이도록 쿠버네티스 업그레이드 절차를 고친다.
- 이번 장애 때 kube-proxy 가 낸 동기화 오류를 잡는 지표와 알림을 더했다.
- RabbitMQ 인프라의 복원력을 높일 방법을 검토한다.
교훈
이번 장애를 촉발한 원인은 하나가 아니었다. 네트워크는 모든 것의 바탕이어서 쿠버네티스 업그레이드는 본래 위험하다. 여러 사건이 맞물려 터진 이번 경우에는 팀이 세워 둔 위험 완화 방법이 듣지 않았다.
출처
- https://status.circleci.com/incidents/dcqb3fykhgvg · official-status · 보관본
관련 사례
IL-0144Ubuntu 18.04 의 systemd 보안 업데이트가 DNS 설정을 날려 AKS 노드의 kubelet 이 레지스트리 이름을 해석하지 못하고 파드가 ImagePullBackoff 에 빠졌다.Microsoft Azure · 2022같은 원인 · 공통 kubelet, 클라이언트 쪽 DNS 리졸버와 캐시
IL-0101자동 업그레이드를 꺼 둔 GKE 클러스터의 컨트롤 플레인이 지원 종료 기한에 1.33.2 로 강제 업그레이드된 뒤 새 노드가 모두 초기화에 실패해, 오토스케일링과 스팟 노드 복구가 15시간 멈췄다.Wealthy · 2025 · sev1같은 원인 · 공통 클라이언트 쪽 DNS 리졸버와 캐시
IL-0079GKE 노드가 새 ubuntu_containerd 이미지로 자동 업그레이드된 뒤 커널에서 kube-proxy 가 쓰는 iptables 확장이 빠져, 여러 GKE 클러스터의 인그레스 트래픽이 완전히 끊겼다.Altinity · 2025같은 원인 · 공통 kube-proxy
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0230
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0230/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.