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

사례3건

3건 중 1~3번째

  1. 증상

    Omio 는 6개월 동안 원인을 알 수 없는 멈춤을 겪었다. 애플리케이션이 멈추거나 헬스 체크에 응답하지 않았고, 네트워크 연결이 끊겼다.

    촉발

    쿠버네티스는 CPU limit 을 커널 CFS 의 쿼터로 구현한다. 주기는 100ms 이고, limit 2코어는 주기마다 CPU 시간 200ms 가 된다. 스레드 10개가 동시에 돌면 20ms 만에 쿼터를 다 쓰고, 남은 80ms 동안 파드의 모든 스레드가 멈춘다. 여기에 커널 CFS 스케줄러의 알려진 버그가 불필요한 스로틀링을 일으켜, 컨테이너가 허용된 쿼터를 다 쓰기도 전에 스로틀링됐다.

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

    팀은 6개월 동안 애플리케이션이 멈추거나 헬스 체크에 응답하지 않는 현상을 겪었지만, 쿠버네티스가 cgroup 지표를 내보내지 않아 스로틀링을 바로 알아채지 못했다. 파드 안에서 /sys/fs/cgroup/cpu/cpu.stat 의 nr_throttled 와 throttled_time 을 읽어 스로틀링 비율을 확인했다.

    조치
    • 버그를 고친 최신 커널이 모든 클러스터에 배포될 때까지 CPU limit 을 껐다.
    후속 조치
    • CFS 쿼터 버그를 고친 최신 커널을 모든 클러스터에 배포한다.
    • 사용률, 포화도, 오류를 보는 USE 지표와 함께 API 지연과 오류율을 지켜보며 결과가 기대한 대로인지 확인한다.
    교훈

    CFS 쿼터 버그가 고쳐지지 않은 커널을 쓴다면 쿠버네티스에서 CPU limit 을 없애거나 kubelet 에서 CFS 쿼터를 끄는 편이 낫다. CPU request 와 limit 은 설정이 비슷해 보여도 구현이 전혀 다르다. CPU 스로틀링은 쿠버네티스 기본 지표에 드러나지 않으므로 cpu.stat 을 직접 확인해야 한다. limit 을 끄면 최적화되지 않은 애플리케이션이 노드의 CPU 를 독차지할 수 있으니, JVM, Go, Node 런타임을 미리 튜닝해 둬야 한다.

  2. 증상

    2018년 7월 19일 15:00 UTC 쯤 모니터링 인프라가 일부 API, 특히 pilot 과 tiles 의 5xx 응답 증가를 알렸다. 사용자 프로필을 가져오는 pilot 서비스가 먼저 응답하지 않아 플랫폼 로그인이 실패했고, 문제는 거기서 퍼져 나갔다.

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

    15:00 UTC 쯤 모니터링 인프라가 일부 API, 특히 pilot 과 tiles 의 5xx 응답 증가를 알렸다.

    조치
    • 멈춘 워커 노드의 kubelet 을 되살리려 했지만 노드는 곧 다시 Not Ready 가 되었다.
    • 18:00 UTC 쯤부터 클러스터의 모든 워커 노드를 시차를 두고 재시작했다. 약 1.5시간 뒤 모든 노드의 재시작이 끝나며 서비스가 안정되었다.
    후속 조치
    • 수정이 업스트림에 들어가 클라우드 제공자인 MS Azure 에 반영될 때까지, 노드와 kubelet 이 정상으로 돌도록 정기적인 롤링 재시작을 적용한다.
    교훈

    AirMap 은 운영 클러스터의 증상을 오픈소스 커뮤니티의 알려진 이슈와 대조해 근본 원인과 수정 후보를 찾을 수 있었다. 업스트림 수정이 클라우드 제공자에게 반영되기 전까지는 워커 노드를 정기적으로 롤링 재시작해 같은 장애를 막는다.

  3. 증상

    14:10 에 입출금 계좌 결제 처리에 필요한 서비스 하나를 배포하자 그 서비스로 가는 요청이 모두 실패했다. 이때부터 입출금 계좌 고객의 결제가 실패했다. 선불 카드는 이 서비스를 쓰지 않아 아직 영향이 없었다.

    촉발

    14:10 에 엔지니어가 입출금 계좌 결제 처리에 필요한 서비스에 변경을 배포했다. 2주 전 etcd 클러스터를 재구성한 뒤로 쿠버네티스와 etcd 클라이언트 버그가 요청 타임아웃을 낼 수 있는 상태였고, 이 때문에 linkerd 는 배포 뒤 새 파드의 위치를 받지 못했다.

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

    14:10 배포 직후 그 서비스로 가는 요청이 모두 실패했고 입출금 계좌 결제가 실패하기 시작했다. 14:12 롤백 뒤에도 오류가 계속되자 14:16 에 내부적으로 장애를 선언했다. 15:13 에 플랫폼 전체가 멈추자 자동 알림이 거의 모두 울렸다.

    조치
    • 14:12 에 배포한 변경을 롤백했지만 오류는 계속됐다.
    • 고객 영향을 줄이려고 장애 때 쓰는 내부 백업 절차를 가동해 대부분의 고객이 계속 카드를 쓸 수 있게 했다.
    • 14:26 에 linkerd 인스턴스 수백 개를 모두 재시작하기 시작했고, 이 조치가 장애를 키웠다.
    • 14:37 에 kubelet 이 apiserver 에서 설정을 받지 못하자 apiserver 프로세스 세 개를 재시작했다.
    • 15:27 에 플랫폼 팀이 새 linkerd 버전을 배포하기 시작했다. 이 버전에는 비호환 문제를 고친 코드가 들어 있었고, 스테이징에서 몇 주째 시험하던 버전이었다.
    • 15:31 에 엔드포인트가 없는 쿠버네티스 서비스를 지워 linkerd 가 서비스 디스커버리 정보를 읽게 했고, 플랫폼이 회복했다.
    후속 조치
    • 클러스터 재구성 뒤 타임아웃을 일으킬 수 있는 쿠버네티스 버그를 고친다.
    • 파싱 오류를 고친 새 linkerd 버전을 배포한다.
    • 영향을 받은 구성 요소에 더 나은 헬스 체크, 대시보드, 알림을 만들어 무엇이 잘못됐는지 더 분명한 신호를 주고 사람의 실수를 막는다.
    • 장애를 내부와 외부에 더 분명하고 빠르게 알리도록 절차를 개선한다.
    교훈

    분산 시스템의 대규모 장애는 이해하기 매우 어렵고, 사람이 좋은 뜻으로 한 조치가 오히려 문제를 키울 수 있다. 이번에는 linkerd 를 모두 재시작한 결정이 또 다른 버전 비호환 문제를 드러내 장애를 더 키웠다. 배포가 잦고 노드와 애플리케이션 장애에 자동으로 대응하는 백엔드에서는 네트워크가 매우 동적이다. 그래서 배포와 요청 라우팅 시스템을 믿을 수 있는 것이 무엇보다 중요하다. Monzo 는 인터페이스를 바꿀 때 앞뒤 버전과 호환되게 해서 롤백을 안전하게 할 수 있게 해 두었지만, 이번에는 롤백한 뒤에도 오류가 계속됐다.

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

이 3건에서 가장 많이 나오는 구성 요소: kubelet, 컨테이너 CPU 한도. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.

원인별1