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

사례13건

13건 중 3~7번째

  1. 증상

    2026년 3월 4일 오후 4시 26분 PST 무렵부터 약 30분 동안 여러 모델의 API 요청에서 오류율과 지연 시간이 올랐다. 영향은 주로 API 트래픽에 나타났고, Codex 트래픽 일부도 영향을 받았다.

    촉발

    보호용 서킷 브레이커가 일부 스케줄링 작업을 멈춰 둔 사이에 인프라 작업이 큐에 쌓였고, 서킷 브레이커가 풀리자 이 작업이 한꺼번에 실행됐다.

    원인
    구성 요소
    기여 요인
    조치
    • 엔지니어들이 영향을 받은 모델에 인프라 자원을 손으로 다시 배정했다.
    • 추론 엔진을 다시 올리고 모델에 재배정해 서비스를 되살렸다.
    후속 조치
    • 자동 용량 관리 시스템이 실제 상태와 어긋났을 때 이를 더 잘 감지하고 대응하도록 보호 장치를 보강한다.
    • 서킷 브레이커와 스케줄링 시스템의 상태와 그 영향을 쉽게 알아볼 수 있도록 관측성을 높인다.
    • 오래 멈췄다가 풀린 뒤 큐에 쌓인 작업이 대량으로 한꺼번에 실행되지 않도록 보호 장치를 더한다.
    • 용량 조정이 실제 상태와 어긋나는 문제를 잡아내도록 모니터링과 알림을 개선한다.
    교훈

    실행을 멈춘 동안에도 작업을 큐에 쌓는 자동화는 멈춤이 풀리는 순간 낡은 상태를 근거로 한 변경을 한꺼번에 쏟아낼 수 있다. 서킷 브레이커가 무엇을 멈춰 두었는지, 풀릴 때 무엇이 실행될지 눈으로 확인할 수 있어야 한다. 긴 멈춤 뒤에 쌓인 작업이 대량으로 한 번에 실행되지 않게 막아야 한다.

  2. 증상

    새벽 3시에 "배포는 성공했는데, 서비스는 죽었다"는 Slack 메시지가 왔다. 모든 파드는 Ready 였고 Datadog 도 초록불이었지만, 사용자는 계속 오류 화면을 보고 있었다.

    촉발

    롤링 업데이트에서 새 파드가 readinessProbe 를 통과해 Ready 가 되자 Kubernetes 가 곧바로 옛 파드를 지웠다. 그때 ALB 는 새 파드 IP 를 대상 그룹에 막 등록해 initial 상태로 헬스 체크를 하고 있었다.

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

    새벽 3시에 "배포는 성공했는데, 서비스는 죽었다"는 Slack 메시지로 알았다. 파드 상태와 Datadog 대시보드는 모두 정상이었고, 장애는 사용자가 보는 화면에만 나타났다.

    조치
    • 네임스페이스에 elbv2.k8s.aws/pod-readiness-gate-inject=enabled 레이블을 붙였다. AWS Load Balancer Controller 의 웹훅이 파드에 ReadinessGate 를 넣었다. 새 파드는 ALB 대상이 healthy 가 된 뒤에야 Ready 가 됐고, 그제야 옛 파드가 지워졌다.
    교훈

    Kubernetes 의 Ready 와 ALB 의 healthy 는 서로 다른 시점에 정해지므로, 둘을 잇는 장치가 없으면 롤링 업데이트 때 502 가 날 수 있다. 파드 상태와 대시보드가 모두 정상이어도 사용자는 오류를 볼 수 있다. terminationGracePeriodSeconds 를 늘려 시간을 버는 방식은 배포만 느리게 하고 새 파드가 뜰 때의 공백은 막지 못한다. ReadinessGate 는 ALB 대상 유형이 ip 일 때만 의미가 있고, instance 모드에서는 노드가 대상이라 쓸 수 없다. ReadinessGate 를 쓰면 파드가 Ready 가 되기까지 30초에서 40초가 더 걸리므로 급한 스케일 아웃에 대비해 레플리카나 HPA 를 넉넉히 잡는다. 웹훅의 failurePolicy 를 Ignore 로 두면 컨트롤러가 죽어도 배포가 막히지 않는다.

  3. 증상

    2024년 12월 11일 오후 3시 13분 PST 에 알림이 울려 엔지니어들에게 전달됐다. 3시 16분부터 ChatGPT, API, Sora 를 포함한 OpenAI 의 모든 서비스가 크게 느려지거나 완전히 멈췄다.

    촉발

    오후 3시 12분 PST 에 쿠버네티스 컨트롤 플레인 지표를 자세히 수집하는 새 텔레메트리 서비스를 배포했다. 이 서비스의 설정 때문에 각 클러스터의 모든 노드가 무거운 쿠버네티스 API 요청을 보냈다. 이 요청은 클러스터가 클수록 비용이 커진다. 변경은 오후 2시 51분부터 3시 20분 사이에 모든 클러스터에 적용됐다.

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

    변경이 모든 클러스터에 적용되던 오후 3시 13분 PST 에 알림이 울려 엔지니어들에게 전달됐다. 탐지 도구는 고객이 영향을 받기 몇 분 전에 문제를 잡았고, 엔지니어들은 3시 16분에 원인을 찾았다. 다만 노드의 DNS 캐시가 실제 실패를 늦춰, 문제의 전체 범위가 보이기 전에 배포가 계속 진행됐다.

    조치
    • 클러스터 규모를 줄여 쿠버네티스 API 부하의 총량을 낮췄다.
    • 쿠버네티스 관리 API 로 가는 네트워크 접근을 막아 새로 들어오는 무거운 요청을 차단하고 API 서버가 회복할 시간을 벌었다.
    • 쿠버네티스 API 서버를 증설해 밀린 요청을 처리할 자원을 늘리고 수정을 적용할 수 있게 했다.
    • 컨트롤 플레인 제어권을 되찾은 뒤 문제의 텔레메트리 서비스를 지웠다.
    • 오후 3시 27분부터 영향받은 클러스터에서 트래픽을 빼기 시작했고, 가능한 곳에서는 트래픽을 정상 클러스터로 옮겼다.
    • 많은 서비스가 동시에 자원을 내려받아 자원 한도가 찬 클러스터에는 추가로 수동 조치를 했다.
    후속 조치
    • 모든 인프라 설정 변경에 단계적 배포를 적용하고, 서비스 워크로드와 쿠버네티스 컨트롤 플레인을 포함한 클러스터 상태를 계속 감시한다.
    • 데이터 플레인이 컨트롤 플레인 없이 버티는 상황과 잘못된 변경을 일부러 배포하는 상황을 시험하는 장애 주입 테스트를 돌린다.
    • 데이터 플레인이 컨트롤 플레인을 지나치게 압박할 때도 엔지니어가 쿠버네티스 API 서버에 접근할 수 있는 비상 접근 수단을 만든다.
    • 데이터 플레인과 컨트롤 플레인을 분리한다. 서비스 디스커버리가 쿠버네티스 DNS 에 묶여 있는 구조를 풀어, 핵심 서비스가 요청을 처리할 때 컨트롤 플레인에 기대지 않게 한다.
    • 클러스터 기동에 필요한 자원에 캐시와 동적 속도 제한을 더하고, 클러스터 하나를 통째로 빠르게 교체하는 훈련을 정기적으로 한다.
    교훈

    이 장애는 여러 시스템과 절차가 동시에 실패하며 예상하지 못한 방식으로 얽혀 생겼다. 테스트는 이 변경이 쿠버네티스 컨트롤 플레인에 주는 영향을 잡지 못했다. DNS 캐시 때문에 변경과 서비스 실패 사이에 시간 차가 생겼다. 컨트롤 플레인에 접근할 수 없게 되면서 복구가 매우 느렸다. 데이터 플레인이 컨트롤 플레인과 따로 돌도록 설계되어 있어도, DNS 기반 서비스 디스커버리가 컨트롤 플레인에 기대면 컨트롤 플레인 장애가 서비스 장애로 번진다. 배포 전 점검은 클러스터의 CPU 와 메모리 사용량만 봤고 API 서버 부하는 보지 않았다.

  4. 증상

    2023년 3월 14일 19시 UTC 직후 엔지니어가 Old Reddit 이라 불리는 레거시 스택을 돌리는 클러스터의 업그레이드를 시작했다. 2분쯤은 괜찮아 보였지만 곧 사이트 전체가 갑자기 멈췄다. CDN 엣지의 상태 코드별 RPS 그래프가 이를 보여 주었다. 사용자는 오류 페이지나 글이 하나도 없는 홈페이지를 보았다.

    촉발

    Reddit 에서 가장 중요한 클러스터 가운데 하나인 레거시 클러스터를 쿠버네티스 1.23 에서 1.24 로 업그레이드했다.

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

    업그레이드를 시작하고 2분쯤 뒤 CDN 엣지의 상태 코드별 RPS 그래프에서 사이트가 멈춘 것이 보였다. 팀은 곧바로 장애를 선언했고 3분 안에 대응 인원이 통화에 모였다. 엣지 지표는 일부러 클러스터와 분리되어 있어 살아 있었지만, 클러스터 자체의 지표는 모두 사라졌다.

    조치
    • API 서버에서 타임아웃을 내던 Open Policy Agent 의 웹훅 설정을 지웠다.
    • 복원 뒤 어차피 쓸 수 없게 될 워커 노드를 모두 종료했다.
    • 컨트롤 플레인 노드 두 대를 종료하고, 남은 한 대의 구성 요소를 다운그레이드한 뒤 그 노드에 백업 데이터를 복원했다.
    • 단일 노드 컨트롤 플레인이 부하에 무너지지 않도록 클러스터 오토스케일러를 껐다.
    • 새 컨트롤 플레인 노드를 띄우고, 호스트명이 맞지 않던 TLS 인증서를 새로 만들어 노드들을 합류시켰다.
    • 트래픽을 1% 에서 시작해 5%, 10%, 20%, 35%, 55%, 80%, 100% 로 조금씩 늘렸다.
    • 트래픽이 돌아올 때 문제를 일으키지 않도록 손으로 멈춰 두었던 민감한 레거시 서비스를 조심스럽게 다시 켰다.
    후속 조치
    • 클러스터 구성을 코드로 관리해 모든 선택에 기록이 남게 하고, 코드로 만들 수 없는 것은 자세히 문서로 남긴다.
    • 클러스터마다 다른 맞춤형 구성을 걷어 내고 모든 클러스터의 구성 요소를 표준화한다.
    • 모든 클러스터를 최대한 같은 모습으로 유지하고 필요하면 다시 만들거나 복제할 수 있도록 클러스터 전체의 수명 주기를 관리하는 도구를 만든다.
    • 믿고 테스트에 쓸 수 있는 프리프로덕션 클러스터를 더 둔다.
    • 백업 복원 절차를 개선하고 클러스터 업그레이드를 안전하게 만든다.
    교훈

    쿠버네티스 버전과 구성 요소 업그레이드는 여전히 위험하다. 미리 테스트하고 검증해도 이번처럼 처음 보는 방식으로 깨질 수 있다. 쿠버네티스에는 공식 다운그레이드 절차가 없어, 롤백하는 방법은 백업에서 복원하는 것뿐이다. 복원 절차가 환경 변화를 따라가지 못하면 실제 장애 때 그 자리에서 고쳐 써야 하고, 복원을 결정하기까지 오래 망설이게 된다. 이번 복원은 결국 성공했지만 절차는 개선해야 한다. 코드로 남기지 않은 설정은 아는 사람이 떠나면 아무 기록도 남지 않는다. 라우트 리플렉터 설정이 어디에도 커밋되어 있지 않아 장애 중에 누구도 의심하지 못했다. 지표가 클러스터 안에서만 수집되면 클러스터가 망가질 때 함께 사라진다. 이번에는 로그 수집 에이전트가 영향을 받지 않아 원인을 추적할 수 있었다. 클러스터마다 다른 맞춤형 구성이 쌓이면 장애가 잦아진다. 직접 원인은 노드 레이블이었지만 근본 원인은 일관성 부족이었다.

  5. 증상

    PR 하나를 머지한 직후 InfluxDB Cloud 운영 환경 하나가 통째로 사라졌다. 쓰기와 읽기를 비롯한 모든 API 엔드포인트가 404 오류를 냈다.

    촉발

    팀원 한 명이 설정 파일에 새 객체 여러 개를 더하는 PR 을 올렸다. 그중 새 ArgoCD Application 과 AppProject 의 이름이 자동화 오류로 app02-cluster01 이 아니라 기존 것과 같은 app01-cluster01 로 정해졌다. 코드 리뷰에서도 app01 과 app02 의 차이를 알아채지 못해 PR 이 그대로 머지됐다.

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

    모니터링과 경보 시스템은 이 장애를 바로 잡아내지 못했다. 그래서 팀은 계획을 세워 복구하기 전에 먼저 변경을 되돌리려 했다. 팀이 장애를 무엇으로 알게 됐는지는 글에 나오지 않는다.

    조치
    • 머지된 PR 을 되돌리기 시작했다가 곧바로 멈췄다.
    • etcd 메타데이터 클러스터를 복원했다.
    • 지워진 쿠버네티스 객체를 다시 만들어 남아 있던 PersistentVolume 을 다시 쓸 수 있게 하고, StatefulSet 을 다시 만들었다.
    • Zookeeper 볼륨을 Velero 로 매시간 받아 둔 백업에서 복원했다.
    • 헬스 체크와 readiness 체크를 끈 채 Kafka StatefulSet 을 파드 하나씩 다시 만들었다.
    • 쓰기 선행 로그 역할을 하는 Kafka 로 다시 쓰기를 받고, 쓰기를 처리하는 컴포넌트의 레플리카 수와 메모리 request 와 limit 을 늘렸다.
    • 스토리지 파드를 다시 만들었다. 파드는 오브젝트 스토리지에서 데이터를 내려받아 인덱싱한 뒤 쓰기 선행 로그에 밀려 있던 데이터를 읽어 들였다.
    • ArgoCD, 쿼리, 대시보드, 예약 작업을 다시 켜고, 레플리카 수를 원래대로 돌린 뒤 최종 QA 점검을 했다.
    후속 조치
    • 상태를 되살리는 절차를 담은 런북을 만들었다. PVC 같은 쿠버네티스 객체는 지워졌지만 디스크와 볼륨에 데이터는 남아 있을 때 할 일을 자세히 적었다.
    • 모든 환경의 모든 볼륨이 PVC 객체가 지워져도 데이터를 유지하도록 설정했다.
    • 외부에 드러나는 장애를 다루는 절차를 개선했다.
    • 생성된 YAML 을 객체 하나당 파일 하나로 저장하도록 바꿨다. 예를 들어 etcd Service 는 v1.Service-(namespace).etcd.yaml 파일이 된다. 이제 이번과 같은 PR 은 새 객체를 더하는 변경이 아니라 기존 객체를 덮어쓰는 변경으로 보인다.
    • YAML 생성 도구가 중복 객체를 찾아 리뷰를 요청하기 전에 경고하도록 고쳤다. 파일 이름만 보지 않고, apiVersion 이 networking.k8s.io/v1beta1 과 networking.k8s.io/v1 처럼 달라도 네임스페이스와 이름이 같으면 같은 객체로 판단한다.
    • 모든 상태 저장 리소스와 ArgoCD 가 관리하는 Namespace 객체에 Prune=false 어노테이션을 달아, 설정이 잘못돼도 ArgoCD 가 지우지 않게 했다.
    • ArgoCD Application 에 FailOnSharedResource=true 옵션을 넣었다. 다른 Application 이 관리하거나 관리했던 객체를 바꾸려 하면 ArgoCD 는 변경을 적용하지 않고 동기화를 실패로 멈춘다.
    교훈

    무엇보다 모니터링과 경보가 장애를 바로 잡아내지 못했다. 그 탓에 팀은 계획된 복구 대신 롤백부터 시도했다. InfluxDB Cloud 인스턴스 일부나 전체를 잃었을 때 쓸 런북도 없었다. 상태 저장 애플리케이션은 변경을 되돌린다고 원래대로 돌아오지 않고, 데이터 없는 새 인스턴스가 생길 뿐이다. 이런 PR 은 시스템이 머지를 막았어야 했다. 볼륨을 Retain 으로 둔 데다 Telegraf 처럼 쓰기를 재시도하는 클라이언트가 있어서 데이터를 하나도 잃지 않았다.

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

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

원인별5

배포 결함2건

  1. IL-0136 Sweden Central 리전에서 내부 서비스 배포가 캐시를 비워 메타데이터 백엔드에 평소 20배의 트래픽이 몰렸고, 데이터베이스 연결에 기대는 헬스 체크가 인스턴스를 계속 재시작시켜 Azure OpenAI 요청이 6시간 가까이 실패했다
  2. IL-0188 EKS 롤링 업데이트 때 Kubernetes 는 새 파드가 Ready 가 되자마자 옛 파드를 지웠지만 ALB 는 새 파드를 아직 healthy 로 보지 않아, 배포마다 약 30초 동안 502 가 났다.

설정 변경4건

  1. IL-0200 새로 띄운 쿠버네티스 노드가 호환되지 않는 etcd 버전으로 돌아 여러 운영 클러스터의 합의가 깨졌고, GitHub.com 의 git 작업과 웹 요청이 5XX 오류로 실패했다.
    GitHub2026
  2. IL-0005 새 텔레메트리 서비스가 모든 노드에서 무거운 쿠버네티스 API 요청을 보내 대형 클러스터의 컨트롤 플레인이 무너졌고, DNS 기반 서비스 디스커버리가 깨져 OpenAI 의 모든 서비스가 멈췄다
    OpenAI2024
  3. IL-0009 ArgoCD Application 이름이 겹쳐 InfluxDB Cloud 운영 환경 하나가 통째로 삭제됐다
  4. IL-0035 ElastAlert 에 새로 넣은 알림 규칙 때문에 ElastAlert 파드가 메모리를 끝없이 써서 노드가 잇달아 NotReady 가 되었고, 같은 클러스터의 도구와 Grafana, Prometheus 가 함께 흔들렸다.
    NU.nl2019

소프트웨어 결함4건

  1. IL-0124 서킷 브레이커가 풀리자 낡은 상태를 근거로 쌓여 있던 용량 조정이 한꺼번에 실행돼 여러 추론 엔진이 동시에 빠졌고, OpenAI API 의 오류율과 지연 시간이 올랐다.
    OpenAI2026
  2. IL-0032 mutating admission controller 의 JSON 패치 버그로 일주일 동안 새 코드가 배포되지 않았고, 운영 서비스 하나는 파드가 두 개만 남아 오류율이 치솟았다
    Airbnb2020
  3. IL-0012 CPU limit 과 커널 CFS 쿼터 버그로 파드가 과하게 스로틀링돼 헬스 체크가 실패하고 애플리케이션이 멈췄다
    Omio2020
  4. IL-0003 etcd 클러스터 재구성 뒤 쿠버네티스 버그로 linkerd 가 서비스 위치 갱신을 받지 못했고, linkerd 를 모두 재시작하자 엔드포인트가 없는 서비스를 파싱하지 못하는 오류가 드러나 플랫폼 전체가 멈췄다
    Monzo2017

업그레이드로 깨진 호환성1건

조직
  1. IL-0060 쿠버네티스 1.24 업그레이드로 node-role.kubernetes.io/master 레이블이 사라지자 이 레이블에 기대던 Calico 라우트 리플렉터가 동작을 멈춰 레거시 클러스터의 네트워크가 모두 끊기고 Reddit 이 314분 동안 멈췄다
    Reddit2023

용량 한계2건

  1. IL-0075 클러스터가 EC2 인스턴스 약 290대로 커지자 노드마다 도는 Datadog 에이전트가 쿠버네티스 API 를 폴링하면서 API 서버가 CPU 와 메모리를 다 써 쿠버네티스 컨트롤 플레인을 쓸 수 없게 됐다.
  2. IL-0001 CoreDNS 파드가 메모리 한도 100Mi 에 걸려 OOM 으로 계속 죽으면서 쿠버네티스 클러스터 전체의 DNS 가 멈췄다