Incident Library
적용된 필터 구성 요소컨테이너 CPU 한도도메인쿠버네티스모두 풀기검색어 없이 필터만 적용한 목록입니다. 최근 사례부터입니다.
추천 필터 검색하면 검색어에서 찾은 분류 값이 여기에 나옵니다.

그래프

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

사례7건

7건 중 1~5번째

  1. 증상

    운영 중인 이커머스 플랫폼의 응답이 갑자기 느려졌다. 상품 조회 페이지가 특히 심했고, 사용자들에게서 "페이지가 안 열린다"는 문의가 들어왔다.

    촉발

    외부 커뮤니티인 뽐뿌에 플랫폼 링크가 담긴 게시글이 올라와 짧은 시간에 많은 사용자가 몰렸고, 이 사용자들이 상품 조회 API 를 집중적으로 호출했다.

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

    사용자에게서 "페이지가 안 열린다"는 문의가 들어와 장애를 알았다. 대시보드의 파드 상태는 정상이었고, 네임스페이스 CPU 사용량과 CPU 메트릭을 직접 보고서야 CPU 스로틀링을 확인했다.

    조치
    • HPA 의 minReplicas 를 5에서 10으로 늘렸다.
    • Deployment 의 CPU limit 을 1코어에서 2코어로 올렸다.
    후속 조치
    • CPU limit 을 무작정 높이면 노드 자원을 과하게 차지할 수 있으므로, 모니터링하면서 적정 수준으로 계속 조정한다.
    교훈

    글쓴이는 예측 가능한 이벤트성 트래픽까지는 받아낼 수 있게 설정해 뒀다고 생각했다. 그러나 외부 커뮤니티 게시글 하나로 트래픽이 폭증하자 그동안 문제없던 리소스 설정이 순식간에 병목이 됐다. CPU 스로틀링은 파드 상태와 로그에 드러나지 않아서 파드 목록이 아니라 CPU 메트릭을 봐야 찾을 수 있었다. 글쓴이는 대규모 트래픽에 미리 대비한 경험이 부족했다고 돌아보고, 트래픽 패턴이 바뀔 때의 대비와 리소스 설정을 더 고민하기로 했다.

  2. 증상

    남은 엔드포인트의 요청 비율을 EKS 쪽으로 1% 에서 25% 로 올리자 Sentry 에 DNS 이름 해석 오류가 대량으로 올라왔다. API 가 데이터베이스와 외부 서비스에 연결하지 못했다.

    촉발

    ALB 로 엔드포인트마다 요청 비율을 바꾸며 이전하던 중, 남은 엔드포인트의 요청 비율을 EKS 쪽으로 1% 에서 25% 로 올렸다.

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

    요청 비율을 EKS 쪽으로 올린 직후 Sentry 에 DNS 이름 해석 오류가 대량으로 올라온 것을 확인했다.

    조치
    • 오류를 멈추려고 요청 비율을 VM 쪽으로 되돌렸다.
    • 임시 조치로 HPA 리소스를 만들어 CoreDNS 파드를 오토스케일하게 했고, 그 뒤 EKS 이전을 마쳤다.
    후속 조치
    • 애플리케이션 Deployment 의 dnsConfig 에 ndots 값 "1" 을 넣어 파드가 항상 FQDN 으로 이름을 해석하게 했다.
    • CoreDNS ConfigMap 의 Corefile 에서 cache 를 600 으로 바꿔 캐시 TTL 을 늘렸다.
    • CoreDNS ConfigMap 의 health 플러그인에 lameduck 30s 를 넣어, 스케일인 때 파드가 바로 끝나지 않고 남은 처리를 이어 가게 했다.
    • 운영 환경과 스테이징 환경의 차이를 줄이는 것을 비용과 균형을 보며 검토한다.
    교훈

    MonotaRO 는 관리형 서비스이니 문제가 없으리라 짐작하고 사전 사례 조사, 부하 시험, 감시 같은 측정을 하지 않아 이번 문제가 났다고 보았다. 그래서 짐작하지 말고 측정하라는 원칙을 다시 새겼다. 운영 환경과 스테이징 환경의 차이가 컸다. 네트워크 구성이 달라 환경마다 ndots 가 달랐고, 스테이징 환경의 데이터베이스 사양으로는 고부하 시험을 할 수 없었다. 직접 관리하지 않는 부분의 리소스도 잘 알지 못했다. 쿠버네티스로 옮긴 다른 회사의 사례를 조사했다면 이번 문제를 어느 정도 예측할 수 있었다고 했다.

  3. 증상

    자체 호스팅한 Temporal Server 의 History 서비스에서 요청 지연이 일정하지 않았다. 대시보드에서 history 파드의 CPU 사용률은 60% 아래로 나왔지만 파드는 CPU 스로틀링을 받고 있었다.

    촉발

    노드는 8코어였고 history 파드의 CPU 한도는 2코어였는데, Go 로 작성된 Temporal Server 는 GOMAXPROCS 기본값대로 노드의 코어 8개를 모두 쓸 수 있다고 보고 동작했다.

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

    kube-prometheus 대시보드에서 history 파드의 CPU 사용률은 60% 아래였지만 스로틀링 비율은 0보다 컸다. 15초 이상 간격으로 수집하는 CPU 사용률 지표로는 0.1초 단위로 일어나는 스로틀링이 보이지 않으므로, 스로틀링 지표를 따로 보고서야 문제를 찾았다.

    조치
    • history 파드 배포에 GOMAXPROCS 환경 변수를 CPU 한도와 같은 2로 설정했다.
    후속 조치
    • Temporal 1.21.0 부터는 CPU 한도가 있고 GOMAXPROCS 환경 변수가 따로 설정되지 않았으면 서버가 GOMAXPROCS 를 CPU 한도에 맞춰 자동으로 설정한다.
    교훈

    CPU 사용률이 낮게 나와도 스로틀링은 일어날 수 있으므로 스로틀링 지표를 따로 관찰해야 한다. Go 서비스에서는 GOMAXPROCS 를 CPU 한도의 정수 코어 수에 맞춘다. GOMAXPROCS 는 CPU 요청값으로는 자동 설정되지 않으므로, CPU 한도를 쓰지 않는다면 CPU 요청값과 같거나 조금 큰 값으로 직접 설정한다. 가능하면 CPU 한도를 쓰지 말고 CPU 요청값을 적절히 잡은 뒤 노드 CPU 사용량을 지켜본다. 노드 CPU 가 자주 바닥나면 파드가 요청값을 넘어 자주 버스트한다는 뜻이므로 요청값을 다시 잡는다.

  4. 증상

    DevOps 팀이 아직 운영 트래픽을 받지 않는 notification-preferences 마이크로서비스의 `resources.requests.cpu` 를 2에서 1로 줄였다. 작업을 마치고 몇 분 뒤 메모리 사용량이 90% 를 넘었다는 경보가 왔다. 메모리 할당량이나 JVM 의 GC 관련 인자는 건드리지 않은 상태였다.

    촉발

    리소스 최적화 작업 중 notification-preferences 디플로이먼트의 `resources.requests.cpu` 를 2에서 1로 줄였다. CPU limit 은 설정하지 않은 상태였다.

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

    CPU requests 를 줄이고 몇 분 뒤 메모리 사용량이 90% 를 넘었다는 경보가 울렸다.

    조치
    • JVM 옵션에 `-XX:ActiveProcessorCount=1` 을 넣어 JVM 이 쓸 CPU 수를 강제로 지정했다. 자원을 다시 늘리거나, CPU limit 을 걸거나, requests 를 1001m 이나 999m 으로 두는 방법은 각각 문제가 있어 고르지 않았다.
    후속 조치
    • 이 문제를 사내 공지로 알렸다.
    교훈

    cgroup v1 환경에서 JVM 은 `cpu.shares` 값이 정확히 1024 일 때 이를 설정 없음으로 보고 노드의 CPU 수를 쓴다. CPU limit 없이 requests 만 1로 준 JVM 파드는 노드가 클수록 스레드를 많이 띄우고 메모리를 더 쓴다. 이 문제는 쓸 수 있는 CPU 수로 스레드 수를 정하는 WebFlux 같은 프레임워크에서 특히 크게 드러난다. 이런 설정이라면 `-XX:ActiveProcessorCount` 나 CPU limit 으로 CPU 수를 명시해야 한다. Hyperconnect 는 원래 운영 JVM 애플리케이션에 CPU requests 를 2 이상 주었고, 마이크로서비스가 늘어 자원을 아끼려다 이 문제를 만났다.

  5. 증상

    2022년 4월 11일 13:17 UTC 에 고객과 Gitpod 직원들이 워크스페이스가 간헐적으로 응답하지 않는다고 알렸다. 4월 8일과 9일에 새 세대 워크스페이스 클러스터 ws39 를 모든 리전에 배포한 직후였다.

    촉발

    2022년 4월 8일과 9일에 새 세대 워크스페이스 클러스터 ws39 를 모든 리전에 배포한 것이 시작이었다.

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

    2022년 4월 11일 13:17 UTC 에 고객과 Gitpod 직원들의 신고로 알았고, incident.io 연동으로 Slack 에 장애를 열었다. 4월 12일에도 고객과 직원의 신고로 알았고, 4월 17일에는 엔지니어들이 워크스페이스 노드의 CPU 부하가 오른 것을 보고 내부 장애를 열었다.

    조치
    • IO 제한 기능이 없어 워크스페이스 시작 트래픽을 이전 세대 클러스터 ws38 로 돌렸고, 4월 11일 15:37 UTC 에 마쳤다.
    • t2d 대신 더 빠른 c2d 머신 유형과 로컬 SSD 를 쓰는 새 클러스터 ws39a 를 만들어 트래픽을 옮겼다.
    • Let's Encrypt 속도 제한 문제를 풀고, Let's Encrypt 에 한도를 올려 달라고 요청했다.
    • ws38 클러스터를 쓸 수 없어 EU XL 트래픽을 임시로 리전 EU 클러스터로 보내 워크스페이스를 다시 시작할 수 있게 했다. 그리고 망가진 ws-eu39xl 을 대신할 ws-eu39bxl 클러스터를 새로 만들었다.
    • stopping 상태에 걸린 워크스페이스를 정리해 사용자가 다시 시작할 수 있게 했다.
    • 4월 8일 배포 전처럼 1TB 부트 디스크를 단 노드로 ws40 을 만들어 디스크 IO 대역폭을 늘렸다.
    • 모니터링으로 노드의 작업을 직접 살펴 과도한 CPU 시간을 쓰는 워크스페이스를 찾아 시스템에서 지웠다.
    • 노드를 손으로 뒤지고 채굴 탐지 시스템을 함께 써서 부정 사용자를 찾아 Gitpod 사용을 막았다.
    • ws38 세대에는 없던 ws-daemon 변경을 되돌려 CPU 제한을 다시 안정시켰고, 이 수정을 ws34 클러스터에 담아 배포했다.
    • 새 ws34 배포에서 워크스페이스 포트로 가는 ACME HTTP 요청을 막아 Let's Encrypt 한도에 다시 걸리지 않게 했다.
    • 워크스페이스 사이에 디스크 IO 를 공정하게 나누는 ws41xl 클러스터와 일반 리전용 ws41 클러스터를 만들어 트래픽을 단계적으로 옮겼다.
    후속 조치
    • 테스트 결과가 진행하면 안 되는 배포를 미리 걸러 내도록 테스트 자동화에 계속 투자한다.
    • 새 클러스터로 트래픽 비율을 옮기는 간격을 배포마다 다르게 하고, 큰 배포일수록 단계 사이를 길게 둔다.
    • 워크스페이스 클러스터 배포에 위험 평가 단계를 넣어 변경 묶음의 크기와 배포 속도를 정하고, 이 단계를 자동화하는 것을 목표로 한다.
    • 팀 사이 의존이 롤백을 막지 않도록 팀끼리 주는 영향을 계속 줄인다.
    • PR 을 머지하기 전에 하위 호환이 깨지는 변경을 찾는 리뷰 기준을 더하고, 그런 PR 은 나눠서 배포를 롤백하기 어려운 상황을 피한다.
    • 장애 완화의 첫 수단으로 롤백을 권하도록 절차를 고쳤고, 이 과정을 자동화하는 방법을 논의한다.
    • 상태 페이지의 워크스페이스 서비스가 장애를 주황이나 빨강으로 제대로 표시하도록 고쳤고, 플레이북도 그에 맞게 고쳤다.
    • 장애 중 내부 소통을 Slack 채널 하나와 Google Meet 하나로 모으고, 장애 절차를 그에 맞게 고쳤다.
    • 당번 체계를 다시 짜서 5월 9일부터 엔지니어링 인력의 10% 가 늘 당번을 맡고, 그 시간으로 관측성과 알림과 시스템 안정성을 개선한다.
    교훈

    4월 11일에 롤백을 결정했다면 가장 좋았다. 롤백하지 않고 수정을 계속 만들어 배포하면서 고객은 필요 이상으로 오래 성능 저하를 겪었고 일부는 데이터를 잃었다. 규모가 크고 바로 앞 배포와 가까운 변경을 너무 빨리 내보냈고, 테스트 결과가 배포를 막았어야 했다. 배포 묶음을 작게 하고 배포를 자주 한다는 원칙을 ws39 에서 지키지 못했고, 팀 사이 의존이 롤백을 어렵게 만들었다. 기여 요인 가운데 일부는 막을 수 있었다.

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

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

원인별3

용량 한계3건

  1. IL-0181 외부 커뮤니티 게시글로 트래픽이 몰려 상품 API 파드가 CPU limit 1코어에서 스로틀링되면서 상품 조회 페이지가 매우 느려졌다
    Kevin2026
  2. IL-0433 EC2 에서 EKS on Fargate 로 트래픽을 옮기던 중 CoreDNS 과부하로 이름 해석 오류가 쏟아져 롤백했다
  3. IL-0028 쿠버네티스에서 Temporal History 파드가 CPU 사용률이 60% 아래인데도 CPU 스로틀링을 받아 요청 지연이 불안정했다

소프트웨어 결함3건

  1. IL-0175 JVM 파드의 CPU requests 를 1코어로 줄이자 JVM 이 노드의 CPU 36개를 인식해 Reactor Netty 스레드가 늘고 메모리 사용량이 경보 기준을 넘었다
  2. IL-0029 CPU 한도를 건 컨테이너가 사용량이 한도에 한참 못 미치는데도 스로틀링되어 사용자 대면 서비스의 지연 시간이 늘었다.
    Buffer2020
  3. IL-0012 CPU limit 과 커널 CFS 쿼터 버그로 파드가 과하게 스로틀링돼 헬스 체크가 실패하고 애플리케이션이 멈췄다
    Omio2020

배포 결함1건

조직
  1. IL-0591 Gitpod 워크스페이스가 새 클러스터 세대 배포 뒤 열흘 넘게 모든 리전에서 느려지고 시작 실패와 데이터 유실이 났다
    Gitpod2022