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

사례24건

24건 중 1~5번째

  1. 증상

    2026-06-03 오후 3시 38분 EDT 에 xPRO 운영 CMS 와 xPRO 본 애플리케이션이 503 을 낸다는 알림이 함께 울렸다. 공개 사이트 https://xpro.mit.edu 에 고객이 제대로 접속하지 못했다.

    촉발

    cert-manager 가 2026-05-04 에 xpro-web.odl.mit.edu 인증서의 갱신 구간에 들어가 DNS-01 검증을 시작했다. 이 검증이 Fastly 가 만든 _acme-challenge.xpro-web.odl.mit.edu CNAME 과 부딪혀 끝나지 못했고, 기존 오리진 인증서가 2026-06-03 오후 3시 29분 EDT 에 만료됐다.

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

    오후 3시 38분 EDT 에 xPRO 운영 CMS 와 xPRO 본 사이트가 503 을 낸다는 알림이 울렸다. 인증서가 만료된 지 9분 뒤였다.

    조치
    • 오래된 cert-manager 자원을 지우고 다시 만들어 cert-manager 가 백엔드 오리진의 새 인증서를 발급하게 했다. 이것으로 서비스가 돌아왔다.
    후속 조치
    • OpenEdX 가 아닌 xPRO 의 Fastly TLS 구독에서 백엔드 오리진 도메인을 뺐다.
    • src/ol_infrastructure/applications/xpro 의 Production 스택에 Pulumi 변경을 배포했다.
    • Fastly 의 검증 CNAME 을 뺀 뒤, xpro 네임스페이스에 있는 OpenEdX 가 아닌 xPRO 인증서를 cert-manager 로 직접 갱신하거나 cert-manager 가 저절로 갱신하게 했다.
    • cert-manager 가 관리하는 오리진 도메인이 Fastly TLS 구독에 들어가지 못하게 막는 테스트나 정책 검사를 넣는 방안을 검토한다.
    • cert-manager 의 CertificateRequest 와 Order 가 실패하면 더 일찍 알림을 보내, 인증서가 만료되기 전에 오래된 ACME 실패를 찾는 방안을 검토한다.
    교훈

    이 장애는 처음에 cert-manager 의 ACME 갱신 실패로 이해됐다. 그 이해는 맞았지만 모자랐고, 빠진 진단은 Fastly 가 cert-manager 의 몫인 백엔드 오리진 도메인의 검증까지 관리하도록 설정돼 있었다는 점이었다. 갱신 실패를 일찍 잡지 못한 것은 cert-manager 가 관리하는 백엔드 오리진 도메인이 Fastly TLS 구독에 들어가면 안 된다는 것을 검사하는 장치나 테스트가 없었기 때문이다. 팀은 TLS 인증서와 DNS 검증 레코드를 누가 맡는지 경계를 분명히 정하고 그 경계를 지키는 장치를 둬야 한다고 정리했다. 특히 TLS 자동화를 설정할 때 Fastly 의 공개 프런트엔드 도메인과 쿠버네티스 APISIX 백엔드 오리진 도메인을 바꿔 써도 되는 같은 서비스 도메인으로 다루면 안 된다.

  2. 증상

    2026년 3월 25일 12:13 PDT부터 15:30 PDT까지 Discord 의 음성·영상 기능이 크게 망가졌다. 사용자 대부분이 통화를 시작하거나 참여하지 못했고, 통화 상태에는 “Awaiting Endpoint” 메시지가 떴다.

    촉발

    Elixir 서비스를 쿠버네티스로 옮기던 중, 주말 CPU 사용률을 낮추려고 sessions 서비스 파드의 CPU 와 메모리를 늘리고 파드 수를 그만큼 줄이는 변경을 배포했다. 레플리카 수가 줄자 쿠버네티스가 첫 번째 존의 파드 50% 를 종료했고, 진행 중인 다른 작업을 기다리는 안전 검사 때문에 핸드오프가 시작되기 전에 종료 유예 시간이 끝났다.

    원인
    구성 요소
    기여 요인
    조치
    • 13:43 PDT까지 calls, streams, guilds 서비스에 낮은 syncer 생성 제한을 넣고 voice syncers 클러스터를 다시 재시작했다. 막히는 supervisor 가 gun supervisor 로 바뀌면서 인스턴스들이 etcd 등록을 유지했고 일부 syncer 의 RPC 를 SFU 로 보냈다.
    • 인스턴스를 골라 하나씩 다시 재시작했고, 14:03에 재시작한 인스턴스 2-3 처럼 일부 인스턴스가 완전히 회복했다.
    • 인스턴스 15대를 추가로 올려 voice syncers 클러스터의 용량을 두 배로 늘렸다. 새 인스턴스들은 메일박스 대기열 문제 없이 syncer 를 받았고, 인스턴스당 syncer 수가 절반이 됐다.
    • 14:26에 마지막으로 막혀 있던 인스턴스를 재시작해 두 배로 늘어난 클러스터가 완전히 정상이 됐다.
    후속 조치
    • Elixir 워크로드용 validating admission webhook 을 쿠버네티스 클러스터에 넣어, 파드가 프로세스를 다 넘기기 전에는 워크로드를 줄이는 업데이트를 거부한다.
    • 부하 테스트 뒤 Holster.Pool 의 supervisor 를 PartitionSupervisor 로 바꿔, 연결 풀 요청을 독립된 여러 supervisor 에 나누고 나가는 연결을 동시에 만들거나 꺼낼 수 있게 했다.
    • gun 연결 프로세스의 생명주기 관리를 그 프로세스를 만드는 Holster.Pool 로 옮겨 gun 연결 supervisor 를 아예 쓰지 않게 했다.
    • voice syncers 를 호출하는 상위 서비스의 속도 제한을 다시 조정해 더 정확히 걸리게 했다. 필요하면 로드 셰딩 도구로 이 제한을 강제로 적용해 voice syncer 를 다시 만들게 할 수도 있다.
    • voice syncers 의 엔드포인트 선택에 새 속도 제한을 넣고 조정해, 나가는 연결 생성을 제한하는 수단을 하나 더 뒀다.
    • HTTP 연결 풀링 메일박스에 감시를 더해 언제 문제가 되고 언제 아닌지 더 분명히 알 수 있게 했다.
    • 서비스 디스커버리 등록과 voice syncer 에서 SFU 로 가는 RPC 트래픽의 계측과 로그를 전부 검토하고 넓혔다.
    • 메일박스 상태 합계 같은 간접 지표 대신, 모든 서비스에서 가장 중요한 프로세스를 직접 감시하도록 넓혀 간다.
    • 더 많은 워크로드를 쿠버네티스로 옮겨, VM 을 손으로 준비하는 대신 명령 하나로 파드를 늘릴 수 있게 한다.
    • A/V 인프라의 컨트롤 플레인 서비스를 여러 리전에 수평 확장해 신뢰성과 리전 장애 내성을 얻고, 나가는 연결 급증을 전 세계에 고르게 흩는다.
    교훈

    충분히 큰 트래픽 급증은 시스템 어딘가의 병목을 찾아낸다. 이전의 큰 부하 장애에서는 여러 ScyllaDB 데이터베이스가 복구를 막았지만, 이번에는 데이터베이스가 잘 버텼고 병목이 음성 서비스로 옮겨 갔다. 용량 한계를 만나면 공급을 늘리거나 수요를 줄이는 두 길이 있고, Discord 는 장애 대응과 사후 조치를 정할 때 이 질문을 분명히 던진다. 장애 중에는 쓸 수 있는 도구를 알아야 한다. Elixir 와 BEAM 가상 머신에서는 어떤 프로세스의 상태든 꺼내 볼 수 있고 핫패치로 관측을 더할 수도 있다. 분산 시스템에서는 장애 모드를 따져야 한다. Elixir 프로세스는 메시지를 하나씩 처리하므로 바쁜 프로세스의 핵심 루프가 느려지면 서비스와 사용자 경험이 함께 나빠진다. Discord 는 사후 검토에서 장애를 어떻게 피할지뿐 아니라 일어난 뒤 어떻게 더 빨리 풀지도 물었고, 복구 시간을 줄이면 관계없는 장애에서도 더 빨리 회복할 수 있다고 봤다.

  3. 증상

    8:10 UTC 에 팀은 Redis 스테이트풀셋을 고아 삭제했다. 고아 삭제는 파드와 디스크는 그대로 두고 스테이트풀셋 객체만 지우는 방식이다. 스테이트풀셋을 다시 만들자 쿠버네티스가 8:10 부터 8:15 UTC 사이에 스테이트풀셋 전체를 빠르게 재시작했다. 처음에는 백엔드 서비스가 Redis 연결 오류를 냈지만 서비스 전체가 곧바로 무너지지는 않았다.

    촉발

    팀은 디스크를 온라인으로 늘린 뒤 Git 의 선언적 설정을 실제 상태와 맞추려고 Redis 스테이트풀셋을 고아 삭제했다. 고아 삭제는 파드와 디스크는 남기고 스테이트풀셋 객체만 지우는 방식이다. 그다음 늘린 크기를 적은 저장소 템플릿으로 스테이트풀셋을 다시 만들었다.

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

    Redis 클러스터 여러 인스턴스의 디스크 여유 공간이 바닥나고 있다는 알림이 시작이었다. 그 뒤의 장애는 스테이트풀셋을 다시 만든 직후 백엔드 서비스가 Redis 연결 오류를 내면서 드러났다.

    조치
    • 망가진 Redis 클러스터를 손으로 복구했다. 마스터에서 쓸모없어진 노드 ID 를 지우고, 해당 레플리카를 리셋한 뒤 클러스터에 다시 붙이고 복제가 따라잡기를 기다렸다.
    • 실제로 메모리가 바닥난 구성 요소를 찾아낸 뒤, 백엔드 서비스를 확장하고 그 구성 요소의 메모리 한도를 올렸다.
    • 프로브를 잠시 느슨하게 해, 백엔드 인스턴스가 ready 와 not ready 를 오가지 않고 바로 트래픽을 받게 했다.
    • 10:00 UTC 에 임시 조치를 되돌렸다.
    후속 조치
    • 빠져 있던 스타트업 프로브를 넣는다. 데이터셋을 다 읽기 전에는 파드를 ready 로 표시하지 않는다.
    • 재시작한 파드가 옛 마스터 IP 주소에 묶여 있을 때 쓸 수 있도록 Redis 용 자체 컨트롤 플레인을 만든다.
    • 서비스 전체의 단일 장애점이 된 이 Redis 클러스터 의존을 줄인다. 중요한 정보 일부를 서버마다 따로 둔 Redis 클러스터 같은 다른 데이터 저장소로 옮기고, 백엔드 일부 구성 요소에 Kafka 를 쓰기 시작한다.
    교훈

    장애를 일으킨 것은 디스크 확장이 아니라 상태를 맞추려고 컨트롤러 객체를 다시 만든 단계였다. 고칠 수 없는 필드가 있으면 객체를 통째로 바꾸는 위험한 방법을 쓰게 된다. 그렇게 바꾸면 쿠버네티스가 워크로드를 넓은 범위에서 다시 조정할 수 있다. 스타트업 프로브와 엄격한 레디니스 프로브가 있어야 롤링 재시작이 현재 파드가 정말 준비될 때까지 기다린다. 이번 장애에서 가장 뼈아픈 것은 프로브가 없었다는 점이다. 분산 클러스터가 다시 붙고 복제를 따라잡는 데는 시간이 걸리므로, 의존하는 서비스는 그동안 기능을 줄여서라도 버티도록 설계해야 한다.

  4. 증상

    2025년 2월 18일 08:41 UTC, Grafana Labs 의 애플리케이션 팀 여러 곳이 자기 엔드포인트 일부에 접속이 되지 않는 것을 알아챘다.

    촉발

    로드 밸런서의 TLS 정책 버전을 올리면서, 기본 TLS 정책을 덮어쓸 수 있도록 Crossplane 컴포지션의 병합 정책을 바꾼 변경이 개발, 스테이징, 운영 환경에 동시에 적용됐다.

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

    08:41 UTC 에 애플리케이션 팀 여러 곳이 자기 엔드포인트 일부에 접속이 되지 않는 것을 알아챘다. 조사해 보니 최근의 TLS 정책 설정 변경 때문에 그 엔드포인트의 로드 밸런서가 사라져 있었다.

    조치
    • 문제의 코드 변경을 롤백했다.
    • 영향받은 쿠버네티스 Service 를 다시 만들어 쿠버네티스가 로드 밸런서를 새로 만들게 했다.
    후속 조치
    • 한 번에 두 개 이상의 웨이브로 배포하는 것을 막는 CI 검사를 넣어, 개발에서 스테이징, 카나리, 운영으로 이어지는 순서를 벗어나는 배포를 잡아내게 했다.
    • 논의만 하던 더 정교한 웨이브 설계의 우선순위를 올려 개선안을 합의하고 구현한다.
    • 실수로 지워지지 않도록 로드 밸런서에 삭제 보호를 켜기 시작했다. Crossplane 수준의 삭제 보호보다 한 층 아래에서 막는다.
    • 로드 밸런서 말고도 중요한 클라우드 리소스를 하나씩 살펴 필요한 곳에 삭제 보호를 켠다.
    • 변경 검증과 가시성을 높이려고 만든 Crossplane Managed Resources exporter 를 플랫폼 엔지니어링 안에서 베타로 시험하고 있다. 이번 장애를 일으킨 변경에 적용해 보면 차이가 분명히 드러난다.
    • TLS 정책을 다시 설정하는 기능을 제대로 완성하고 시험해, 애플리케이션 팀이 배포할 수 있게 했다.
    교훈

    작은 변경이라 위험이 낮다고 가정하고 충분한 시험과 영향 범위 줄이기를 건너뛴 것이 장애로 이어졌다. 웨이브 배포는 절차로 기대하는 데 그치지 않고 시스템이 강제해야 한다. 비상 예외는 웨이브를 고르지 않았을 때의 기본 동작이 아니라 말 그대로 예외여야 한다. 이번 변경은 시험을 안 한 것이 아니라 시험한 범위가 충분하지 않았다. 클라우드 로드 밸런서 컨트롤러와 자체 도구까지 처음부터 끝까지 돌려 봐야 의도한 작은 변화만 일어나는지 알 수 있었다. 개발 웨이브부터만 적용하도록 강제했다면 제대로 시험할 수밖에 없었을 것이다.

  5. 증상

    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 서버 부하는 보지 않았다.

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

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

원인별1

설정 변경24건

  1. IL-0512 xPRO 의 쿠버네티스 APISIX 오리진 인증서가 갱신되지 못하고 만료되어 xpro.mit.edu 가 한 시간 동안 503 을 냈다
  2. IL-0499 세션 서버가 대량으로 내려간 뒤 음성 통화 라우팅 서비스가 과부하로 멈춰 음성·영상 통화가 세 시간 넘게 연결되지 않았다
  3. IL-0063 Redis 스테이트풀셋을 다시 만들자 Redis 클러스터가 한꺼번에 재시작되며 일부가 망가졌고, 재연결 폭주로 백엔드가 OOM 으로 죽어 AdGuard VPN 이 약 50분 멈췄다.
  4. IL-0192 Crossplane 컴포지션의 병합 정책 변경이 Service 타입을 ClusterIP 로 바꿔 클라우드 로드 밸런서가 지워지고 Grafana Cloud 서비스의 약 25%가 끊겼다.
  5. IL-0005 새 텔레메트리 서비스가 모든 노드에서 무거운 쿠버네티스 API 요청을 보내 대형 클러스터의 컨트롤 플레인이 무너졌고, DNS 기반 서비스 디스커버리가 깨져 OpenAI 의 모든 서비스가 멈췄다
    OpenAI2024
  6. IL-0114 클러스터 용량을 늘리던 중 버전이 고정되지 않은 VPC CNI 플러그인이 자동으로 업데이트돼 새 파드가 IP 를 받지 못하고 Pending 에 머물렀고, 메인넷 운영 환경의 정산이 약 3.5시간 멈췄다.
  7. IL-0153 DOKS 1.27.6-do.0 과 1.28.2-do.0 워커 노드에서 매일 아침 도는 apt 자동 업그레이드가 15분 타임아웃에 걸려 강제 종료되면서 노드 네트워킹이 망가지고, 노드가 사흘 연속 NotReady 가 됐다.
  8. IL-0473 Azure 공개 쿠버네티스 클러스터의 노드 풀이 모두 지워지고 다시 만들어지지 않아 Jenkins 인프라 서비스가 4시간 넘게 멈췄다
  9. IL-0091 Terraform 으로 노드 인스턴스 타입을 바꾸자 노드가 한꺼번에 교체되어 사용자 운영 파드가 모두 지워지고 서비스가 내려갔다
  10. IL-0231 EKS 클러스터의 워커 노드가 모두 꺼지고 새 노드가 뜨지 않아 Stytch API 가 14분 동안 완전히 멈췄다
    Stytch2023
  11. IL-0109 로그 수집을 고치려던 EKS 노드 롤오버가 꼬이면서 Auto Scaling 그룹이 정상 워커 노드를 모두 종료해 클러스터에 노드가 하나도 남지 않았다.
    DFDS2023
  12. IL-0116 CNI 설정 변경이 스테이징에 없던 하드웨어 종류와 호환되지 않아 GPU 클러스터 하나의 워크로드가 네트워크 연결을 잃었고, text-davinci-003 모델이 완전히 멈췄다.
    OpenAI2023
  13. IL-0513 쿠버네티스 노드 순차 재시작 중 Ingress 가 관리하는 ELB 의 HTTPS 리스너가 꺼져 PyPI 백엔드에 HTTPS 로 닿지 못했다
  14. IL-0191 Loki distributor 서비스에 레이블 셀렉터가 하나 더 들어가 롤아웃 중 새 파드 몇 개에만 쓰기 트래픽이 몰렸고, 그 파드들이 OOM으로 죽으면서 로그 쓰기 경로가 약 25분간 멈췄다.
  15. IL-0009 ArgoCD Application 이름이 겹쳐 InfluxDB Cloud 운영 환경 하나가 통째로 삭제됐다
  16. IL-0111 메인 인그레스 컨트롤러를 Traefik v2 로 바꾸자 X-Forwarded 헤더가 전달되지 않아 Okta 로그인이 깨졌고, DFDS 온라인 예약이 한 시간 넘게 멈췄다
    DFDS2021
  17. IL-0010 템플릿 중괄호가 빠진 설정 변경으로 ArgoCD 가 전 세계 모든 클러스터의 서비스를 지웠다
  18. IL-0105 VPC CNI 교체로 ALB 에서 타깃 그룹이 떨어져 나가 쿠버네티스 클러스터의 모든 서비스가 503 을 냈다
    DFDS2021
  19. IL-0365 ALB 의 인스턴스 연결이 모두 사라져 Hellman 쿠버네티스 클러스터의 모든 서비스가 외부에서 닿지 않았다
    DFDS2020
  20. IL-0458 Toolforge 쿠버네티스 API 서버가 재시작 뒤 올라오지 못해 몇 시간 동안 클러스터 전체가 멈췄다
  21. IL-0008 응답하지 않는 OPA 검증 웹훅 때문에 GKE 마스터 업그레이드가 멈추고 API 서버가 간헐적으로 끊기면서 노드가 끝없이 재생성됐다
  22. IL-0004 새 Cortex 클러스터에서 기본 우선순위를 받은 파드가 우선순위가 없는 운영 Ingester 를 연쇄적으로 선점해 Hosted Prometheus 쓰기가 실패했다
  23. IL-0066 ConfigMap 만 바꾸고 디플로이먼트는 그대로 둔 탓에 잘못된 설정이 몇 주 뒤 노드 교체 때 모든 브리지 파드에 퍼져 Pusher 의 모든 트래픽이 끊겼다
    Pusher2019
  24. IL-0055 실패하는 CronJob 이 기본 concurrencyPolicy 때문에 겹겹이 쌓여 재시작하는 파드가 수천 개로 늘었고 클러스터가 내려갔다
    Target2018