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

사례4건

4건 중 1~4번째

  1. 증상

    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 오류에서 드러났다.

  2. 증상

    2021-06-21 08:05 UTC 부터 API 의 Apdex 가 나빠지고 Rails 대기열이 늘어나는 추세가 보였다. Apdex 는 목표 시간 안에 끝난 요청의 비율로 사용자 만족도를 나타내는 지표다. 08:43 에 ahmad 가 Slack 에서 장애를 선언했고, 09:01 에 API 디플로이먼트가 비정상 상태이고, 노드를 늘려 파드 용량을 더할 수도 없다는 것을 확인했다.

    촉발

    GitLab 이 운영하는 GCP us-east1 리전에서 SSD 재고가 바닥난 상태였는데, 사용자 트래픽이 늘어 API 서비스가 노드를 늘려야 했다.

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

    로그를 한참 뒤져서 찾았다. 클러스터 오토스케일러 오류는 일부 노드가 백오프 상태라 확장할 수 없다고만 했고, 인스턴스 그룹 수준 오류도 ZONE_RESOURCE_POOL_EXHAUSTED 뿐이어서 어떤 자원이 바닥났는지 알 수 없었다. 결국 GCP 지원팀이 SSD 재고 부족을 알려 주었다. 탐지까지 22시간이 걸렸고, 팀은 자원 가용성 알림이 있었다면 탐지와 진단을 앞당길 수 있었다고 보았다.

    조치
    • 09:55 에 pd-standard 디스크를 쓰는 노드 풀을 하나 더 만들었다.
    • 10:37 에 새 노드 풀이 늘어나지 않자 API 부담을 덜려고 이 노드 풀을 세 존 모두에서 손으로 늘렸다.
    • 13:42 에 배포가 막혀 있고 다른 워크로드도 같은 영향을 받고 있어서 pd-standard 디스크를 쓰는 새 노드 풀들을 올리기로 했다.
    • 18:16 에 canary 시험에서 클러스터 오토스케일러가 새 노드 풀과 함께 동작하지 않자 프로덕션 배포를 막는다고 공지하고, 오토스케일러 문제로 Google 에 지원 케이스를 열었다.
    • 18:26 에 남은 워크로드의 노드 풀과 nodeSelector 를 바꾸는 인프라 작업을 시작했다.
    • pd-standard 노드 풀 위주로 하루 동안 운영하며 문제가 없는 것을 확인한 뒤 SSD 노드 풀을 정리해 없앴다.
    후속 조치
    • 쿠버네티스 서비스를 pd-standard 디스크로 옮겼다.
    • 자원 고갈 오류를 지표로 수집한다.
    교훈

    장애를 수습하는 도중 다른 버그를 만나 대응 전체가 느려졌다. 팀에는 클라우드 자원 가용성을 감시할 수단도, 자원을 미리 예약해 둘 수단도 없었다. 워크로드는 pd-ssd 대신 pd-standard 디스크에서도 문제없이 도는 것으로 보였다.

  3. 증상

    Metrictank 인스턴스 일부가 쓰기 큐를 비우지 못한다는 알림이 왔다. Metrictank 가 Cassandra 에 쓰지 못하고 있다는 뜻이었다.

    촉발

    GCP SSD 영구 디스크의 성능이 크게 떨어져 많은 I/O 가 오랫동안 실패했고, 그 때문에 노드가 자동으로 재부팅됐다.

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

    팀은 Metrictank 쓰기 인스턴스가 쓰기 큐를 비우지 못한다는 알림을 받고 장애를 알았다. Metrictank 가 대부분의 쿼리를 메모리에서 계속 처리해서 오류율은 아주 천천히 올라갔기 때문에, 이 알림이 없었다면 발견이 훨씬 늦었을 것이다.

    조치
    • 새 노드라면 디스크를 붙일 수 있을 것이라 보고 클러스터의 컴퓨트 노드를 늘렸지만 효과가 없었다.
    • GCP 장애가 풀린 뒤 Cassandra StatefulSet 을 지우고 Pod Management Policy 를 바꿔 다시 만들었다. 파드 하나를 빼고 모두 떠서 Cassandra 클러스터가 정상으로 돌아왔다.
    • 긴 장애 동안 데이터를 잃지 않도록 Kafka 토픽 보존 기간을 늘렸다.
    • Metrictank 재시작이 CPU 부족으로 느려지지 않도록 클러스터에 노드를 임시로 더 붙였다.
    • 모든 Metrictank 인스턴스를 재시작해 새 Cassandra IP 로 연결되게 했다. 재시작은 20시간 넘게 걸렸다.
    후속 조치
    • 모든 Cassandra IP 가 바뀌면 Metrictank 가 다시 연결하지 못하는 버그를 고쳤다. 연결이 죽은 것을 감지하면 gocql 연결을 새로 만든다.
    • 쓰기 큐가 가득 찬 상태에서 새 데이터가 들어오면 생기던 교착을 고쳤다. 내부 자료 구조 하나를 잠금으로 보호하는 대신 atomic 연산으로 갱신한다.
    교훈

    받은 데이터를 처리하기 전에 쓰기 선행 로그인 Kafka 에 먼저 저장해 둔 덕분에, Cassandra 를 되살린 뒤 그동안 받은 데이터를 모두 처리해 저장할 수 있었다. Kafka 가 SSD 가 아닌 디스크를 쓴 것은 운이 좋았다. 그렇지 않았다면 Kafka 도 Cassandra 와 같은 장애를 겪었을 수 있다. 23시간 동안 파라과이, 알바니아, 호주에 있는 세 사람이 시간대를 나눠 대응했다. 두 버그를 고친 지금은 같은 상황이 와도 복구가 23시간이 아니라 3시간 안에 끝날 것으로 본다. 오래 미룬 문제도 새로 보면 생각보다 간단히 풀릴 수 있다. 장애가 주말에 나서 고객 부하가 대부분 캐시 데이터를 읽는 알림 쿼리뿐이었던 것도 운이 좋았다.

  4. 증상

    미뤄 둔 GKE 업그레이드를 하던 저녁, 마스터는 문제없이 올라갔지만 노드 풀 업그레이드가 예상보다 훨씬 오래 걸렸다. 노드가 14개이고 노드당 5분쯤 걸리는 클러스터도 한 시간 넘게 걸렸고, 일부 노드는 드레인에 15분 넘게 걸렸다. emptyDir 를 쓰는 파드와 5분에서 10분짜리 terminationGracePeriodSeconds 가 드레인을 늦췄다.

    촉발

    마이그레이션에 쫓겨 미뤄 둔 업그레이드로 운영 클러스터를 1.10.X 에서 1.12.5-gke.10 으로 올렸다. 구글은 3월 14일 GKE 릴리스 노트에서, 이 버전으로 올린 마스터의 오류율이 높아진다는 보고가 있어 새 클러스터와 마스터 업그레이드에서 이 버전을 빼는 중이라고 밝혔다. 그런데도 3월 19일에 이 버전을 고를 수 있었다.

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

    업그레이드하던 엔지니어가 드레인이 느리고 노드 풀 업그레이드가 멈추고 파드가 Pending 에 머무는 것을 직접 보았다. 인그레스 장애는 업그레이드 뒤에 드러났고, 로그로 원인을 찾지 못해 구글 지원팀에 물어 알려진 버그라는 것을 알았다. HPA 이상은 업그레이드 다음 날 발견했다.

    조치
    • 노드 풀의 노드 목록을 뽑아 kubectl drain 에 --ignore-daemonsets --delete-local-data 를 주어 노드를 미리 드레인했다.
    • 노드 풀에 해당하는 관리형 인스턴스 그룹을 찾아 gcloud compute instance-groups managed delete-instances 로 멈춘 인스턴스를 지웠다.
    • gcloud container operations list 로 operationType: UPGRADE_NODES, status: RUNNING 인 작업을 찾아 gcloud beta container operations cancel 로 멈춘 노드 풀 업그레이드를 취소했다.
    • 동작을 멈춘 내부 인그레스 대신 한동안 port-forward 로 접근했다.
    • HPA 가 이상해진 배포에서 활성 레플리카셋이 두 개면 오래된 레플리카셋을 천천히 줄였고, 하나면 더미 환경 변수를 바꿔 다시 배포했다.
    후속 조치
    • HorizontalPodAutoscaler 가 최대치의 70% 와 100% 에 닿으면 Alertmanager, Prometheus, Slack 으로 경보를 보내게 했다.
    • 배포에 활성 레플리카셋 두 개가 30분 동안 남아 있을 때와 60분 동안 남아 있을 때 경보를 보내게 했다.
    • 임의로 크게 잡은 종료 유예 시간을 다시 따져 본다.
    • 클러스터를 업그레이드하기 전에 GKE 릴리스 노트를 먼저 확인한다.
    • 운영이 아닌 환경에는 자동 업그레이드를 쓰고, 운영 환경은 클러스터를 수동으로 업그레이드하고 노드는 자동 업그레이드를 쓴다.
    • 사전 검증 환경을 이름까지 운영과 최대한 똑같이 맞춘다.
    교훈

    클러스터를 업그레이드하기 전에는 GKE 릴리스 노트를 먼저 봐야 한다. 운영이 아닌 환경에는 자동 업그레이드를 써서 영향을 먼저 겪고, 운영에는 수동 클러스터 업그레이드와 자동 노드 업그레이드를 섞어 예측 가능성과 유지 부담 사이에서 균형을 잡는다. 사전 검증 환경은 이름까지 운영과 같게 둬야 한다. 노드 풀 업그레이드 시간은 노드 수와 드레인 시간에 달려 있다. emptyDir 를 쓰는 파드에 safe-to-evict 어노테이션을 달고, 지나치게 긴 종료 유예 시간을 다시 따져 보고, PodDisruptionBudget 을 두면 드레인이 빨라진다.

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

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

원인별1