사례5건
5건 중 1~5번째
IL-0102배포와 워커 오토스케일링 폭주가 겹치자 크기를 고정해 둔 CoreDNS 가 메모리 한도를 넘겨 재시작된 뒤 회복하지 못했고, Buildkite 사이트 전체가 약 30분 멈췄다.Buildkite2026- 증상
22:47 UTC 부터 Buildkite 웹 화면, REST API, Agent API, 작업 큐, 알림이 한꺼번에 장애를 겪었다. 모든 고객이 웹 화면이나 REST API 로 새 빌드를 만들 수 없었고, 작업 배정이 늦어졌다.
- 촉발
22:44 UTC 에 애플리케이션을 배포하면서 파드가 한꺼번에 늘어 이미 떠 있던 노드의 여유 용량이 바닥났다. 같은 시각 알림 워커를 비롯한 백그라운드 워커들도 확장하려 했고, 노드 공급이 늦어지자 확장 지표가 그대로인 채 파드를 계속 더 요청했다. 이 워커들의 최대 레플리카 수는 평소보다 높게 잡혀 있었다.
- 원인
- 구성 요소
- 기여 요인
- 감지
장애는 22:47 UTC 에 시작됐고, Buildkite 는 22:55 UTC 에 문제를 조사 중이라고 상태 페이지에 처음 알렸다. 23:05 UTC 에는 사이트 전체 장애를 조사 중이라고 올렸다. CoreDNS 쿼리 처리 시간은 클러스터가 커지면서 늘고 있었지만, 핵심 모니터링 쿼리의 결함과 쿼리량 모니터링 부족 때문에 장애 전에는 이를 알아채지 못했다.
- 조치
- 추가 애플리케이션 배포를 멈췄다.
- CoreDNS 파드를 3개에서 12개로 늘렸다.
- CoreDNS 파드마다 메모리 한도를 512 MiB 에서 2 GiB 로 올렸다.
- CoreDNS 를 돌리는 시스템 노드 풀을 늘렸다.
- 후속 조치
- CoreDNS 파드를 3개에서 12개로 늘리고, 파드당 메모리 한도를 512 MiB 에서 2 GiB 로 올리고, 이 파드들을 돌릴 시스템 노드 풀을 넓혔다.
- EKS 관리형 CoreDNS 오토스케일링을 켠다. 검증한 최소 레플리카 수를 정하고, 레플리카를 여러 노드와 가용 영역에 나눠 둘 만큼 용량을 확보한다.
- CoreDNS 쿼리 처리 시간, 쿼리량, 고루틴 증가, 메모리 압박, OOM 재시작, 사용 가능한 레플리카 수에 직접 알림을 건다. 장기 추세도 용량 계획에 넣어 지켜본다.
- 클러스터에 꼭 필요한 다른 서비스도 살핀다. 검증된 용량, 직접 알림, 장애 도메인 분산이 없는 서비스, 그리고 안전한 오토스케일링도 문서로 정한 고정 여유분도 없는 서비스를 찾아 고친다.
- 교훈
크기를 고정해 둔 CoreDNS 는 클러스터가 커지고 변경 속도가 빨라지면 한순간에 무너질 수 있다. 나중에 낮출 생각으로 높게 잡아 둔 워커의 최대 레플리카 수는 노드 공급이 늦어질 때 오토스케일링 폭주를 막지 못했다. 모니터링 쿼리에 결함이 있고 쿼리량을 제대로 감시하지 않아 장기 추세가 보이지 않았다. 클러스터 핵심 서비스는 급격한 저하와 여유분 감소를 둘 다 직접 감시해야 한다.
- 증상
2025년 9월 4일, CoreDNS 파드 하나가 OOMKilled 됐다.
- 촉발
CoreDNS 파드 하나가 OOMKilled 됐다.
- 원인
- 구성 요소
- 기여 요인
- 교훈
장애는 Istio, kube-proxy, conntrack 각각의 동작이 겹쳐 생겼다. Istio 는 DNS 캐시를 공격적으로 갱신하며 클라이언트 포트를 다시 썼고, kube-proxy 는 conntrack 항목을 정리하지 않았고, conntrack 의 UDP 기본 타임아웃은 2분이었다. kube-proxy 쪽 문제는 쿠버네티스 v1.32 에서 고쳐졌다. 발표자는 Istio 가 아주 복잡한 일은 단순하게 만들지만 아주 단순한 일은 복잡하게 만든다고 평했다. 발표자는 또 Cilium 을 소개했다. Cilium 은 iptables 체인을 차례로 훑는 대신 맵으로 Service 를 찾고, eBPF 데이터 경로로 kube-proxy 를 완전히 대체할 수 있다.
- 증상
프로덕션 EKS 클러스터에서 원인을 바로 알기 어려운 서비스 에러가 간헐적으로 났다. RDS 나 Redis 같은 외부 서비스를 호출할 때 연결이 가끔 실패했다. DNS 요청이 몰릴 때는 도메인 조회 응답이 늦어지거나 조회가 아예 실패했다.
- 촉발
모든 CoreDNS 파드가 같은 노드에 배치되었고, 그 노드의 메모리 사용률이 급증해 메모리가 고갈됐다.
- 원인
- 구성 요소
- 기여 요인
- 감지
글은 전면 장애를 어떻게 알아챘는지 적지 않았다. 그 전의 DNS 문제는 원인을 알기 어려운 서비스 에러가 간헐적으로 나면서 드러났다. 팀은 RDS 와 Redis 호출이 가끔 실패하는 현상을 추적하다가 DNS 이름 해석 실패가 근본 원인이라는 것을 확인했다.
- 조치
- CoreDNS 앞에서 DNS 질의를 받아 노드마다 캐시하는 NodeLocalDNS Cache 를 데몬셋으로 배포해 CoreDNS 부하를 줄였다.
- CoreDNS 에 maxUnavailable: 1 인 PodDisruptionBudget 과 topology.kubernetes.io/zone 기준의 topologySpreadConstraints 를 적용해 파드가 한 곳에 몰리지 않게 했다.
- Deployment 의 dnsConfig 로 ndots 값을 5 에서 2 로 낮춰 불필요한 DNS 조회를 줄였다.
- 교훈
쿠버네티스의 ndots:5 기본값은 점이 적은 외부 도메인을 조회할 때마다 질의를 여러 번 만든다. 이 부하는 트래픽이 큰 프로덕션 환경에서야 드러난다. CoreDNS 를 파드 2개의 기본 구성으로 두면 클러스터 전체의 단일 장애점이 된다. CoreDNS 파드는 노드와 가용 영역에 흩어 둔다. 별도 노드 그룹이나 Fargate 로 분리하면 다른 워크로드와 자원을 다투지 않는다. Affinity 와 PriorityClassName 으로 우선순위를 주면 더 안정적이다. CoreDNS 의 캐시와 bufsize 조정은 증상을 잠깐 줄였을 뿐이다. ndots 값은 여러 자료가 1이나 2를 권하지만 각 환경에 맞춰 정해야 한다.
- 증상
2021년 9월부터 메트릭 질의 서비스의 업데이트를 롤아웃할 때마다 오류가 늘었다. 서비스 로그에는 DNS 오류 때문에 메트릭 데이터 저장소에 연결하지 못했다는 내용이 찍혔다. 클라이언트가 실패한 질의를 자동으로 재시도해 사용자에게 보이는 오류는 적었지만, 재시도 때문에 대시보드와 모니터의 지연이 늘었다.
- 촉발
2021년 8월 메트릭 질의 클라이언트의 업데이트를 롤아웃하면서 새 기본값인 gRPC round_robin 부하 분산 정책이 처음 적용됐다. round_robin 은 끊긴 채널을 자동으로 다시 연결하는데, 오래전에 넣어 둔 매우 공격적인 gRPC 재연결 타임아웃과 겹쳐 서비스 롤아웃 때마다 사라진 파드 IP 로 SYN 이 쏟아졌다.
- 원인
- 구성 요소
- 기여 요인
- 감지
2021년 9월부터 메트릭 질의 서비스 롤아웃 때 오류가 늘어나는 것을 보았고, 서비스 로그에서 DNS 오류가 데이터 저장소 연결을 막는 것을 확인했다.
- 조치
- node-local-dns 파드의 메모리를 64 MB 에서 256 MB 로 올렸다. OOM 오류는 멈췄지만 DNS 오류는 계속됐다.
- AWS 가 더 많은 연결을 추적할 수 있다고 한 더 큰 인스턴스 유형으로 서비스 인프라를 올려 보았고, 그것만으로 문제가 사라지는 것을 확인했다.
- SYN 폭주를 일으킨 사용자 지정 gRPC 재연결 파라미터를 지우고 기본값으로 되돌리는 PR 을 만들었다. 다음 롤아웃에서는 오류가 나지 않았다.
- 후속 조치
- Cilium 프로젝트에 PR 을 기여한다. 이 PR 은 옛 파드 IP 에 unreachable 경로를 더해, 지워진 파드로 가는 요청이 martian 패킷이 되지 않게 한다. 그러면 역경로 필터가 SYN 을 버리지 않고, 클라이언트는 분명한 ICMP 오류를 받는다.
- 교훈
gRPC, 쿠버네티스, AWS 같은 강력한 추상화도 엣지 케이스에서는 평소에 숨어 있던 복잡함이 오류로 드러난다. 몇 달을 조사한 끝에, 이번 장애의 뿌리가 팀이 직접 한 변경에 있다는 것을 찾았다. 의존성의 버그를 피해 가려던 변경, 이전 장애를 고치려던 변경, 기본 재연결 파라미터를 덮어쓴 변경이었다. 이 변경들은 당시에는 안전해 보였지만 한참 뒤에 상관관계를 찾기 어려운 때에 뜻밖의 결과를 냈다. DNS 문제처럼 보여도 DNS 문제가 아닐 때가 있다. AWS ENA 지표와 VPC Flow Logs 는 연결 추적을 들여다보는 데 중요하다. DNS 전파 시간은 여러 요인에 좌우된다.
- 증상
Zalando Fashion Store 의 모든 웹 상품 페이지와 코디 페이지가 한 시간 넘게 고객에게 오류를 많이 냈다. 오류는 쿠버네티스 클러스터 하나에서 도는 핵심 데이터 집계 계층 서비스에서 나왔다.
- 촉발
그리 중요하지 않은 하위 서비스 하나로 가는 호출이 타임아웃 나기 시작했다. 집계 계층이 이 호출에 404 로 응답하자 클라이언트가 재시도했고, 집계 계층으로 가는 요청과 그만큼의 DNS 쿼리가 갑자기 치솟았다.
- 원인
- 구성 요소
- 기여 요인
- 감지
DNS 장애로 클러스터 내부 모니터링이 함께 멈춰 당직 호출이 자동으로 가지 않았다. 집계 계층 서비스 당직 엔지니어가 평소처럼 자동 호출에 기대지 못하고 쿠버네티스 담당 당직 엔지니어에게 직접 전화했다. 그래서 쿠버네티스 당직 엔지니어가 장애를 알기까지 예상보다 오래 걸렸다. 연락을 받은 엔지니어가 CoreDNS 파드가 OOM 으로 죽고 있는 것을 찾아냈다.
- 조치
- 쿠버네티스 당직 엔지니어가 CoreDNS 파드의 메모리 request 와 limit 을 100Mi 에서 2000Mi 로 직접 올렸다.
- 후속 조치
- 노드마다 dnsmasq 를 앞에 둔 CoreDNS 를 띄우는 방식으로 더 튼튼한 DNS 구성을 도입한다. 검토하고 시험한 다른 어떤 구성보다 이 방식의 성능이 좋았다.
- 클러스터 바깥에서 클러스터 전체 상태를 보는 알림을 강화한다. 팀은 클러스터 안 애플리케이션이 영향을 받기 전에, 늦어도 같은 시점에는 클러스터 이상을 알아야 한다.
- 장애 대응 절차와 도구를 개선한다. 자동 당직 호출이 실패해도 당직 엔지니어가 다른 도구로 옮겨 가지 않고 다른 팀에 바로 에스컬레이션할 수 있게 한다. 채팅 봇으로 에스컬레이션을 단순하게 만드는 방안을 추진하고 있다.
- 교훈
쿠버네티스 DNS 구성은 충분히 튼튼하지 않았다. 애플리케이션 하나가 DNS 를 사실상 서비스 거부 공격하듯 몰아붙여 클러스터 전체를 멈추게 할 수 있어서는 안 된다. DNS 쿼리를 늘린 애플리케이션의 영향 범위는 적어도 노드 하나, 가능하면 파드 하나 안에 갇혀야 한다. 팀은 conntrack 을 처리하는 리눅스 커널의 경쟁 상태나 ndots 5 문제 같은 쿠버네티스 DNS 문제를 대부분 알고 있었고, 일부는 완화책도 갖고 있었다. 하지만 이 문제들이 DNS 구성에 얼마나 크게 영향을 주는지는 제대로 알지 못했다. 모니터링도 충분히 튼튼하지 않았다. 일부 알림은 클러스터 밖에서 돌았지만 대부분은 클러스터 안에서 돌았다. 그래서 DNS 가 무너졌을 때 당직 엔지니어가 자동으로 호출되지 않았고 복구 시간이 필요 이상으로 길어졌다.
이 5건에서 가장 많이 나오는 구성 요소: CoreDNS, 클라이언트 쪽 DNS 리졸버와 캐시. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.
원인별3
용량 한계3건
IL-0102배포와 워커 오토스케일링 폭주가 겹치자 크기를 고정해 둔 CoreDNS 가 메모리 한도를 넘겨 재시작된 뒤 회복하지 못했고, Buildkite 사이트 전체가 약 30분 멈췄다.Buildkite2026IL-0027CoreDNS 파드가 모두 한 노드에 몰린 채 그 노드의 메모리가 고갈되자 DNS 가 응답하지 못해 아이디어스 서비스 전체가 멈췄다Backpackr2025IL-0001CoreDNS 파드가 메모리 한도 100Mi 에 걸려 OOM 으로 계속 죽으면서 쿠버네티스 클러스터 전체의 DNS 가 멈췄다Zalando2019
소프트웨어 결함1건
- 기여 요인
설정 변경1건
- 조직