Incident Library
적용된 필터 원인소프트웨어 결함기여 요인미검증 가정모두 풀기검색어 없이 필터만 적용한 목록입니다. 최근 사례부터입니다.
추천 필터 검색하면 검색어에서 찾은 분류 값이 여기에 나옵니다.

그래프

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

사례8건

8건 중 3~7번째

  1. 증상

    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 로 파드를 늘려 여유 있는 노드에 배치되게 한다. 클러스터에 여유가 없으면 알림을 받거나 노드 오토스케일러로 노드를 늘린다.

  2. 증상

    RedisFailover 리소스에 바뀐 설정을 적용하자 고객 웹사이트의 가장 큰 Redis 데이터베이스에서 데이터가 모두 사라졌다. 이 데이터베이스는 TTL 없이 영속 저장소로도 쓰였고, .rdb 스냅숏이 5 Gb 를 넘었다. 서비스가 멈췄고 백업에서 데이터를 복원해야 했다.

    촉발

    RedisFailover 리소스에서 Redis 레플리카 수를 1에서 2로 늘리면서, 같은 변경으로 컨테이너의 메모리 requests 와 limits 를 22 GB 에서 19 GB 로 낮췄다.

    원인
    구성 요소
    기여 요인
    조치
    • 미리 준비해 둔 백업에서 Redis 데이터를 복원했다.
    후속 조치
    • 레디니스 프로브 문제를 Redis Operator 이슈로 올렸고, 개발자들에게서 받은 수정을 시험해 통과를 확인했다.
    • 상황 분석을 마친 뒤 Spotahome Redis Operator 를 계속 쓸지 다시 검토한다.
    • Redis 데이터베이스를 정리하고, 불필요한 키를 만든 애플리케이션 코드를 고친다.
    • Redis 의 내장 클러스터링과 샤딩을 검토한다.
    교훈

    핵심 인프라를 쿠버네티스 오퍼레이터로 관리할 때는 그 오퍼레이터가 얼마나 성숙하고 검증됐는지 따져 봐야 한다. 레플리카 수와 리소스 값을 한 번에 바꾸면 롤링 업데이트가 예상하지 못한 순서로 파드를 재시작할 수 있다. 레디니스 프로브가 ping 만 보면 복제가 끝나지 않은 빈 인스턴스도 준비됐다고 판단한다. Redis 클러스터를 바꾸기 전에는 반드시 dump.rdb 파일을 백업해야 한다.

  3. 증상

    Ravelin 이 API 계층을 기존 VM 에서 GKE 의 쿠버네티스 클러스터로 옮기고 Ingress 를 설정한 뒤, 통합 테스트가 가끔 502 오류를 받기 시작했다.

    촉발

    파드가 종료될 때 SIGTERM 을 받자 새 연결을 받지 않는 정상 종료를 시작했지만, GKE Ingress 는 엔드포인트 변경을 늦게 반영해 그 파드로 계속 새 트래픽을 보냈다.

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

    Ingress 를 설정한 뒤 통합 테스트가 가끔 502 오류를 받는 것을 보고 알았다.

    교훈

    쿠버네티스에서 엔드포인트 제거와 SIGTERM 은 동시에 일어나므로, SIGTERM 을 받았다고 바로 새 연결을 거부하면 안 된다. Ingress 는 특히 엔드포인트 변경을 늦게 반영한다. 파드는 종료 유예 시간이 끝날 때까지 계속 요청을 처리해야 하고, 유예 시간은 로드 밸런서에 변경이 반영되는 시간보다 길어야 한다.

  4. 증상

    어느 일요일, 클러스터 사용자 한 명이 지연 시간이 올라갔다며 쿠버네티스 업무 시간 외 지원 담당을 직접 호출했다. 특히 p90 과 최댓값 지연이 높았다.

    촉발

    HAProxy 인그레스 컨트롤러를 v0.6 으로 올렸다. v0.5 문서는 sort-backends 플래그의 기본값이 false 이고 백엔드 서버를 기본으로 무작위로 섞는다고 설명했다. 그러나 템플릿이 pod_ip:port 를 키로 하는 맵을 순회할 때 Go 의 text/template 이 키 순서대로 방문해, 파드는 늘 IP 오름차순으로 설정 파일에 들어갔다. 운영 클러스터처럼 변화가 잦은 곳에서는 설정이 자주 다시 쓰였고, HAProxy 가 무중단 리로드를 하지 못해 재시작하는 일이 잦았다. 그때마다 모든 HAProxy 인스턴스가 같은 목록의 처음부터 라운드 로빈을 시작했다.

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

    클러스터 사용자가 p90 과 최댓값 지연이 오른 것을 보고 업무 시간 외 쿠버네티스 지원 담당을 직접 호출했다. 그 전에도 한 사용자가 파드 사이 요청 분포가 고르지 않다고 알렸지만 팀은 우선순위를 낮게 두었다.

    조치
    • 내부 배포 도구 Slingshot 의 설정을 바꿔, 영향받은 서비스의 매니페스트가 파드 IP 대신 Service VIP 를 쓰게 했다.
    • 컨트롤러가 맵에 넣은 순서를 슬라이스에 보관하고 템플릿이 그 슬라이스를 순회하도록 컨트롤러 코드와 설정 템플릿을 패치했다.
    • 패치를 샌드박스 클러스터에서 테스트한 뒤 운영 클러스터에 배포했다.
    후속 조치
    • 컨트롤러 패치를 운영에서 돌리고, 백엔드 주소는 다시 파드 IP 를 기본으로 쓴다.
    • 업스트림 프로젝트에 GitHub 이슈와 PR 을 올려 문제를 알렸다.
    • 클러스터 컴포넌트를 바꿀 때는 구체적인 동작과 조건을 염두에 두고 테스트한다.
    교훈

    클러스터 컴포넌트를 바꿀 때는 특정 동작과 조건을 염두에 두고 테스트해야 한다. 팀은 백엔드 목록이 정렬되면 hot-podding 이 생긴다는 것을 이미 알았지만, 새 플래그가 기대대로 동작하는지 충분히 테스트하지 않았다. 같은 키워드라도 언어의 한 곳에서 동작하는 방식이 다른 곳에서도 같으리라고 기대하면 안 된다. Go 의 range 와 text/template 의 range 는 맵을 순회하는 순서가 달랐다. 쿠버네티스 클러스터의 작은 컴포넌트 하나만 바꿔도 클러스터 사용자와 고객에게 큰 피해를 줄 수 있다.

  5. 증상

    팀의 Redis 의존 라이브러리를 쓰는 서비스들이 시작하자마자 죽는다는 보고가 운영 담당자에게 들어왔다. Spring Boot 로그를 보니 빈 초기화 중에 Redis 호스트 이름을 해석하지 못하고 있었다.

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

    Redis 의존 라이브러리를 쓰는 서비스 팀들이 시작 중에 서비스가 죽는다고 운영 담당자에게 보고하면서 문제가 처음 드러났다. 문제가 다시 나타났을 때는 팀이 Kibana 에서 호스트 이름 해석 실패를 보고 알았다.

    조치
    • 배포 매니페스트에 dnsConfig 블록을 넣어 ndots 를 4 로 낮췄다.
    • 라이브러리에서 잘못 설정된 최대 연결 풀 크기를 고쳐 새 버전을 내고 Redis 연결 수를 약 70% 줄였다.
    후속 조치
    • 이미지 라이브러리에 추가한 glibc 기반 Debian 베이스 이미지가 DNS 문제를 해결하는지 시험한다.
    • 더 새로운 Netty 버전을 쓰도록 의존성을 올린다.
    교훈

    쿠버네티스 기본값 ndots:5 에서는 리졸버가 점이 다섯 개보다 적은 외부 호스트 이름에 검색 도메인을 먼저 붙여 조회한다. 이 동작이 musl 리졸버의 NXDOMAIN 처리나 라이브러리의 DNS 리졸버 결함과 만나면 간헐적인 해석 실패가 된다. ndots 를 낮추면 대부분 서비스가 살아나지만 오래가는 해법은 아니다. 글쓴이는 이런 실패를 잡는 알림을 원했지만, 한 번씩 나는 DNS 실패마다 울리는 알림은 원하지 않는다고 했다.

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

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

원인별1

소프트웨어 결함8건

  1. IL-0058 Argo CD 에서 여러 앱이 함께 선언한 네임스페이스가 force 동기화로 지워져 앱 약 97개가 Missing/OutOfSync 상태에서 빠져나오지 못했다.
  2. IL-0171 Bottlerocket AMI 에 libdcgm.so 가 없어 GPU 노드의 AcceleratedHardwareReady 가 False 가 됐고, Karpenter 노드 자동 복구가 Ready 뒤 10~11분마다 GPU 노드를 교체하는 일을 끝없이 되풀이했다.
    Inflab2025
  3. IL-0029 CPU 한도를 건 컨테이너가 사용량이 한도에 한참 못 미치는데도 스로틀링되어 사용자 대면 서비스의 지연 시간이 늘었다.
    Buffer2020
  4. IL-0196 Redis Operator 로 레플리카를 늘리면서 메모리 한도를 낮추자 데이터를 가진 유일한 Redis 파드가 재시작됐고, Sentinel 이 빈 레플리카를 마스터로 올려 데이터가 모두 지워졌다.
    Palark2020
  5. IL-0062 GKE Ingress 뒤의 파드가 SIGTERM 을 받자마자 새 연결을 받지 않고 정상 종료해서 API 에 가끔 502 오류가 났다
  6. IL-0011 HAProxy 인그레스 템플릿이 백엔드 파드를 IP 순으로 정렬해 일부 파드에 요청이 몰리고 인그레스 컨테이너가 OOMKilled 됐다
  7. IL-0050 ndots:5, Alpine 의 musl 리졸버, Netty 4.1.30 의 DNS 처리 문제가 겹쳐 쿠버네티스 서비스가 클러스터 밖 Redis 호스트 이름을 반복해서 해석하지 못했다
  8. IL-0051 외부 업체의 로그 클라이언트가 새 컨테이너가 뜰 때마다 파일 디스크립터를 다시 열고 이전 것을 닫지 않아 쿠버네티스 노드가 too many open files 로 내려갔다