Incident Library
적용된 필터 구성 요소리눅스 커널기여 요인미패치 알려진 버그도메인쿠버네티스모두 풀기검색어 없이 필터만 적용한 목록입니다. 최근 사례부터입니다.
추천 필터 검색하면 검색어에서 찾은 분류 값이 여기에 나옵니다.

그래프

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

사례5건

5건 중 1~5번째

  1. 증상

    토요일인 5월 17일 이른 시각에 OpsGenie 알림이 울렸다. Altinity.Cloud 의 ClickHouse 클러스터 하나가 갑자기 조용해졌다. 쿼리도, 지표도, 접속하려는 고객의 로그도 들어오지 않았다. 파드는 모두 Running 이었고 노드도 정상으로 보였지만 데이터베이스까지 오는 트래픽이 없었다.

    촉발

    GKE 가 노드를 ubuntu_containerd 1.32.3-gke.1785003 이미지와 커널 6.8.0-1022-gke 로 자동 업그레이드했다. 이 커널은 nf_tables 모듈의 패키징이나 로딩 방식에 회귀가 있어 kube-proxy 가 쓰는 iptables 확장을 지원하지 않았다.

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

    OpsGenie 알림으로 알았다. ClickHouse 클러스터 하나에서 쿼리, 지표, 고객 접속 로그가 모두 끊겼고, 곧 다른 클러스터들도 같은 상태가 됐다.

    조치
    • 아직 영향받지 않은 클러스터에 유지보수 제외를 걸어 업그레이드를 모두 멈췄다. 이 조치로 문제가 GKE 에서 운영하는 모든 클러스터로 번지는 것을 막았다.
    • 로드밸런서 헬스 체크 정책을 바꿔 kube-proxy 헬스 체크 실패를 무시하게 했다. kube-proxy 에 필요한 확장이 없는 노드로도 트래픽이 흐르면서 서비스가 회복됐다.
    • 영향받은 클러스터 전부를 ubuntu_containerd 에서 nf_tables 문제가 없는 다른 커널을 쓰는 cos_containerd 이미지로 옮기기 시작했다. 노드를 새 이미지로 다시 만들어야 해서 짧은 다운타임이 생겼다.
    후속 조치
    • 회귀를 더 일찍 잡도록 이미지 사전 테스트 파이프라인을 넓힌다.
    • GKE 자동 업그레이드 예정 알림을 켜서 미리 대비한다.
    • 모든 클러스터에 GKE 유지보수 기간을 반드시 설정해 업그레이드가 배포되는 시점을 직접 정한다.
    • Google 이슈 트래커에 올린 커뮤니티 이슈를 추적하며 고쳐진 Ubuntu 이미지를 기다린다.
    교훈

    관리형 Kubernetes 의 노드 자동 업그레이드는 사용자가 검증하지 않은 커널을 운영 노드에 올린다. 클라우드 업체의 이미지 검증만 믿으면 이런 회귀를 막지 못한다. IPv6 를 쓰지 않아도 kube-proxy 는 IPv6 iptables 규칙을 적용하므로, 그 적용이 실패하면 로드밸런서 헬스 체크도 실패해 모든 인그레스가 끊길 수 있다. 영향받은 버전이 확인되면 아직 업그레이드되지 않은 클러스터의 업그레이드부터 멈춰야 피해가 번지지 않는다. Altinity 는 영향받은 사용자에게 externalTrafficPolicy: Cluster 로 바꿔 kube-proxy 헬스 체크를 끄고, 운영 노드 이미지를 cos_containerd 로 바꾸고, 고쳐진 이미지가 확인될 때까지 자동 업그레이드를 멈추라고 권한다.

  2. 증상

    KateSQL 의 인스턴스 교체 작업에서 MySQL 파드 생성 시간이 10분에서 30분까지 들쭉날쭉했다. 일부 MySQL 파드는 데이터가 같은 다른 파드보다 시작과 종료가 훨씬 느렸고, 설정 변경이나 업그레이드 같은 유지 보수 때 MySQL 인스턴스를 빨리 교체하기 어려워졌다.

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

    KateSQL 인스턴스 교체 작업에서 MySQL 파드 생성 시간이 10분에서 30분까지 들쭉날쭉한 것을 보고 알았다.

    조치
    • 옛 노드를 cordon 하고, KateSQL 인스턴스 교체로 MySQL 파드를 새 노드로 옮기며 GKE 오토스케일러가 노드를 늘리게 한 뒤, 옛 노드를 drain 해 클러스터를 줄였다. 새 MySQL 파드의 성능이 좋아졌다.
    • `echo 1 | sudo tee /sys/fs/cgroup/memory/kubepods/memory.force_empty` 로 kubepods cgroup 이 죽은 cgroup 을 비우게 해 메모리 cgroup 수를 약 1800개로 줄였다. 재시작한 MySQL 파드는 80G 버퍼 풀을 5초 만에 초기화했다.
    • GKE 1.18 로 새 GKE 클러스터를 만들어 새 MySQL 파드를 그 클러스터에 띄웠다. 몇 주 동안 버퍼 풀 초기화 시간과 질의 성능이 고르게 유지됐다.
    교훈

    이번 조사는 Shopify 데이터베이스 플랫폼 그룹이 한 조사 가운데 가장 오래 걸린 축에 들었다. 문제의 성격, 재현의 어려움, 따를 만한 정해진 방법이 전혀 없었다는 점 때문에 근본 원인을 찾는 데 오래 걸렸다. 그래도 문제를 풀 방법은 여러 가지가 있었다.

  3. 증상

    Buffer 엔지니어가 컨테이너의 스로틀링 지표를 살펴보니, CPU 사용량이 한도 근처에도 가지 않은 컨테이너가 많이 스로틀링되고 있었다.

    촉발

    Buffer 는 노드를 지키려고 컨테이너에 CPU 한도를 걸어 두었는데, 노드 커널에는 CPU 한도가 걸린 컨테이너를 필요 없이 스로틀링하는 버그가 남아 있었다.

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

    엔지니어가 컨테이너의 스로틀링 지표를 살피다가, CPU 사용량이 한도보다 훨씬 낮은 컨테이너도 많이 스로틀링되는 것을 보고 알았다.

    조치
    • 사용자에게 직접 또는 간접으로 닿는 경로에 있는 모든 서비스에서 CPU 한도를 없앴다.
    • 한도를 없앤 서비스에 톨러레이션을 더해 테인트를 건 노드에서만 돌게 하고, 한도가 있는 서비스와 떼어 놓았다.
    • 서비스마다 몇 달 치 사용량을 분석해 최대 CPU 사용량에 20% 넘는 여유를 더한 값을 CPU 요청값으로 정했고, 메모리 요청값도 같은 방식으로 정했다.
    후속 조치
    • 커널 수정이 들어간 노드 이미지로 올린다. Buffer 는 kops 1.18 이상에서 기본 이미지가 되는 Ubuntu 20.04 를 기다리고 있다.
    • 수정된 커널로 올린 뒤 스로틀링이 정말 사라졌는지 확인하고, 그 결과로 글을 고친다.
    교훈

    리눅스에서 컨테이너를 돌리면 쿠버네티스든 Mesos 든 Swarm 이든 스로틀링 때문에 컨테이너가 제 성능을 내지 못할 수 있다. 먼저 커널을 수정된 버전으로 올리고 스로틀링 지표를 지켜보는 편이 낫다. CPU 한도를 없애면 지연 시간은 줄지만 위험하다. 한도를 없앤다면 CPU 요청값을 제대로 잡고, 노드의 CPU 와 메모리 사용량을 꼼꼼히 모니터링한다. 사용량이 높으면 Horizontal Pod Autoscaler 로 파드를 늘려 여유 있는 노드에 배치되게 한다. 클러스터에 여유가 없으면 알림을 받거나 노드 오토스케일러로 노드를 늘린다.

  4. 증상

    Omio 는 6개월 동안 원인을 알 수 없는 멈춤을 겪었다. 애플리케이션이 멈추거나 헬스 체크에 응답하지 않았고, 네트워크 연결이 끊겼다.

    촉발

    쿠버네티스는 CPU limit 을 커널 CFS 의 쿼터로 구현한다. 주기는 100ms 이고, limit 2코어는 주기마다 CPU 시간 200ms 가 된다. 스레드 10개가 동시에 돌면 20ms 만에 쿼터를 다 쓰고, 남은 80ms 동안 파드의 모든 스레드가 멈춘다. 여기에 커널 CFS 스케줄러의 알려진 버그가 불필요한 스로틀링을 일으켜, 컨테이너가 허용된 쿼터를 다 쓰기도 전에 스로틀링됐다.

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

    팀은 6개월 동안 애플리케이션이 멈추거나 헬스 체크에 응답하지 않는 현상을 겪었지만, 쿠버네티스가 cgroup 지표를 내보내지 않아 스로틀링을 바로 알아채지 못했다. 파드 안에서 /sys/fs/cgroup/cpu/cpu.stat 의 nr_throttled 와 throttled_time 을 읽어 스로틀링 비율을 확인했다.

    조치
    • 버그를 고친 최신 커널이 모든 클러스터에 배포될 때까지 CPU limit 을 껐다.
    후속 조치
    • CFS 쿼터 버그를 고친 최신 커널을 모든 클러스터에 배포한다.
    • 사용률, 포화도, 오류를 보는 USE 지표와 함께 API 지연과 오류율을 지켜보며 결과가 기대한 대로인지 확인한다.
    교훈

    CFS 쿼터 버그가 고쳐지지 않은 커널을 쓴다면 쿠버네티스에서 CPU limit 을 없애거나 kubelet 에서 CFS 쿼터를 끄는 편이 낫다. CPU request 와 limit 은 설정이 비슷해 보여도 구현이 전혀 다르다. CPU 스로틀링은 쿠버네티스 기본 지표에 드러나지 않으므로 cpu.stat 을 직접 확인해야 한다. limit 을 끄면 최적화되지 않은 애플리케이션이 노드의 CPU 를 독차지할 수 있으니, JVM, Go, Node 런타임을 미리 튜닝해 둬야 한다.

  5. 증상

    Nginx 기반 리버스 프록시를 쿠버네티스로 옮긴 뒤, Prometheus 가 몇몇 서비스의 p99 지연 증가에 알림을 보냈다. 그래프에서 p99 지연은 7/24 부터 올라가 있었다.

    촉발

    리버스 프록시를 전용 ElasticBeanstalk 머신에서 공용 EKS 워커 노드로 옮기자, 프록시가 다른 서비스로 보내는 패킷이 노드에서 iptables 규칙에 따라 SNAT 를 거치게 되었다.

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

    Prometheus 가 몇몇 서비스의 p99 지연 증가에 알림을 보냈다. 예전처럼 평균 응답 시간만 봤다면 꼬리 지연만 오른 이번 문제는 십중팔구 놓쳤을 것이다.

    조치
    • 지연이 생기는 곳을 찾으려고 AWS X-Ray 추적을 붙이고, 추적에 $upstream_connect_time 속성을 더했다.
    • 해당 서비스의 파드를 더 많은 노드에 더 많이 띄웠다. 지연은 줄었지만 사라지지 않았다.
    • AWS VPC CNI 에 AWS_VPC_K8S_CNI_EXTERNALSNAT=true 를 설정해 노드에서 SNAT 를 껐다.
    교훈

    쿠버네티스 같은 복잡한 시스템을 디버깅할 때는 관측 가능성이 핵심이다. 평균 응답 시간 대신 p99 를 보고 있었기에 문제를 알아챘고, 추적을 붙여 느린 요청의 특징을 알게 되자 원인 가까이 갈 수 있었다. 실제 해법을 찾으려면 SNAT 가 어떻게 동작하는지, EKS 내부와 amazon-vpc-cni-k8s 플러그인이 어떤 역할을 하는지까지 이해해야 했다. EKS 에서는 노드 AMI 의 iptables 가 무작위 포트 할당을 지원하지 않을 수 있고, 그때는 외부 SNAT 설정이 대안이 된다.

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

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

원인별3

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

조직
  1. IL-0079 GKE 노드가 새 ubuntu_containerd 이미지로 자동 업그레이드된 뒤 커널에서 kube-proxy 가 쓰는 iptables 확장이 빠져, 여러 GKE 클러스터의 인그레스 트래픽이 완전히 끊겼다.

소프트웨어 결함3건

  1. IL-0462 GKE 위 MySQL 파드 일부가 시작과 종료에 오래 걸려 KateSQL 인스턴스 교체가 느려졌다
  2. IL-0029 CPU 한도를 건 컨테이너가 사용량이 한도에 한참 못 미치는데도 스로틀링되어 사용자 대면 서비스의 지연 시간이 늘었다.
    Buffer2020
  3. IL-0012 CPU limit 과 커널 CFS 쿼터 버그로 파드가 과하게 스로틀링돼 헬스 체크가 실패하고 애플리케이션이 멈췄다
    Omio2020

DNS·네트워크 장애1건

조직
  1. IL-0057 EKS 노드의 SNAT 과정에서 conntrack 경합으로 바깥으로 나가는 TCP 연결이 1초나 3초씩 늦어져, 서비스 간 호출이 많은 서비스의 p99 지연이 늘었다.
    Prezi2019