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

사례5건

5건 중 1~5번째

  1. 증상

    2025-10-21 21:45 UTC, 타임아웃 오류를 줄이려는 배포 직후 자동 모니터링이 기능 플래그 서비스의 오류율 상승을 잡았다. 2분 만에 롤백했지만 오류율은 내려가지 않았고, US 데이터센터에서 평가 요청의 약 38% 가 오류를 냈다.

    촉발

    10월 21일에는 증상만 고치려던 타임아웃 처리 배포가 장애를 일으켰다. 28일에는 플래그 서비스와 무관한 일상 배포가 파드 롤아웃을 일으켰고, 이 롤아웃이 장애로 이어졌다. 24일에는 로드밸런서 뒤에서 모든 트래픽을 IP 하나에서 온 것으로 본 레이트 리밋 배포가 장애를 일으켰다.

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

    21일에는 배포 2분 뒤 자동 모니터링이 오류율 상승을 잡았고, 28일에는 온콜이 높은 오류 수 경보를 받았다. PostHog 는 대부분의 경우 2분 안에 감지했다고 정리했다. 24일에는 429 오류 경보가 없어서 18:10 UTC 부터 들어온 고객 신고로 알았고, 감지까지 62분이 걸렸다. CPU 경보가 아예 없어서 공통 원인인 CPU 포화는 오래 드러나지 않았고, 29일에서 30일 사이 장애는 7시간 넘게 이어졌다.

    조치
    • 10월 21일 타임아웃 처리를 바꾼 배포를 2분 안에 롤백했지만 오류는 멈추지 않았다.
    • 10월 21일 23:00 UTC 부터 연결과 Redis 쓰기를 조절해 23:28 UTC 에 서비스를 복구했다.
    • 10월 28일 롤아웃을 멈추고 US 플래그 파드를 0개로 줄여 Redis 가 회복되기를 기다린 뒤, 파드를 차례로 다시 올렸다.
    • 10월 30일 00:03 UTC 에 하드웨어 변경을 롤백해 오류는 대부분 가라앉혔지만 지연은 남았다.
    • 파드 리소스 요청을 늘리고 쿠버네티스 플릿 크기를 조정해 노드당 파드 수를 줄였다.
    • 로드밸런서와 서비스 사이 Envoy 재시도에 한도를 걸었다.
    • 데이터베이스 연결 타임아웃과 다른 중요한 설정을 런타임 설정으로 옮기고, 타임아웃 값을 피크 부하에 맞게 늘렸다.
    • 노드마다, 파드마다 CPU 사용률이 80% 를 5분 동안 넘으면 온콜을 호출하는 CPU 경보를 추가했다.
    후속 조치
    • 플래그, 수집, 인프라 팀 엔지니어로 전담 팀을 꾸려 애플리케이션과 인프라 전체를 살피고 남은 병목을 찾는다.
    • 플래그 서비스의 Redis 를 본 애플리케이션의 Redis 와 분리하는 방안을 검토한다.
    • ArgoCD 동기화를 다시 켜기 전에 플래그 서비스 차트 설정을 ArgoCD 의 현재 값에 맞추고, 배포 전략과 Redis 전략을 정한다.
    • 플래그 관련 코드의 필수 코드 오너를 기능 플래그 팀으로 정한다.
    • 중요한 플래그 지표와 런북 링크를 한데 모은 대시보드를 만들고, 기능 플래그 런북을 고친다.
    • 기존 서비스 지표와 인프라 지표에 빠져 있는 경보를 추가한다.
    • readiness 검사가 liveness 검사를 그대로 따라 하지 않고, 데이터베이스에 ping 을 보내는 식으로 부하가 걸렸을 때 약해졌던 의존성을 확인하게 바꾼다.
    • 캐시 채우기 작업에 레이트 리밋을 걸어 Redis 에 감당하지 못할 만큼 작업이 몰리지 않게 한다.
    • 연결 풀을 모니터링해 풀이 바닥에 가까워지면 자동으로 요청을 조절하고, 동시 연결 수에 상한을 둔다.
    • 운영 규모의 부하 시험 체계를 만든다.
    • 점진적 롤아웃 기반을 만들어 배포가 미치는 범위를 줄인다.
    • Postgres 에서 Redis 로 가는 데이터 흐름을 문서로 정리하고, 데이터 전송이 한꺼번에 몰릴 때 쓸 런북을 만든다.
    교훈

    가장 큰 교훈은 CPU 크기 산정이었다. 노드가 파드 요청에 비해 작으면 노드 하나에 파드가 너무 많이 몰리고, CPU 포화가 과도한 병렬 처리, 연결 풀 고갈, 느린 쿼리처럼 서로 다른 모습으로 나타난다. 증상만 고친 수정 때문에 21일의 장애가 28일에 되풀이됐다. PostHog 는 CPU 를 넉넉히 받은 파드를 적은 수로 돌리는 편이 낫다고 정리했다. 기능 플래그 서비스와 본 애플리케이션이 Redis 를 같이 쓰면 한쪽 과부하가 다른 쪽을 쓰러뜨리는 단일 장애 지점이 된다. CPU 지표는 처음부터 경보로 걸어야 하고, Postgres 에서 Redis 로 가는 전송 급증도 경보 대상이다. 재시도, 캐시 채우기, 연결 생성에 한도가 없으면 장애가 커진다. 과부하 패턴은 운영 트래픽에서만 드러났으므로 부하 시험이 필요하고, 중요한 설정은 배포 없이 바꿀 수 있어야 한다.

  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. 증상

    프로덕션 EKS 클러스터에서 원인을 바로 알기 어려운 서비스 에러가 간헐적으로 났다. RDS 나 Redis 같은 외부 서비스를 호출할 때 연결이 가끔 실패했다. DNS 요청이 몰릴 때는 도메인 조회 응답이 늦어지거나 조회가 아예 실패했다.

    촉발

    모든 CoreDNS 파드가 같은 노드에 배치되었고, 그 노드의 메모리 사용률이 급증해 메모리가 고갈됐다.

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

    글은 전면 장애를 어떻게 알아챘는지 적지 않았다. 그 전의 DNS 문제는 원인을 알기 어려운 서비스 에러가 간헐적으로 나면서 드러났다. 팀은 RDS 와 Redis 호출이 가끔 실패하는 현상을 추적하다가 DNS 이름 해석 실패가 근본 원인이라는 것을 확인했다.

    조치
    • CoreDNS 앞에서 DNS 질의를 받아 노드마다 캐시하는 NodeLocalDNS Cache 를 데몬셋으로 배포해 CoreDNS 부하를 줄였다.
    • CoreDNS 에 maxUnavailable: 1 인 PodDisruptionBudget 과 topology.kubernetes.io/zone 기준의 topologySpreadConstraints 를 적용해 파드가 한 곳에 몰리지 않게 했다.
    • Deployment 의 dnsConfig 로 ndots 값을 5 에서 2 로 낮춰 불필요한 DNS 조회를 줄였다.
    교훈

    쿠버네티스의 ndots:5 기본값은 점이 적은 외부 도메인을 조회할 때마다 질의를 여러 번 만든다. 이 부하는 트래픽이 큰 프로덕션 환경에서야 드러난다. CoreDNS 를 파드 2개의 기본 구성으로 두면 클러스터 전체의 단일 장애점이 된다. CoreDNS 파드는 노드와 가용 영역에 흩어 둔다. 별도 노드 그룹이나 Fargate 로 분리하면 다른 워크로드와 자원을 다투지 않는다. Affinity 와 PriorityClassName 으로 우선순위를 주면 더 안정적이다. CoreDNS 의 캐시와 bufsize 조정은 증상을 잠깐 줄였을 뿐이다. ndots 값은 여러 자료가 1이나 2를 권하지만 각 환경에 맞춰 정해야 한다.

  4. 증상

    2022년 11월 14일 LIS 허브 사용자가 "backoff after failed scale-up" 오류를 보고했다. 사용자 서버가 뜨지 않았고 노드 풀이 늘어나지 않았다.

    촉발

    영국 시각 오전 10시에 Google Cloud europe-west2 리전의 B 존에서 할당할 자원이 바닥났다.

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

    사용자가 "backoff after failed scale-up" 오류를 보고하면서 장애가 드러났다. 영향은 태평양 시각 02:00 에 시작됐고, 인시던트는 3시간 40분 뒤인 05:40 에 열렸다.

    조치
    • GCP 콘솔에서 해당 노드 풀을 고쳐, 자원이 남아 있던 같은 리전의 A 존과 C 존에도 노드를 만들 수 있게 했다.
    후속 조치
    • 다음 둘 중 하나를 한다. 블랙 프라이데이 행사가 끝나면 노드 풀을 다시 B 존으로만 묶거나, 클러스터와 NFS 를 A 존으로 옮긴다.
    • 리전 단위 NFS 를 쓸 수 있는 엔터프라이즈 요금제를 알아본다. 비용은 더 든다.
    • PagerDuty 알림이 언제나 엔지니어에게 닿도록 한다.
    교훈

    엔지니어 한 명이 인시던트 지휘, 공지, 디버깅을 오랫동안 혼자 맡았다. 팀이 함께 나서서 이 엔지니어를 더 많이 도울 수 있었다. 호출 알림이 대응 엔지니어에게 닿지 않아 이 문제가 더 커졌다. "backoff after failed scale-up" 은 보통 쿼터 문제지만 이번에는 쿼터를 올려도 소용이 없었다. 원인은 로그의 ZONE_RESOURCE_POOL_EXHAUSTED 오류에서 드러났다.

  5. 증상

    2022년 5월 10일 낮 12시 EST 에 헬스체크 시스템이 경보를 울렸다. EU 리전의 백엔드 API, 프런트엔드, 터널이 모두 내려가 있었다. 처음에는 클라이언트 쪽에서 요청이 끊겼거나, 메모리나 CPU 사용량 때문에 축출된 서버에 요청이 닿은 일시적 오류라고 생각했다. 메인 대시보드가 내려간 것을 보고 바로 대응을 시작했다.

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

    헬스체크 시스템이 서비스가 내려갔다는 첫 알림을 보냈다. 팀은 처음에 일시적 오류로 보고 자동 복구를 기대했지만, 메인 대시보드가 내려간 것을 확인하고 바로 대응을 시작했다.

    조치
    • 인증서 교체가 노드를 다시 만들지 않아 13시 20분 노드 풀을 손으로 다시 만들었다.
    • 14시 30분에는 이미 메인 클러스터의 서비스를 새로 만든 GKE 클러스터에 복제하고 있었다.
    • 16시 50분 기존 클러스터에서 쿠버네티스 Service 레코드를 지워 로드 밸런서를 새 클러스터에 붙일 수 있게 했다.
    • 17시 30분 StatefulSet 을 기존 클러스터에서 떼어 내고 모든 쓰기를 메인 디스크로 돌렸다.
    • 18시 30분 임시 ClickHouse 인스턴스의 데이터를 내보내 메인 인스턴스에 다시 넣었다.
    후속 조치
    • 디스크 데이터를 복잡하게 옮기지 않고도 클러스터 사이를 빠르게 바꿀 수 있도록 배포 매니페스트를 고쳤다.
    교훈

    기존 인프라를 살리는 작업에는 시간 상한을 정해야 한다. 장애 내내 서비스가 곧 살아날 것처럼 보였지만, 기존 클러스터를 훨씬 일찍 포기하고 새 클러스터에서 다시 시작했어야 했다. 이미 들인 노력이 아까워 살리기를 멈추지 못한 것이 판단을 늦췄다. 오래된 GKE 클러스터라면 클러스터 CA 인증서의 유효기간을 `gcloud container clusters describe <cluster name> --zone europe-north1-a --format "value(masterAuth.clusterCaCertificate)" | base64 --decode | openssl x509 -text | grep Validity -A 2` 로 확인할 수 있다.

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

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

원인별4

용량 한계2건

  1. IL-0100 노드가 파드의 CPU 요청에 비해 작아 CPU 가 포화되면서 PostHog 기능 플래그 서비스에 열흘 사이 장애가 세 번 났다.
  2. IL-0027 CoreDNS 파드가 모두 한 노드에 몰린 채 그 노드의 메모리가 고갈되자 DNS 가 응답하지 못해 아이디어스 서비스 전체가 멈췄다

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

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

클라우드 제공자 장애1건

조직
  1. IL-0096 GCP europe-west2-b 존의 자원이 바닥나 이 존 하나에 묶인 GKE 노드 풀이 늘어나지 못했고, LIS 허브의 사용자 서버가 6시간 30분 동안 뜨지 않았다.
    2i2c2022

인증서·자격 증명 만료1건

  1. IL-0113 한 번도 교체되지 않은 GKE API 서버 인증서 때문에 메인 클러스터의 컨트롤 플레인이 망가져 EU 리전의 백엔드 API, 프런트엔드, 터널이 모두 멈췄다