Incident Library
적용된 필터 구성 요소영구 볼륨과 스테이트풀셋기여 요인단일 장애점모두 풀기검색어 없이 필터만 적용한 목록입니다. 최근 사례부터입니다.
추천 필터 검색하면 검색어에서 찾은 분류 값이 여기에 나옵니다.

그래프

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

사례4건

4건 중 1~4번째

  1. 증상

    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 를 쓰기 시작한다.
    교훈

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

  2. 증상

    2025년 9월 14일, 이미 떠 있던 노드는 계속 돌았지만 새로 만들어지는 노드는 하나도 클러스터에 제대로 들어오지 못했다. 스팟 인스턴스에서 돌던 백그라운드 워커, 리포트 서비스, 주문 할당 시스템이 완전히 멈췄다. API 는 기존 노드에서 계속 응답했지만 부하가 늘어도 확장할 수 없었다.

    촉발

    노드 풀의 자동 업그레이드를 꺼 두었는데도 Google 이 버전 지원 종료 기한을 이유로 컨트롤 플레인을 v1.32.x 에서 v1.33.2 로 강제 업그레이드했다.

    원인
    구성 요소
    기여 요인
    조치
    • 강제 업그레이드와 같은 버전인 v1.33 으로 새 GKE 클러스터를 만들었다.
    • 쿠버네티스 1.33 과 호환되도록 Istio 를 1.27.1 로 올렸다.
    • 쿠버네티스 1.33 에 맞게 cert-manager 설정을 갱신했다.
    • 모든 운영 워크로드를 새 클러스터로 옮기고, 파드 스케줄링, DNS 조회, PVC 마운트, 외부 연동이 정상인지 확인했다.
    • 손상된 기존 클러스터를 폐기했다.
    후속 조치
    • 모든 클러스터를 GKE stable 릴리스 채널로 설정한다.
    • 2025년 4분기까지 Argo CD 와 모니터링 같은 관리용 구성 요소를 따로 돌리는 관리 클러스터를 만든다.
    • 중요한 워크로드의 스팟 인스턴스 사용을 다시 검토하고, 온디맨드 대체 노드 풀을 추가한다.
    • SRE 업그레이드 절차를 문서로 남긴다. 관리 클러스터를 먼저 올리고, 며칠 동안 지켜본 뒤 운영 클러스터를 올린다.
    • 쿠버네티스, Istio, cert-manager 사이의 호환 표를 문서로 남긴다.
    • 업그레이드를 자동으로 시험하는 파이프라인을 만든다.
    • 빠르게 이전할 수 있도록 고정 IP 를 예약해 둔다.
    • Istio, cert-manager, CSI, DNS 애드온의 버전을 고정한다.
    • 지원 종료 기한에 몰리지 않도록 stable 릴리스를 따라 제때 올리고, GKE 알림과 공지를 정기적으로 확인한다.
    교훈

    Google 은 자동 업그레이드를 꺼 두어도 버전 지원 종료 기한이 되면 컨트롤 플레인을 강제로 올린다. 강제 업그레이드를 피하려면 지원 버전 범위 안에 머물러야 한다. 기존 노드가 멀쩡해도 새 노드 초기화는 완전히 실패할 수 있다. 선점된 스팟 노드가 클러스터에 돌아오지 못하면 장애가 연쇄로 번진다. 컨트롤 플레인을 올린 뒤 노드 초기화가 되돌릴 수 없게 망가지면 클러스터를 통째로 다시 만들어야 할 수도 있다. 예측할 수 있고 검증된 릴리스 주기를 원하면 GKE stable 채널을 쓴다. 쿠버네티스를 올릴 때는 Istio, cert-manager 같은 의존 구성 요소를 함께 맞춰야 한다. 같은 클라우드에 대기 클러스터가 없으면 바로 넘어갈 곳이 없다. SRE 가 롤아웃을 단계적으로 관리하면 업그레이드 위험이 줄어든다.

  3. 증상

    2025-04-14 09:33 UTC 쯤 Magic Pages 의 컨트롤 플레인 노드 세 대 중 한 대가 갑자기 오프라인이 됐다. 노드를 살펴보니 메모리가 바닥나 있었다. 운영자는 평소 절차대로 고장 난 노드를 빼고 메모리가 조금 더 큰 서버로 바꾸려 했다.

    촉발

    컨트롤 플레인 노드 한 대가 메모리 부족으로 오프라인이 됐다. 이 노드를 교체하는 배포가 실패해 다시 시도하는 동안, 클러스터 내부 구성 요소들이 Hetzner API 를 계속 호출해 시간당 3600건 한도를 소진했다.

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

    모니터링 경보가 쏟아지면서 고객 웹사이트에 접속할 수 없다는 것을 알았다. API 호출 한도가 원인이라는 것은 30분쯤 조사한 뒤에야 찾았다. hetzner-k3s 가 Hetzner API 오류를 감춰서 원인 파악이 늦어졌다.

    조치
    • API 호출을 확실히 멈추려고 서버 전원을 내려 쿠버네티스 클러스터 전체를 껐다.
    • Hetzner API 의 ratelimit-remaining 값이 다시 오르는 것을 지켜보면서, 복구 중에 다시 한도에 걸리지 않도록 여유분이 쌓일 때까지 기다렸다.
    • API 호출 여유가 생긴 뒤 컨트롤 플레인 서버를 다시 켰다.
    • 워커 노드를 올린 뒤 Longhorn 의 핵심 구성 요소를 손으로 띄워 스토리지 볼륨이 스스로 복구되게 했다.
    • 17:00 UTC 쯤 사이트의 95% 가 돌아온 뒤, 남은 사이트를 손으로 다시 시작했다.
    후속 조치
    • 클러스터 노드에서 나가는 Hetzner API 호출량을 따로 모니터링해서 사용량이 높아지면 미리 알 수 있게 한다.
    • Hetzner 와 협의해 API 호출 한도를 늘린다.
    • API 하나에 기대는 구조를 줄일 방법을 찾고, hetzner-k3s 로는 그렇게 하기 어렵다면 다른 도구를 검토한다.
    • 클러스터 전체가 꺼진 뒤 Longhorn 스토리지를 복구하는 절차를 더 탄탄하게 문서로 만들고 시험한다.
    교훈

    Hetzner 의 기본 API 한도인 시간당 3600건은 장애나 복구 상황에서 클러스터가 쓰는 양에 비해 부족했다. 운영자는 배포에 쓰는 API 사용량만 봤고, 실행 중인 클러스터 내부에서 나가는 호출은 지켜보지 않았다. 네트워킹 같은 핵심 기능이 클라우드 API 하나에 기대고 있으면, 그 API 가 막히는 순간 클러스터 전체가 약해진다. hetzner-k3s 의 추상화는 API 오류를 감춰 문제 해결을 늦췄다. 클러스터가 비정상 종료된 뒤 Longhorn 을 살리는 데 손이 많이 가서 장애가 길어졌다.

  4. 증상

    RedisFailover 리소스에 바뀐 설정을 적용하자 고객 웹사이트의 가장 큰 Redis 데이터베이스에서 데이터가 모두 사라졌다. 이 데이터베이스는 TTL 없이 영속 저장소로도 쓰였고, .rdb 스냅숏이 5 Gb 를 넘었다. 서비스가 멈췄고 백업에서 데이터를 복원해야 했다.

    촉발

    RedisFailover 리소스에서 Redis 레플리카 수를 1에서 2로 늘리면서, 같은 변경으로 컨테이너의 메모리 requests 와 limits 를 22 GB 에서 19 GB 로 낮췄다.

    원인
    구성 요소
    기여 요인
    조치
    • 미리 준비해 둔 백업에서 Redis 데이터를 복원했다.
    후속 조치
    • 레디니스 프로브 문제를 Redis Operator 이슈로 올렸고, 개발자들에게서 받은 수정을 시험해 통과를 확인했다.
    • 상황 분석을 마친 뒤 Spotahome Redis Operator 를 계속 쓸지 다시 검토한다.
    • Redis 데이터베이스를 정리하고, 불필요한 키를 만든 애플리케이션 코드를 고친다.
    • Redis 의 내장 클러스터링과 샤딩을 검토한다.
    교훈

    핵심 인프라를 쿠버네티스 오퍼레이터로 관리할 때는 그 오퍼레이터가 얼마나 성숙하고 검증됐는지 따져 봐야 한다. 레플리카 수와 리소스 값을 한 번에 바꾸면 롤링 업데이트가 예상하지 못한 순서로 파드를 재시작할 수 있다. 레디니스 프로브가 ping 만 보면 복제가 끝나지 않은 빈 인스턴스도 준비됐다고 판단한다. Redis 클러스터를 바꾸기 전에는 반드시 dump.rdb 파일을 백업해야 한다.

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

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

원인별4

설정 변경1건

  1. IL-0063 Redis 스테이트풀셋을 다시 만들자 Redis 클러스터가 한꺼번에 재시작되며 일부가 망가졌고, 재연결 폭주로 백엔드가 OOM 으로 죽어 AdGuard VPN 이 약 50분 멈췄다.

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

조직
  1. IL-0101 자동 업그레이드를 꺼 둔 GKE 클러스터의 컨트롤 플레인이 지원 종료 기한에 1.33.2 로 강제 업그레이드된 뒤 새 노드가 모두 초기화에 실패해, 오토스케일링과 스팟 노드 복구가 15시간 멈췄다.

용량 한계1건

  1. IL-0085 Hetzner Cloud 의 k3s 컨트롤 플레인 노드가 메모리 부족으로 꺼진 뒤 클러스터가 Hetzner API 호출 한도를 다 써 버려 모든 고객 사이트가 약 7.5시간 멈췄다.

소프트웨어 결함1건

조직
  1. IL-0196 Redis Operator 로 레플리카를 늘리면서 메모리 한도를 낮추자 데이터를 가진 유일한 Redis 파드가 재시작됐고, Sentinel 이 빈 레플리카를 마스터로 올려 데이터가 모두 지워졌다.
    Palark2020