Incident Library
적용된 필터 원인용량 한계기여 요인자동화 증폭모두 풀기검색어 없이 필터만 적용한 목록입니다. 최근 사례부터입니다.
추천 필터 검색하면 검색어에서 찾은 분류 값이 여기에 나옵니다.

그래프

  • 원인
  • 구성 요소
  • 증상
  • 기여 요인
  • 사례

사례7건

7건 중 1~5번째

  1. 증상

    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 는 클러스터가 커지고 변경 속도가 빨라지면 한순간에 무너질 수 있다. 나중에 낮출 생각으로 높게 잡아 둔 워커의 최대 레플리카 수는 노드 공급이 늦어질 때 오토스케일링 폭주를 막지 못했다. 모니터링 쿼리에 결함이 있고 쿼리량을 제대로 감시하지 않아 장기 추세가 보이지 않았다. 클러스터 핵심 서비스는 급격한 저하와 여유분 감소를 둘 다 직접 감시해야 한다.

  2. 증상

    트래픽이 급하게 오르내리는 환경에서 CoreDNS 에 부하가 몰렸다. 네트워크 문제가 생기고 응답 지연이 크게 늘었다.

    촉발

    트래픽이 급변하면서 수가 적은 CoreDNS 파드에 처리할 수 있는 양보다 많은 부하가 몰렸다.

    원인
    구성 요소
    기여 요인
    조치
    • 클러스터 크기에 맞춰 CoreDNS replica 를 늘리도록 CPA 를 설정하고, 인스턴스 타입에 맞게 nodesPerReplica, coresPerReplica, replica 최솟값과 최댓값을 조정했다.
    • CoreDNS 에 anti-affinity 대신 ScheduleAnyway 로 느슨하게 한 topologySpreadConstraints 를 걸어, Karpenter 의 Consolidation 과 Drift 가 CoreDNS 에 막히지 않게 했다.
    • CoreDNS 의 Error Rate, Panics, Request Duration, Request Rate 에 임곗값 알림을 걸었다.
    • NodeLocal DNSCache 를 적용해 노드마다 DNS 캐시를 두고 메인 CoreDNS 의 부하를 낮췄다.
    교훈

    CoreDNS 가 감당할 수 있는 양은 파드에 준 리소스에 따라 다르고, 그에 따라 평균 지연과 초당 질의 수인 QPS 도 달라진다. CoreDNS replica 를 무작정 늘리면 taint 와 topologySpreadConstraints 때문에 파드가 몇몇 노드에 몰려 Karpenter 의 Consolidation 을 막을 수 있다. 노드 하나가 드레인될 때 그 노드의 CoreDNS 가 한꺼번에 많이 종료되면 서비스에 영향이 갈 수 있다. NodeLocal DNSCache 를 쓰면 메인 CoreDNS 로 가는 DNS 질의가 크게 줄고 스파이크를 다루기 쉬워진다. 어느 노드에서 문제가 생겨도 메인 CoreDNS 는 영향을 받지 않는다. 그래서 서비스 전체 장애로 번질 일이 노드 하나의 문제로 그친다. 글쓴이는 CPA 와 NodeLocal DNSCache 를 함께 적용해 CoreDNS 부하 문제를 거의 없앴다고 보았다.

  3. 증상

    2024년 2월 13일 01:04 CET 에 FR-PAR 리전의 Kubernetes API 에서 RAM 과 CPU 사용량이 치솟아 OOM 이 났다. 노드들이 컨트롤 플레인에 인증하지 못해 일부가 "Not Ready" 상태가 됐다.

    촉발

    2월 12일 새 쿠버네티스 릴리스가 모든 사용자에게 나온 뒤, 12일에서 13일로 넘어가는 밤에 많은 클러스터가 동시에 자동 업그레이드를 시작했다.

    원인
    구성 요소
    기여 요인
    감지

    타임라인의 첫 기록은 01:04 CET 다. 이때 Kubernetes API 의 RAM 과 CPU 사용량이 치솟아 OOM 이 났고, 노드들이 컨트롤 플레인에 인증하지 못해 일부가 "Not Ready" 가 됐다. 기록된 첫 조치는 42분 뒤인 01:46 에 API 자원을 늘린 일이었다.

    조치
    • Kubernetes API 에 배정한 자원을 01:46 과 02:20 두 차례 늘렸다.
    • 02:30 에 API 트래픽을 제한해 들어오는 트래픽을 고르게 만들고 혼잡을 줄였다.
    • 03:20 부터 트래픽 제한을 50-100 개 배치로 나눠 차례로 풀어 노드들이 다시 인증하고 "Ready" 가 되게 했다.
    • 03:40 에 API 혼잡 중에 만들어진 고장 노드를 교체하는 스크립트를 돌렸다.
    • 15:45 부터 노드 인증이 한꺼번에 몰리지 않게 일부 클러스터부터 예전 인증 방식으로 차례로 롤백했고, 2월 19일 모든 클러스터에서 롤백을 마쳤다.
    • 노드 인증이 동시에 몰릴 수 있는 클러스터 업그레이드와 설정 갱신 기능을 2월 20일 10:30 까지 껐다.
    후속 조치
    • Kubernetes API 자원 배정을 늘렸다.
    • 예전 인증 방식으로 롤백했다.
    • 노드에 로컬 인증 캐시를 둔다.
    • 부하가 치솟을 때 더 잘 버티도록 자원 배정 전략을 다시 짠다.
    • 쿠버네티스에 새 요청 큐잉 방식을 넣는다.
    • 높은 부하나 장애가 다른 구성 요소로 번지지 않게 구성 요소를 서로 분리한다.
    • 몇몇 지표를 꼼꼼히 지켜봐 이상 패턴을 더 일찍 찾는다.
    • 이 기간에 노드를 배포했지만 제대로 쓰지 못한 고객에게 환불한다.
    교훈

    고객의 클러스터와 노드가 빠르게 늘면서 기존 트래픽 제어로는 혼잡을 막기 어려워졌다. 많은 클러스터의 자동 업그레이드가 한 번에 시작되면 Kubernetes API 에 부하가 몰리고, 계속 실패하고 재시도하는 노드 인증 방식이 혼잡을 더 키운다. 1월 24일 장애 뒤 넣은 단기 완화 조치로는 재발을 막지 못했다.

  4. 증상

    02:15 UTC 무렵부터 API 수집 엔드포인트의 이벤트 처리가 느려졌다. 실패는 났다가 멎기를 되풀이했고, 끝내 몇 분 동안 수집이 완전히 멈췄다. 기본으로 걸어 둔 알림이 수집 성능과 안정성 문제를 온콜 엔지니어에게 알렸다. 상태 페이지 첫 공지는 수집 서비스의 오류율과 응답 시간이 평소보다 높다는 알림을 조사하고 있다는 내용이었다.

    촉발

    몇 분 사이에 여러 곳에 흩어진 연결에서 비정상적으로 많은 쿼리가 들어왔다.

    원인
    구성 요소
    기여 요인
    감지

    기본으로 걸어 둔 알림이 수집 성능과 안정성 문제를 온콜 엔지니어에게 알렸다. 자동 로드 셰딩 장치도 작동하면서 알림을 더 보냈다. 상태 페이지 첫 공지는 18:28 PST 에 올라왔다.

    조치
    • 엔지니어들이 용량을 확보하려고 수집 호스트 수를 수동으로 크게 늘렸다.
    • 몇 분 동안 수집 트래픽 대부분을 끊고 수집 호스트 용량을 다시 확보했다.
    • 가장 공격적으로 트래픽을 보내던 발신처의 속도 제한을 트래픽이 가라앉을 때까지 임시로 낮춰 클러스터를 안정시켰다.
    후속 조치
    • 장기 해결책을 마련하는 동안 같은 장애가 반복되지 않도록 수집 호스트 수를 늘려 두었다.
    • 이번 장애 경로를 막을 프로젝트를 정하는 일에 집중한다.
    교훈

    Honeycomb 은 이번 장애를 이미 대비책이 있던 장애의 변형으로 보았다. 이번 장애는 그 대비책 일부를 비켜 가는 방식으로 일어났다. 실패했던 호스트들이 쿠버네티스의 CrashLoopBackOff 상태에 걸려 오프라인으로 남으면서 급하게 늘린 용량을 깎아 먹었다. OTel 처럼 배치 단위로 성공과 실패를 알리는 프로토콜에서는 서버가 일부만 버려도 클라이언트가 배치 전체를 다시 보내 트래픽이 크게 불어날 수 있다.

  5. 증상

    사용자들이 작업이 시작되지 않는다고 알려 왔다. 평소에는 모니터링이 먼저 잡아내는 편이었지만 이번에는 사용자 보고가 먼저였다. 처음부터 이미지 풀과 관련된 흔적이 보였다.

    촉발

    애플리케이션 하나가 읽어야 하는 버킷의 권한을 바꾸면서 그 애플리케이션이 시작하지 못하게 됐다. 이 애플리케이션은 약 1,000대 노드에서 도는 DaemonSet이었고 크래시 루프에 빠졌다. imagePullPolicy가 Always여서 재시작할 때마다 노드에 이미 있는 이미지를 다시 받았다.

    원인
    구성 요소
    기여 요인
    감지

    사용자들이 작업이 시작되지 않는다고 알려 와서 알았다. 모니터링보다 사용자 보고가 먼저였다. 팀은 파드 상태, 이미지 풀 지표, 레지스트리 응답 코드를 차례로 확인해 429 속도 제한을 찾았다.

    조치
    • 영향을 받은 NAT 인스턴스를 교체해 레지스트리로 나가는 출발지 IP를 바꿨다.
    • Cloud SQL 접속에 쓰던 고정 IP 설정과 방화벽 규칙을 다시 맞춰 데이터베이스 연결을 되살렸다.
    후속 조치
    • latest 같은 유동 이미지 태그를 막는 어드미션 웹훅을 만들어 워크로드 리소스와 파드에 걸었다.
    • 웹훅이 클러스터가 만드는 파드까지 거부하자, 파드 객체에서는 빼고 워크로드 객체에만 적용하도록 바꿨다.
    교훈

    imagePullPolicy가 Always인 DaemonSet이 크래시 루프에 빠지면 노드 수만큼 이미지 풀이 반복된다. 레지스트리 트래픽이 NAT 몇 대로 모이면 출발지 IP 몇 개가 속도 제한에 걸려 리전 전체가 이미지를 받지 못한다. NAT를 바꾸면 그 IP를 허용해 둔 외부 서비스 연결도 함께 끊긴다. 파드에 거는 어드미션 웹훅은 사용자가 아니라 컨트롤러가 만드는 파드까지 막는다. 발표자들은 대규모 클러스터에서는 DaemonSet을 특히 조심하라고 했다. DaemonSet이 기대는 DNS, Vault, 이미지 저장소도 모두 망가뜨려 본 적이 있다고 했다. 수천 대 단위로 무언가를 다루면 그만큼 망가뜨리기 쉽다는 것이다. kubelet 아래에도 인프라가 있다는 것을 잊지 말라고도 했다.

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

이 7건에서 가장 많이 나오는 구성 요소: 애플리케이션 데이터베이스, 파드 스케줄링과 배치. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.

원인별1

용량 한계7건

  1. IL-0102 배포와 워커 오토스케일링 폭주가 겹치자 크기를 고정해 둔 CoreDNS 가 메모리 한도를 넘겨 재시작된 뒤 회복하지 못했고, Buildkite 사이트 전체가 약 30분 멈췄다.
  2. IL-0182 트래픽이 급변할 때 수가 모자란 CoreDNS 가 과부하로 지연과 간헐적 네트워크 끊김을 일으켰고, 나중에는 과하게 늘린 CoreDNS 파드가 Karpenter 의 노드 통합을 막았다
  3. IL-0168 새 쿠버네티스 릴리스 뒤 많은 Kapsule 클러스터가 동시에 자동 업그레이드되면서 Kubernetes API 가 과부하로 OOM 이 났고, 새 노드 인증 방식의 재시도가 혼잡을 키워 노드가 Not Ready 가 됐다.
  4. IL-0202 갑자기 몰린 쿼리와 데이터베이스 쓰기로 Honeycomb 수집 호스트가 메모리 부족으로 죽었고, 쿠버네티스 CrashLoopBackOff 가 용량 회복을 막아 US1 이벤트 수집이 한 시간 넘게 불안정했다
  5. IL-0037 imagePullPolicy가 Always인 DaemonSet이 크래시 루프를 돌며 이미지를 계속 받아, NAT 세 대를 같이 쓰던 리전 전체가 이미지 레지스트리에서 429로 막혔다
  6. IL-0064 CPU 를 많이 쓰는 파드가 Google Cloud 노드 하나에 몰려 노드가 커널 패닉으로 죽었고, 다시 배치된 파드가 다음 노드를 또 죽이며 웹사이트와 API 가 멈췄다.
  7. IL-0036 재시도를 멈추지 않는 쿠버네티스 Job 이 노드 자원을 다 써 버려 클러스터의 노드가 차례로 죽고 검색과 리포트가 멈췄다.