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

사례17건

17건 중 7~11번째

  1. 증상

    2022년 1월 Render 의 프랑크푸르트 Kubernetes 클러스터 하나에서 새 배포와 크론 잡 실행이 실패했다. etcd 메모리 급증으로 컨트롤 플레인이 과부하에 걸린 상태였다.

    촉발

    etcd 메모리가 급증해 Kubernetes 컨트롤 플레인이 과부하에 걸렸다.

    원인
    구성 요소
    기여 요인
    후속 조치
    • CoreDNS 를 컨트롤 플레인 노드가 아닌 데이터 플레인 노드에서 돌게 했다.
    • etcd 를 전용 노드에서 돌게 했다.
    교훈

    CoreDNS 는 API 서버가 내려가 있어도 메모리 캐시로 DNS 질의에 답할 수 있지만, 초기화할 때는 API 서버가 필요하다. CoreDNS 가 컨트롤 플레인 노드에 있었기 때문에, 컨트롤 플레인 장애 중에 노드를 재부팅하자 새 배포와 크론 잡만 실패하던 장애가 이미 돌던 서비스로 가는 요청까지 실패하는 장애로 커졌다. 핵심 문제는 데이터 플레인이 컨트롤 플레인에서 충분히 분리되어 있지 않았다는 점이다. 노드를 재부팅하지 않았더라도 etcd 메모리 급증만으로 CoreDNS 가 재시작될 수 있었다.

  2. 증상

    트래픽이 급하게 오르내리는 환경에서 CoreDNS 에 부하가 몰렸다. 네트워크 문제가 생기고 응답 지연이 크게 늘었다.

    촉발

    트래픽이 급변하면서 수가 적은 CoreDNS 파드에 처리할 수 있는 양보다 많은 부하가 몰렸다.

    원인
    구성 요소
    기여 요인
    조치
    • 클러스터 크기에 맞춰 CoreDNS replica 를 늘리도록 CPA 를 설정하고, 인스턴스 타입에 맞게 nodesPerReplica, coresPerReplica, replica 최솟값과 최댓값을 조정했다.
    • CoreDNS 에 anti-affinity 대신 ScheduleAnyway 로 느슨하게 한 topologySpreadConstraints 를 걸어, Karpenter 의 Consolidation 과 Drift 가 CoreDNS 에 막히지 않게 했다.
    • CoreDNS 의 Error Rate, Panics, Request Duration, Request Rate 에 임곗값 알림을 걸었다.
    • NodeLocal DNSCache 를 적용해 노드마다 DNS 캐시를 두고 메인 CoreDNS 의 부하를 낮췄다.
    교훈

    CoreDNS 가 감당할 수 있는 양은 파드에 준 리소스에 따라 다르고, 그에 따라 평균 지연과 초당 질의 수인 QPS 도 달라진다. CoreDNS replica 를 무작정 늘리면 taint 와 topologySpreadConstraints 때문에 파드가 몇몇 노드에 몰려 Karpenter 의 Consolidation 을 막을 수 있다. 노드 하나가 드레인될 때 그 노드의 CoreDNS 가 한꺼번에 많이 종료되면 서비스에 영향이 갈 수 있다. NodeLocal DNSCache 를 쓰면 메인 CoreDNS 로 가는 DNS 질의가 크게 줄고 스파이크를 다루기 쉬워진다. 어느 노드에서 문제가 생겨도 메인 CoreDNS 는 영향을 받지 않는다. 그래서 서비스 전체 장애로 번질 일이 노드 하나의 문제로 그친다. 글쓴이는 CPA 와 NodeLocal DNSCache 를 함께 적용해 CoreDNS 부하 문제를 거의 없앴다고 보았다.

  3. 증상

    2023-09-18 13:42, 팀은 High-priority-alert 채널에서 RootVolUtilisation-Critical 알림을 봤다. 14:03 에는 한 사용자가 이미지 풀이 no space left on device 오류로 실패한다고 알렸다.

    촉발

    EKS 모듈을 버전 18 로 올리면서 런치 템플릿이 바뀌었고, 새 노드의 디스크가 100Gb 에서 20Gb 로 줄었다.

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

    13:42 에 High-priority-alert 채널로 RootVolUtilisation-Critical 알림이 왔다. 14:03 에 사용자가 이미지 풀 실패를 보고했고, 장애 선언은 15:12 였다.

    조치
    • 예전 기본 노드 그룹을 uncordon 하고, 새 노드를 drain 해 워크로드를 예전 노드 그룹으로 되돌렸다.
    • 루트 볼륨을 20Gb 로 줄인 런치 템플릿 변경을 찾아, manager 클러스터와 live 클러스터에 수정을 적용했다.
    • 예전 노드 그룹을 drain 해 워크로드를 수정한 노드로 옮겼다.
    후속 조치
    • EKS 모듈을 올릴 때 런치 템플릿 변경을 비교하는 절차를 런북에 넣는다.
    • live 클러스터처럼 크기가 다양한 이미지를 받아 보는 테스트 환경을 만든다.
    • RootVolUtilisation 알림 런북에 디스크 크기 설정을 확인하는 단계를 넣는다.
    • 노드 수에 따라 CoreDNS 를 자동으로 늘리고 줄인다.
    • IP 접두사 부족을 IPv6 로 풀 수 있는지 조사한다.
    • terraform plan 에서 런치 템플릿이 바뀌면 알아챌 수 있게 드리프트 테스트를 추가한다.
    • CNI 와 ipamd 로그를 볼 수 있게 로깅을 갖추고, IP 접두사 부족 오류가 나면 알림을 보낸다.
    교훈

    이 글은 교훈 대신 후속 조치를 적었다. 조치를 보면 팀에는 빈틈이 두 가지 있었다. 하나는 모듈 업그레이드가 바꾼 런치 템플릿을 배포 전에 비교하지도, 드리프트 테스트로 잡지도 않은 것이다. 다른 하나는 drain 중 팀이 의심한 IP 접두사 부족을 확인할 CNI 와 ipamd 로그도, 알림도 없었던 것이다.

  4. 증상

    남은 엔드포인트의 요청 비율을 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 가 달랐고, 스테이징 환경의 데이터베이스 사양으로는 고부하 시험을 할 수 없었다. 직접 관리하지 않는 부분의 리소스도 잘 알지 못했다. 쿠버네티스로 옮긴 다른 회사의 사례를 조사했다면 이번 문제를 어느 정도 예측할 수 있었다고 했다.

  5. 증상

    어느 금요일 오후, 고객 한 곳이 SCHIP 에서 돌리는 일부 서비스에서 HTTP 5xx 오류가 튄다고 알려 왔다. 팀은 바로 장애를 선언했다.

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

    고객이 SCHIP 에서 돌리는 일부 서비스의 HTTP 5xx 가 튄다고 알려 와서 알았다. DNS 와의 관계는 한참 뒤에야 드러났고, 그때 보니 그동안 무시해 온 이 클러스터의 DNS Latency SLI 가 다른 클러스터보다 낮아져 있었다.

    조치
    • dnsmasq 의 노드당 동시 DNS 질의 한도를 150에서 Google 권장값인 1500으로 올렸다.
    • CoreDNS 가 응답에 RA 비트를 항상 넣도록 header 설정에 set ra aa, clear rd 를 넣어 dnsmasq 가 cluster.local 응답을 캐시하게 했다.
    • 노드 로컬 dnsmasq 에서 ndots 때문에 생긴 풀 수 없는 도메인 질의를 가로채 NXDOMAIN 으로 응답하도록 설정해 CoreDNS 로 넘어가지 않게 했다.
    • fluent-bit 가 로그 라우터에 접속할 때 쓰는 호스트 이름을 서비스 이름에서 FQDN 으로 바꿨다.
    • 영향받은 고객에게 앱의 내부 이름 해석을 FQDN 으로 바꾸도록 요청했다.
    교훈

    SLO 를 보기 좋은 지표로만 두지 말고 안전장치로 써야 한다. 이번에는 나빠진 DNS Latency SLI 를 오래 무시한 탓에 원인을 늦게 찾았다. SLO 를 안전장치로 쓰려면 믿을 수 있는 SLI 가 먼저 있어야 한다. 조사가 여러 당직자에게 흩어져 있었고, 관찰 결과와 가설을 한곳에 모으지 않아 같은 가설이나 이미 버린 가설을 다시 붙잡기도 했다. 가설 하나를 버린 뒤에 다음 가설로 넘어가야 한다. 기존 지표에 없는 데이터는 DNStop 처럼 직접 모아야 한다. 멀티 테넌트 환경에서는 DNS 를 한 번 개선하면 모든 고객이 그 효과를 본다.

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

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

원인별5

용량 한계10건

  1. IL-0102 배포와 워커 오토스케일링 폭주가 겹치자 크기를 고정해 둔 CoreDNS 가 메모리 한도를 넘겨 재시작된 뒤 회복하지 못했고, Buildkite 사이트 전체가 약 30분 멈췄다.
  2. IL-0155 NYC1 의 일부 DOKS 클러스터에서 공유 CPU 노드 위의 CoreDNS 때문에 DNS 가 간헐적으로 실패하고 NodeNotReady 가 났다
  3. IL-0048 대형 EKS 클러스터에서 CoreDNS 가 VPC DNS 리졸버로 보내는 질의가 링크 로컬 트래픽의 초당 1024 패킷 한도에 걸려 DNS 조회가 간헐적으로 타임아웃됐다.
  4. IL-0082 EKS 노드 교체 중 CoreDNS 파드 하나가 종료되자 남은 CoreDNS 파드가 늘어난 부하를 버티지 못해 DNS 조회가 느려지고 타임아웃이 났다.
  5. IL-0027 CoreDNS 파드가 모두 한 노드에 몰린 채 그 노드의 메모리가 고갈되자 DNS 가 응답하지 못해 아이디어스 서비스 전체가 멈췄다
  6. IL-0204 Render 프랑크푸르트 클러스터에서 etcd 메모리 급증으로 컨트롤 플레인이 과부하에 걸렸고, 컨트롤 플레인 노드를 재부팅하자 그 위의 CoreDNS 가 다시 뜨지 못해 DNS 가 멈췄다.
    Render2024
  7. IL-0182 트래픽이 급변할 때 수가 모자란 CoreDNS 가 과부하로 지연과 간헐적 네트워크 끊김을 일으켰고, 나중에는 과하게 늘린 CoreDNS 파드가 Karpenter 의 노드 통합을 막았다
  8. IL-0433 EC2 에서 EKS on Fargate 로 트래픽을 옮기던 중 CoreDNS 과부하로 이름 해석 오류가 쏟아져 롤백했다
  9. IL-0445 EKS 로 옮기던 레거시 시스템에서 conntrack 테이블이 넘쳐 연결이 끊겼고, 이어 CoreDNS 파드가 축출될 때와 node-local-dns 를 넣은 뒤에 DNS 오류가 났다
  10. IL-0001 CoreDNS 파드가 메모리 한도 100Mi 에 걸려 OOM 으로 계속 죽으면서 쿠버네티스 클러스터 전체의 DNS 가 멈췄다

소프트웨어 결함1건

  1. IL-0104 Istio 의 공격적인 DNS 캐시 갱신과 클라이언트 포트 재사용, kube-proxy 가 종료된 파드의 conntrack 항목을 정리하지 않는 문제, 2분짜리 UDP conntrack 기본 타임아웃이 겹쳐 CoreDNS 파드가 OOMKilled 됐다.

설정 변경2건

  1. IL-0019 EKS 모듈 18 업그레이드로 새 노드의 디스크가 20Gb 로 줄어 이미지 풀이 no space left on device 로 실패했다
  2. IL-0461 메트릭 질의 서비스를 롤아웃할 때마다 DNS 오류가 나며 질의가 실패했다

DNS·네트워크 장애3건

  1. IL-0083 멀티 테넌트 쿠버네티스 클러스터에서 노드 로컬 dnsmasq 가 동시 질의 한도에 걸리고 cluster.local 응답을 캐시하지 못한 데다 ndots 검색 도메인 질의가 CoreDNS 로 몰려, 서비스 간 호출이 간헐적인 5xx 를 냈다.
  2. IL-0517 Gitpod 워크스페이스 클러스터의 CoreDNS 가 상위 DNS 서버에 닿지 못해 워크스페이스가 시작되지 않고 일부 데이터가 사라졌다
    Gitpod2022
  3. IL-0049 CoreDNS 파드가 줄어든 뒤 kube-proxy 가 conntrack 항목을 지우지 못해 일부 서비스의 DNS 요청이 없어진 파드로 가면서 5xx 가 쏟아졌다
    Preply2020

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

조직
  1. IL-0230 쿠버네티스 업그레이드 도중 메인 운영 클러스터의 서비스 간 통신이 끊겨 모든 고객의 작업이 시작되지 않았다