Incident Library
적용된 필터 구성 요소인그레스 컨트롤러기여 요인미검증 가정모두 풀기검색어 없이 필터만 적용한 목록입니다. 최근 사례부터입니다.
추천 필터 검색하면 검색어에서 찾은 분류 값이 여기에 나옵니다.

그래프

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

사례5건

5건 중 1~5번째

  1. 증상

    새벽 3시에 "배포는 성공했는데, 서비스는 죽었다"는 Slack 메시지가 왔다. 모든 파드는 Ready 였고 Datadog 도 초록불이었지만, 사용자는 계속 오류 화면을 보고 있었다.

    촉발

    롤링 업데이트에서 새 파드가 readinessProbe 를 통과해 Ready 가 되자 Kubernetes 가 곧바로 옛 파드를 지웠다. 그때 ALB 는 새 파드 IP 를 대상 그룹에 막 등록해 initial 상태로 헬스 체크를 하고 있었다.

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

    새벽 3시에 "배포는 성공했는데, 서비스는 죽었다"는 Slack 메시지로 알았다. 파드 상태와 Datadog 대시보드는 모두 정상이었고, 장애는 사용자가 보는 화면에만 나타났다.

    조치
    • 네임스페이스에 elbv2.k8s.aws/pod-readiness-gate-inject=enabled 레이블을 붙였다. AWS Load Balancer Controller 의 웹훅이 파드에 ReadinessGate 를 넣었다. 새 파드는 ALB 대상이 healthy 가 된 뒤에야 Ready 가 됐고, 그제야 옛 파드가 지워졌다.
    교훈

    Kubernetes 의 Ready 와 ALB 의 healthy 는 서로 다른 시점에 정해지므로, 둘을 잇는 장치가 없으면 롤링 업데이트 때 502 가 날 수 있다. 파드 상태와 대시보드가 모두 정상이어도 사용자는 오류를 볼 수 있다. terminationGracePeriodSeconds 를 늘려 시간을 버는 방식은 배포만 느리게 하고 새 파드가 뜰 때의 공백은 막지 못한다. ReadinessGate 는 ALB 대상 유형이 ip 일 때만 의미가 있고, instance 모드에서는 노드가 대상이라 쓸 수 없다. ReadinessGate 를 쓰면 파드가 Ready 가 되기까지 30초에서 40초가 더 걸리므로 급한 스케일 아웃에 대비해 레플리카나 HPA 를 넉넉히 잡는다. 웹훅의 failurePolicy 를 Ignore 로 두면 컨트롤러가 죽어도 배포가 막히지 않는다.

  2. 증상

    LINE 의 messaging-hub 는 일본 음식 배달 서비스 Demaecan 의 Merchant 앱과 Driver 앱에 웹소켓으로 메시지를 보낸다. 어느 날 최대 트래픽 시간이 아닌데도 웹소켓 연결 수 그래프가 순간적으로 크게 떨어졌다. 이 현상은 한 번으로 끝나지 않고 불규칙하게 계속 일어났다.

    촉발

    같은 L7 로드밸런서를 공유하는 다른 서비스 담당자가 자기 LB 설정을 배포하면 HAProxy 가 재로드됐다. hard-stop-after 로 정한 30분이 지나 이전 프로세스가 종료되면서 거기 붙어 있던 웹소켓 연결이 모두 끊겼다.

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

    웹소켓 연결 수 그래프에서 최대 트래픽 시간이 아닌데도 연결 수가 순간적으로 뚝 떨어지는 것을 보고 알았다. Nginx 패킷 드롭은 네트워크 모니터링으로 원인을 찾았다.

    조치
    • Merchant 팀이 토큰 발급 API 를 따로 떼어 배포해 토큰 요청이 몰려도 다른 Merchant API 가 지연되지 않게 했다.
    • Nginx 를 늘리고 파드 안티 어피니티와 레이블 셀렉터로 Nginx 파드가 서로 다른 노드에 뜨게 해서 NF_CONNTRACK 테이블 포화로 생기던 패킷 드롭을 없앴다.
    • Ingress Nginx 의 proxy-read-timeout 과 proxy-send-timeout 을 300s 에서 3600s 로, LB timeout 도 3600s 로 올렸지만 웹소켓 드롭은 멈추지 않았다.
    • 공유하던 L7 LB 를 L4 LB 로 바꿔 웹소켓 드롭을 없앴다.
    교훈

    문제의 범위를 미리 단정해 스스로 제한하면 안 된다. 인프라 팀과 네트워크 팀이 문제없다고 답했다는 이유로 직접 다룰 수 있는 영역만 뒤지다가 공유 L7 LB 를 늦게 의심했다. LB 같은 기술 리소스를 다른 서비스와 공유하면 다른 팀의 배포가 내 서비스의 연결을 끊을 수 있다. Nginx 를 늘려 NF_CONNTRACK 부담을 나눌 때는 파드가 서로 다른 노드에 뜨게 해야 하고, 노드 수보다 많이 늘리면 Pending 상태로 남는 파드가 생긴다는 점도 알아야 한다.

  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. 증상

    GKE 클러스터에서 워크로드를 새 노드 풀로 옮기려고 옛 노드들을 드레인하던 중, 클러스터의 어떤 서비스에도 ingress-nginx 를 거쳐 접속할 수 없게 됐다.

    촉발

    새 노드 풀로 워크로드를 옮기려고 옛 노드를 cordon 하고 드레인했다.

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

    옛 노드를 드레인하던 중 클러스터의 어떤 서비스에도 ingress-nginx 를 거쳐 접속할 수 없는 것을 팀이 알아챘다.

    조치
    • 옛 노드에 남아 있던 nginx-ingress-controller 파드를 지워 새로 Ready 상태가 된 노드에 다시 스케줄되게 했다.
    교훈

    트래픽에 영향을 줄 수 있는 변경을 하기 전에는 문서를 두 번 확인한다. externalTrafficPolicy 가 Local 이면 kube-proxy 는 다른 노드로 트래픽을 넘기지 않고, 로드밸런서 헬스 체크는 엔드포인트가 없는 노드에서 실패한다. cordon 한 노드는 로드밸런서 백엔드에서 빠진다. 이 둘이 겹치면 인그레스 컨트롤러 파드가 cordon 한 노드에만 남아 있을 때 트래픽이 모두 끊긴다.

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

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

원인별4

배포 결함1건

  1. IL-0188 EKS 롤링 업데이트 때 Kubernetes 는 새 파드가 Ready 가 되자마자 옛 파드를 지웠지만 ALB 는 새 파드를 아직 healthy 로 보지 않아, 배포마다 약 30초 동안 502 가 났다.

설정 변경1건

조직
  1. IL-0177 다른 팀의 설정 배포로 공유 L7 HAProxy 가 재로드될 때마다 messaging-hub 의 웹소켓 연결이 한꺼번에 끊겼다.
    LINE+2022

소프트웨어 결함2건

  1. IL-0062 GKE Ingress 뒤의 파드가 SIGTERM 을 받자마자 새 연결을 받지 않고 정상 종료해서 API 에 가끔 502 오류가 났다
  2. IL-0011 HAProxy 인그레스 템플릿이 백엔드 파드를 IP 순으로 정렬해 일부 파드에 요청이 몰리고 인그레스 컨테이너가 OOMKilled 됐다

운영 실수1건

  1. IL-0054 GKE 에서 옛 노드 풀을 드레인하자 로드밸런서가 ingress-nginx 파드가 없는 새 노드만 가리켜 클러스터의 모든 인그레스 트래픽이 끊겼다