Incident Library

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 를 주된 원인으로 좁혔다.

증상 서비스 중단간헐적 연결 실패DNS 조회 실패

원인

촉발
3월 14일 17:40 UTC 쯤 인프라 팀이 전날 되돌렸던 구성 요소들을 다른 방식으로 다시 업그레이드했다. 전날 kube-proxy 를 되돌린 뒤로 iptables 동기화가 조금씩 실패하던 상태에서 업그레이드를 이어 가자 동기화 오류가 한꺼번에 치솟았다.

감지

팀은 3월 14일 18:00 UTC 에 한 서비스의 통신 오류가 늘어나는 것을 보고 장애를 알아챘다. 장애 통화에 사람이 더 들어오면서 영향이 여러 서비스로 퍼진 것을 확인했다. 3월 13일 롤백 뒤에 로그에 나온 소수의 Sync 실패 오류는 그때 알아채지 못했다.

조치

후속 조치

교훈

이번 장애를 촉발한 원인은 하나가 아니었다. 네트워크는 모든 것의 바탕이어서 쿠버네티스 업그레이드는 본래 위험하다. 여러 사건이 맞물려 터진 이번 경우에는 팀이 세워 둔 위험 완화 방법이 듣지 않았다.

출처

관련 사례

내 클러스터에도 있는지 확인하기

kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이 사례와 같은 상태를 점검합니다. 이 사례의 구성 요소: kube-proxy, kubelet, CoreDNS. 점검 항목의 근거는 이 사례 같은 공개 보고서입니다.

AI 도구와 스크립트용

API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.