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

사례3건

3건 중 1~3번째

  1. 증상

    2025년 3월 3일 14:15:34부터 홈랩 쿠버네티스에 올린 서비스에 접속되지 않았다. 운영자가 서비스에 들어가려다 직접 알아챘고, 알아채기까지 3시간이 걸렸다.

    촉발

    정전 때문에 마스터 노드가 재부팅됐다.

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

    운영자가 서비스에 접속하려다 직접 알아챘다. 자동 알림이 없어서 알아채기까지 3시간이 걸렸다.

    조치
    • 원격 접속이 되지 않아 모니터를 연결해 부팅 로그를 보고 커널 패닉을 확인했다.
    • 이전 커널 버전으로 부팅해 시스템을 되살렸다.
    • sudo apt-get remove --purge '^nvidia-.*' 로 망가진 패키지를 지우고 sudo dpkg --configure -a 로 패키지 설정 문제를 고쳤다.
    • dpkg -l | grep -v ^ii 로 남은 망가진 패키지를 찾아 sudo apt-get remove --purge <package_name> 으로 하나씩 지웠다.
    • sudo apt-get install -f 로 빠진 의존성을 채우고 sudo apt-get install --reinstall linux-headers-$(uname -r) 로 커널 헤더를 다시 설치했다.
    • 머신을 재부팅해 커널 패닉이 사라진 것을 확인했다.
    후속 조치
    • GPU 드라이버 설치가 완전히 성공했는지 확인하고, 오류가 나면 바로 변경을 되돌린다.
    • 단일 장애 지점을 없애도록 클러스터를 고가용성 구성으로 옮긴다.
    • 고가용성 구성에서 Kube-API 를 로드 밸런서 뒤에 둔다.
    • 장애를 기록하고 해결 과정을 추적할 티켓 시스템을 만든다.
    • 미리 정해 둔 문제 해결 절차를 만들어 홈랩 장애 대응 시간을 줄인다.
    • Prometheus 와 Grafana 같은 인프라 모니터링을 넣어 문제를 미리 잡는다.
    • 주요 서비스에 HTTP, TCP 검사를 거는 블랙박스 모니터링을 넣어 쿠버네티스 클러스터 밖에서도 장애를 잡는다.
    교훈

    드라이버 빌드 실패를 그대로 두면 몇 주 뒤 재부팅 때 터질 수 있다. 자동 알림이 없어서 발견과 복구가 늦었다. 마스터 노드가 하나뿐이라 노드 하나의 고장이 클러스터 전체 장애가 됐다. 원인을 찾은 뒤에는 비교적 간단히 고쳤고, 데이터 손실은 없었다.

  2. 증상

    2023년 3월 14일 19시 UTC 직후 엔지니어가 Old Reddit 이라 불리는 레거시 스택을 돌리는 클러스터의 업그레이드를 시작했다. 2분쯤은 괜찮아 보였지만 곧 사이트 전체가 갑자기 멈췄다. CDN 엣지의 상태 코드별 RPS 그래프가 이를 보여 주었다. 사용자는 오류 페이지나 글이 하나도 없는 홈페이지를 보았다.

    촉발

    Reddit 에서 가장 중요한 클러스터 가운데 하나인 레거시 클러스터를 쿠버네티스 1.23 에서 1.24 로 업그레이드했다.

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

    업그레이드를 시작하고 2분쯤 뒤 CDN 엣지의 상태 코드별 RPS 그래프에서 사이트가 멈춘 것이 보였다. 팀은 곧바로 장애를 선언했고 3분 안에 대응 인원이 통화에 모였다. 엣지 지표는 일부러 클러스터와 분리되어 있어 살아 있었지만, 클러스터 자체의 지표는 모두 사라졌다.

    조치
    • API 서버에서 타임아웃을 내던 Open Policy Agent 의 웹훅 설정을 지웠다.
    • 복원 뒤 어차피 쓸 수 없게 될 워커 노드를 모두 종료했다.
    • 컨트롤 플레인 노드 두 대를 종료하고, 남은 한 대의 구성 요소를 다운그레이드한 뒤 그 노드에 백업 데이터를 복원했다.
    • 단일 노드 컨트롤 플레인이 부하에 무너지지 않도록 클러스터 오토스케일러를 껐다.
    • 새 컨트롤 플레인 노드를 띄우고, 호스트명이 맞지 않던 TLS 인증서를 새로 만들어 노드들을 합류시켰다.
    • 트래픽을 1% 에서 시작해 5%, 10%, 20%, 35%, 55%, 80%, 100% 로 조금씩 늘렸다.
    • 트래픽이 돌아올 때 문제를 일으키지 않도록 손으로 멈춰 두었던 민감한 레거시 서비스를 조심스럽게 다시 켰다.
    후속 조치
    • 클러스터 구성을 코드로 관리해 모든 선택에 기록이 남게 하고, 코드로 만들 수 없는 것은 자세히 문서로 남긴다.
    • 클러스터마다 다른 맞춤형 구성을 걷어 내고 모든 클러스터의 구성 요소를 표준화한다.
    • 모든 클러스터를 최대한 같은 모습으로 유지하고 필요하면 다시 만들거나 복제할 수 있도록 클러스터 전체의 수명 주기를 관리하는 도구를 만든다.
    • 믿고 테스트에 쓸 수 있는 프리프로덕션 클러스터를 더 둔다.
    • 백업 복원 절차를 개선하고 클러스터 업그레이드를 안전하게 만든다.
    교훈

    쿠버네티스 버전과 구성 요소 업그레이드는 여전히 위험하다. 미리 테스트하고 검증해도 이번처럼 처음 보는 방식으로 깨질 수 있다. 쿠버네티스에는 공식 다운그레이드 절차가 없어, 롤백하는 방법은 백업에서 복원하는 것뿐이다. 복원 절차가 환경 변화를 따라가지 못하면 실제 장애 때 그 자리에서 고쳐 써야 하고, 복원을 결정하기까지 오래 망설이게 된다. 이번 복원은 결국 성공했지만 절차는 개선해야 한다. 코드로 남기지 않은 설정은 아는 사람이 떠나면 아무 기록도 남지 않는다. 라우트 리플렉터 설정이 어디에도 커밋되어 있지 않아 장애 중에 누구도 의심하지 못했다. 지표가 클러스터 안에서만 수집되면 클러스터가 망가질 때 함께 사라진다. 이번에는 로그 수집 에이전트가 영향을 받지 않아 원인을 추적할 수 있었다. 클러스터마다 다른 맞춤형 구성이 쌓이면 장애가 잦아진다. 직접 원인은 노드 레이블이었지만 근본 원인은 일관성 부족이었다.

  3. 증상

    dex의 AuthRequest 리소스가 엄청난 수로 쌓여 있었다. 발표자는 그 전부터 이미 징후가 있었다고 했다.

    촉발

    dex의 잘못된 기본값 때문에 AuthRequest 리소스가 쌓였다. 발표는 원인으로 지나치게 긴 TTL, 계속 새로고침되는 대시보드, 실제 보안 버그를 꼽았다. 그리고 쌓인 리소스를 치우려고 dex 네임스페이스를 지우자 마스터가 내려갔다.

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

    발표자는 그 전부터 이미 징후가 있었다고 했다. 마스터가 내려간 뒤에는 Slack에 경보가 많이 들어왔지만, 인증도 port-forward도 되지 않아 모니터링에는 들어갈 수 없었다.

    조치
    • kill-kube-ns 도구로 API를 직접 호출해 dex 네임스페이스에 남은 kubernetes finalizer를 지웠다.
    • dex를 적절한 기본값으로 설정해 새 네임스페이스에 다시 배포했다.
    교훈

    외부 도구의 기본값을 그대로 믿지 않는다. 목록 조회도 안 될 만큼 쌓인 리소스를 네임스페이스 삭제로 치우면 정리 루프가 타임아웃과 재시도를 반복해 마스터를 내릴 수 있다. 클러스터 인증이 클러스터 안에 있으면 클러스터가 죽었을 때 모니터링에도 들어갈 수 없다. API로 finalizer를 직접 지우는 방법은 발표자도 절대 하지 말라고 한 마지막 수단이다.

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

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

원인별3