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

사례24건

24건 중 14~18번째

  1. 증상

    2022-04-25 15:13 UTC 에 engwan 이 Slack 에서 Sidekiq Apdex 하락으로 장애를 선언했다. Apdex 는 목표 시간 안에 끝난 작업의 비율로 만족도를 나타내는 지표다. 사용자는 사이트가 간헐적으로 느려지는 것을 겪었고, 파이프라인 생성이나 가져오기와 내보내기 같은 비동기 작업이 평소보다 오래 걸렸다.

    촉발

    GKE 파드 안의 Consul 에이전트가 특정 상황에서 메모리를 갑자기 많이 요구했고, 쓸 수 있는 메모리가 없어 Consul 프로세스가 죽었다. 당시 파드 메모리 한도는 500MB 였다.

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

    2022-04-25 15:13 UTC 에 engwan 이 Slack 에서 Sidekiq Apdex 하락으로 장애를 선언했다. 다음 날 01:21 UTC 에는 모니터링이 오류율 상승을 잡았고, 01:26 에 cindy 가 장애를 다시 선언했다.

    조치
    • 16:13 에 gitlab 데이터베이스 사용자의 연결 한도를 올리고 main pgbouncer 의 백엔드 풀을 늘리는 방안을 세웠고, 17:26 에 msmiley 가 변경을 적용해 17:47 에 적용을 확인했다.
    • 임시 조치로 파드 메모리 한도를 500MB 에서 1GB 로 올려 Consul 에이전트가 메모리 급증 때도 계속 돌 수 있게 했다.
    후속 조치
    • 메모리 한도를 1GB 로 올린 것으로 충분한지 GKE 파드의 Consul 에이전트를 지켜본다.
    • Consul 의 메모리 수요 급증을 조사해 하드 메모리 한도를 올리는 것 말고 개선할 방법이 있는지 찾는다.
    교훈

    파드 안에서 함께 도는 Consul 에이전트의 메모리 한도가 모자라자 서비스 디스커버리가 끊겼고, 그 영향이 데이터베이스 primary 포화와 사이트 전체의 지연으로 번졌다. 처음 의심한 pgbouncer 풀 변경과 다음 날 별개로 보였던 오류율 상승이 모두 같은 원인으로 이어졌다. 메모리 한도를 올린 것은 임시 조치였고, Consul 의 메모리 급증이 정상 동작인지 GitLab 설정 탓인지는 아직 조사해야 했다.

  2. 증상

    2021년 9월부터 메트릭 질의 서비스의 업데이트를 롤아웃할 때마다 오류가 늘었다. 서비스 로그에는 DNS 오류 때문에 메트릭 데이터 저장소에 연결하지 못했다는 내용이 찍혔다. 클라이언트가 실패한 질의를 자동으로 재시도해 사용자에게 보이는 오류는 적었지만, 재시도 때문에 대시보드와 모니터의 지연이 늘었다.

    촉발

    2021년 8월 메트릭 질의 클라이언트의 업데이트를 롤아웃하면서 새 기본값인 gRPC round_robin 부하 분산 정책이 처음 적용됐다. round_robin 은 끊긴 채널을 자동으로 다시 연결하는데, 오래전에 넣어 둔 매우 공격적인 gRPC 재연결 타임아웃과 겹쳐 서비스 롤아웃 때마다 사라진 파드 IP 로 SYN 이 쏟아졌다.

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

    2021년 9월부터 메트릭 질의 서비스 롤아웃 때 오류가 늘어나는 것을 보았고, 서비스 로그에서 DNS 오류가 데이터 저장소 연결을 막는 것을 확인했다.

    조치
    • node-local-dns 파드의 메모리를 64 MB 에서 256 MB 로 올렸다. OOM 오류는 멈췄지만 DNS 오류는 계속됐다.
    • AWS 가 더 많은 연결을 추적할 수 있다고 한 더 큰 인스턴스 유형으로 서비스 인프라를 올려 보았고, 그것만으로 문제가 사라지는 것을 확인했다.
    • SYN 폭주를 일으킨 사용자 지정 gRPC 재연결 파라미터를 지우고 기본값으로 되돌리는 PR 을 만들었다. 다음 롤아웃에서는 오류가 나지 않았다.
    후속 조치
    • Cilium 프로젝트에 PR 을 기여한다. 이 PR 은 옛 파드 IP 에 unreachable 경로를 더해, 지워진 파드로 가는 요청이 martian 패킷이 되지 않게 한다. 그러면 역경로 필터가 SYN 을 버리지 않고, 클라이언트는 분명한 ICMP 오류를 받는다.
    교훈

    gRPC, 쿠버네티스, AWS 같은 강력한 추상화도 엣지 케이스에서는 평소에 숨어 있던 복잡함이 오류로 드러난다. 몇 달을 조사한 끝에, 이번 장애의 뿌리가 팀이 직접 한 변경에 있다는 것을 찾았다. 의존성의 버그를 피해 가려던 변경, 이전 장애를 고치려던 변경, 기본 재연결 파라미터를 덮어쓴 변경이었다. 이 변경들은 당시에는 안전해 보였지만 한참 뒤에 상관관계를 찾기 어려운 때에 뜻밖의 결과를 냈다. DNS 문제처럼 보여도 DNS 문제가 아닐 때가 있다. AWS ENA 지표와 VPC Flow Logs 는 연결 추적을 들여다보는 데 중요하다. DNS 전파 시간은 여러 요인에 좌우된다.

  3. 증상

    2020년 7월 13일 08:18 UTC 에 운영 쿠버네티스 클러스터의 파드들이 사용 불가로 표시되기 시작했다. 이 상태가 클러스터 전체로 번지면서 처리 용량이 줄었고, 결국 GitHub.com 서비스가 내려갔다.

    촉발

    파드 안에서 운영에 필요하지 않은 컨테이너 하나가 메모리 한도를 넘어 종료됐다. 앞서 끝난 정기 DNS 유지보수 작업 때문에 클러스터는 이미지 레지스트리에 접속하지 못하는 상태였다.

    원인
    구성 요소
    기여 요인
    조치
    • 캐시된 DNS 레코드로 프로세스를 다시 시작해 레지스트리에서 컨테이너 이미지를 받아 올 수 있게 했다.
    • 이미지를 받아 온 뒤 다시 배포해 서비스를 복구했다.
    후속 조치
    • 같은 패턴으로 파드 재시작이 다시 실패하지 않도록 모니터링을 강화한다.
    • 이미지 레지스트리 의존도를 줄인다.
    • DNS 를 바꿀 때 검증 범위를 넓힌다.
    • 기존 쿠버네티스 배포 정책을 모두 다시 검토한다.
    • 배포 영향을 조금씩 확인하며 내보낼 수 있도록 점진 배포 방식을 개선한다.
    교훈

    운영에 필요 없는 보조 컨테이너 하나도 파드 전체를 사용 불가로 만들 수 있다. ImagePullPolicy 가 Always 이면 재시작마다 레지스트리에 기대게 되므로, 레지스트리나 DNS 가 흔들릴 때 평소에는 1분이면 끝날 재시작이 긴 장애로 바뀐다. 수습하려고 재배포하면 같은 실패를 전체 클러스터로 퍼뜨릴 수 있다.

  4. 증상

    어느 월요일 아침, 엔지니어가 쿠버네티스 클러스터 경고를 보려고 Prometheus 대시보드를 열었는데 접속되지 않았다. Prometheus 서버 파드는 CrashLoopBackOff 상태였다.

    촉발

    Prometheus 가 시작한 지 5분 만에 시계열 수가 2,162,256 까지 급증해 메모리 8GB 호스트의 메모리를 거의 다 썼다.

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

    월요일 아침 엔지니어가 클러스터 경고를 확인하려고 Prometheus 대시보드를 열었다가 접속되지 않는 것을 보고 알았다.

    조치
    • Prometheus configMap 에서 불필요한 설정 대부분을 지워 컨테이너가 더 이상 비정상 종료되지 않게 했다.
    후속 조치
    • Prometheus 파드의 requests 와 limits 를 알맞게 고친다. 지금 문제를 완전히 풀지는 못해도 비슷한 문제를 막아 해결 시간을 줄인다.
    • 불필요한 수집 지표를 줄이도록 수집 대상이나 수집 간격을 조정한다.
    • Prometheus 에 필요한 메모리를 예측해 새 호스트를 마련하고 deploy-topology: Prometheus 같은 노드 레이블을 붙인 뒤, 매니페스트에 nodeSelector 를 넣어 Prometheus 파드가 그 호스트에만 배치되게 한다.
    교훈

    원인은 둘이었다. 첫째, Prometheus 파드의 requests 와 limits 를 잘못 잡아 Prometheus 서버 컨테이너가 높은 oom_score_adj 를 받았다. 둘째, 대규모 클러스터에서 Prometheus 가 쓸 메모리를 미리 예측하지 않았다. 쿠버네티스에서 파드의 QoS 클래스는 메모리가 모자랄 때 어느 컨테이너가 먼저 죽는지에 영향을 준다. 커널의 OOM Killer 는 메모리 사용량과 oom_score_adj 로 점수를 매기고, kubelet 은 QoS 클래스에 따라 oom_score_adj 를 정한다.

  5. 증상

    2019년 7월 19일 금요일, Grafana Cloud 의 Hosted Prometheus 서비스가 장애를 겪었다. 오류 예산 기반 Prometheus 알림이 장애 시작 4분 안에 당직자를 호출했다.

    촉발

    7월 19일 한 엔지니어가 큰 고객을 위한 전용 Cortex 클러스터를 새로 띄웠다. 새 클러스터 설정에는 새로 도입한 파드 우선순위 지정이 없어서, 모든 파드가 기본값인 medium 우선순위를 받았다. 쿠버네티스 클러스터에는 새 Cortex 클러스터를 올릴 자원이 부족했다.

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

    새로 도입한 오류 예산 기반 Prometheus 알림이 장애 시작 4분 안에 당직자를 호출했다.

    조치
    • 쿠버네티스 클러스터를 늘려 새 Cortex 클러스터와 기존 운영 Cortex 클러스터가 모두 들어가게 했다.
    • Cortex 앞의 인증 리버스 프록시에서 난 OOM 을 찾아 고쳤다.
    후속 조치
    • 운영 Ingester 에 high 우선순위 지정을 반영했다.
    • 클러스터 전역 설정처럼 네임스페이스 밖에 있는 객체의 배포는 더 많은 사람이 리뷰한다.
    • 네임스페이스 밖 설정 변경에는 모두 설계 문서를 요구한다.
    • 인증 리버스 프록시의 규모 조정을 자동화해 과부하 때 OOM 이 나지 않게 한다.
    • 한꺼번에 몰려드는 재시도를 막으려고 Prometheus 의 기본 백오프와 확장 동작을 조사한다.
    교훈

    운영 Ingester 에 high 우선순위를 지정하기 전에 medium 을 기본 우선순위로 만들지 말았어야 했다. 운영 Ingester 의 high 지정도 더 일찍 배포했어야 했다. 팀은 이 변경이 설계 문서를 쓸 만큼 크지 않다고 보고 GitHub 이슈에서만 논의했다. 좋은 점도 있었다. Cortex 는 자원이 충분해지자 추가 조치 없이 스스로 회복했다. 팀은 새 로그 수집 시스템인 Grafana Loki 로 Ingester 가 정상적으로 종료됐는지 확인했다.

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

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

원인별5

용량 한계15건

  1. IL-0102 배포와 워커 오토스케일링 폭주가 겹치자 크기를 고정해 둔 CoreDNS 가 메모리 한도를 넘겨 재시작된 뒤 회복하지 못했고, Buildkite 사이트 전체가 약 30분 멈췄다.
  2. IL-0548 EKS 의 Prometheus 가 거듭 죽으며 Buildkite 의 알림 전달과 빌드 디스패치가 지연됐다
  3. IL-0027 CoreDNS 파드가 모두 한 노드에 몰린 채 그 노드의 메모리가 고갈되자 DNS 가 응답하지 못해 아이디어스 서비스 전체가 멈췄다
  4. IL-0044 kube-prometheus-stack 업그레이드 뒤 Prometheus 가 WAL 재생 중 메모리를 50Gi 넘게 써서 시작할 때마다 OOMKilled 로 죽었다
  5. IL-0110 Grafana Agent 파드가 메모리를 많이 쓰던 노드에 Hangfire 파드가 함께 올라가 시스템 OOM 으로 CrashLoopBackOff 를 반복했고, 노드가 응답을 멈추고 NotReady 가 됐다.
    DFDS2024
  6. IL-0168 새 쿠버네티스 릴리스 뒤 많은 Kapsule 클러스터가 동시에 자동 업그레이드되면서 Kubernetes API 가 과부하로 OOM 이 났고, 새 노드 인증 방식의 재시도가 혼잡을 키워 노드가 Not Ready 가 됐다.
  7. IL-0169 FR-PAR 의 Scaleway Kubernetes API 가 메모리 부족으로 쓰러져 노드 인증이 막히고 Kapsule 노드가 NotReady 가 됐다.
  8. IL-0016 네임스페이스와 규칙이 늘어 live 클러스터의 Prometheus 가 메모리 부족으로 OOMKilled 되며 플랫폼 모니터링이 끊겼다
  9. IL-0195 200개가 넘는 노드의 고객 클러스터에서 Cilium 파드가 LIST 요청을 한꺼번에 쏟아내 kube-apiserver 가 메모리를 다 쓰고 죽기를 되풀이했다.
    Palark2023
  10. IL-0206 GKE 파드 안의 Consul 에이전트가 메모리 급증으로 거듭 OOM kill 되어 Rails 파드가 데이터베이스 복제본을 찾지 못했고, 모든 쿼리가 primary 로 몰려 GitLab.com 이 느려졌다.
    GitLab2022
  11. IL-0176 시계열 급증으로 호스트 메모리가 바닥나자 oom_score_adj 999 를 받은 Prometheus 컨테이너가 커널 OOM Killer 에게 먼저 죽어 CrashLoopBackOff 에 빠졌다.
    LINE2020
  12. IL-0026 메모리 제한이 없는 fluentd-sumologic 파드가 메모리를 다 써서 운영 쿠버네티스 노드 두 대에 이틀 연속 SystemOOM 이 났다
  13. IL-0001 CoreDNS 파드가 메모리 한도 100Mi 에 걸려 OOM 으로 계속 죽으면서 쿠버네티스 클러스터 전체의 DNS 가 멈췄다
  14. IL-0031 API 서버가 OOMKill로 죽자 Skipper 인그레스가 라우트를 잃었고, 고객 트래픽이 끊기며 IAM 서비스에서 404 오류가 났다
  15. IL-0503 GKE 노드의 메모리가 바닥나 mybinder.org 의 proxy 파드가 OOM 으로 죽고 새 서버 실행이 실패했다

설정 변경5건

  1. IL-0063 Redis 스테이트풀셋을 다시 만들자 Redis 클러스터가 한꺼번에 재시작되며 일부가 망가졌고, 재연결 폭주로 백엔드가 OOM 으로 죽어 AdGuard VPN 이 약 50분 멈췄다.
  2. IL-0191 Loki distributor 서비스에 레이블 셀렉터가 하나 더 들어가 롤아웃 중 새 파드 몇 개에만 쓰기 트래픽이 몰렸고, 그 파드들이 OOM으로 죽으면서 로그 쓰기 경로가 약 25분간 멈췄다.
  3. IL-0461 메트릭 질의 서비스를 롤아웃할 때마다 DNS 오류가 나며 질의가 실패했다
  4. IL-0004 새 Cortex 클러스터에서 기본 우선순위를 받은 파드가 우선순위가 없는 운영 Ingester 를 연쇄적으로 선점해 Hosted Prometheus 쓰기가 실패했다
  5. IL-0035 ElastAlert 에 새로 넣은 알림 규칙 때문에 ElastAlert 파드가 메모리를 끝없이 써서 노드가 잇달아 NotReady 가 되었고, 같은 클러스터의 도구와 Grafana, Prometheus 가 함께 흔들렸다.
    NU.nl2019

소프트웨어 결함2건

  1. IL-0104 Istio 의 공격적인 DNS 캐시 갱신과 클라이언트 포트 재사용, kube-proxy 가 종료된 파드의 conntrack 항목을 정리하지 않는 문제, 2분짜리 UDP conntrack 기본 타임아웃이 겹쳐 CoreDNS 파드가 OOMKilled 됐다.
  2. IL-0011 HAProxy 인그레스 템플릿이 백엔드 파드를 IP 순으로 정렬해 일부 파드에 요청이 몰리고 인그레스 컨테이너가 OOMKilled 됐다

배포 결함1건

  1. IL-0530 us-central1 의 가상 네트워크 라우터 컨트롤러가 메모리 부족으로 재시작을 되풀이해 새 VM 과 마이그레이션된 VM 의 네트워크가 오래 끊겼다

DNS·네트워크 장애1건

조직
  1. IL-0199 운영에 꼭 필요하지 않은 컨테이너가 메모리 한도를 넘어 파드가 사용 불가로 표시됐고, DNS 작업 탓에 레지스트리에 접속하지 못해 파드가 다시 뜨지 못하면서 GitHub.com 이 4시간 넘게 멈췄다.
    GitHub2020