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

사례3건

3건 중 1~3번째

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

    Metrictank 인스턴스 일부가 쓰기 큐를 비우지 못한다는 알림이 왔다. Metrictank 가 Cassandra 에 쓰지 못하고 있다는 뜻이었다.

    촉발

    GCP SSD 영구 디스크의 성능이 크게 떨어져 많은 I/O 가 오랫동안 실패했고, 그 때문에 노드가 자동으로 재부팅됐다.

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

    팀은 Metrictank 쓰기 인스턴스가 쓰기 큐를 비우지 못한다는 알림을 받고 장애를 알았다. Metrictank 가 대부분의 쿼리를 메모리에서 계속 처리해서 오류율은 아주 천천히 올라갔기 때문에, 이 알림이 없었다면 발견이 훨씬 늦었을 것이다.

    조치
    • 새 노드라면 디스크를 붙일 수 있을 것이라 보고 클러스터의 컴퓨트 노드를 늘렸지만 효과가 없었다.
    • GCP 장애가 풀린 뒤 Cassandra StatefulSet 을 지우고 Pod Management Policy 를 바꿔 다시 만들었다. 파드 하나를 빼고 모두 떠서 Cassandra 클러스터가 정상으로 돌아왔다.
    • 긴 장애 동안 데이터를 잃지 않도록 Kafka 토픽 보존 기간을 늘렸다.
    • Metrictank 재시작이 CPU 부족으로 느려지지 않도록 클러스터에 노드를 임시로 더 붙였다.
    • 모든 Metrictank 인스턴스를 재시작해 새 Cassandra IP 로 연결되게 했다. 재시작은 20시간 넘게 걸렸다.
    후속 조치
    • 모든 Cassandra IP 가 바뀌면 Metrictank 가 다시 연결하지 못하는 버그를 고쳤다. 연결이 죽은 것을 감지하면 gocql 연결을 새로 만든다.
    • 쓰기 큐가 가득 찬 상태에서 새 데이터가 들어오면 생기던 교착을 고쳤다. 내부 자료 구조 하나를 잠금으로 보호하는 대신 atomic 연산으로 갱신한다.
    교훈

    받은 데이터를 처리하기 전에 쓰기 선행 로그인 Kafka 에 먼저 저장해 둔 덕분에, Cassandra 를 되살린 뒤 그동안 받은 데이터를 모두 처리해 저장할 수 있었다. Kafka 가 SSD 가 아닌 디스크를 쓴 것은 운이 좋았다. 그렇지 않았다면 Kafka 도 Cassandra 와 같은 장애를 겪었을 수 있다. 23시간 동안 파라과이, 알바니아, 호주에 있는 세 사람이 시간대를 나눠 대응했다. 두 버그를 고친 지금은 같은 상황이 와도 복구가 23시간이 아니라 3시간 안에 끝날 것으로 본다. 오래 미룬 문제도 새로 보면 생각보다 간단히 풀릴 수 있다. 장애가 주말에 나서 고객 부하가 대부분 캐시 데이터를 읽는 알림 쿼리뿐이었던 것도 운이 좋았다.

  3. 증상

    2018년 7월 19일 15:00 UTC 쯤 모니터링 인프라가 일부 API, 특히 pilot 과 tiles 의 5xx 응답 증가를 알렸다. 사용자 프로필을 가져오는 pilot 서비스가 먼저 응답하지 않아 플랫폼 로그인이 실패했고, 문제는 거기서 퍼져 나갔다.

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

    15:00 UTC 쯤 모니터링 인프라가 일부 API, 특히 pilot 과 tiles 의 5xx 응답 증가를 알렸다.

    조치
    • 멈춘 워커 노드의 kubelet 을 되살리려 했지만 노드는 곧 다시 Not Ready 가 되었다.
    • 18:00 UTC 쯤부터 클러스터의 모든 워커 노드를 시차를 두고 재시작했다. 약 1.5시간 뒤 모든 노드의 재시작이 끝나며 서비스가 안정되었다.
    후속 조치
    • 수정이 업스트림에 들어가 클라우드 제공자인 MS Azure 에 반영될 때까지, 노드와 kubelet 이 정상으로 돌도록 정기적인 롤링 재시작을 적용한다.
    교훈

    AirMap 은 운영 클러스터의 증상을 오픈소스 커뮤니티의 알려진 이슈와 대조해 근본 원인과 수정 후보를 찾을 수 있었다. 업스트림 수정이 클라우드 제공자에게 반영되기 전까지는 워커 노드를 정기적으로 롤링 재시작해 같은 장애를 막는다.

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

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

원인별3