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

사례2건

2건 중 1~2번째

  1. 증상

    모니터링과 알림이 곧바로 울렸다. 알림 하나는 Patroni 페일오버를 가리켰다. GitLab.com 으로 가는 트래픽은 모두 5XX 오류로 끝났다.

    촉발

    엔지니어가 로컬 개발 환경에서 사내 도구로 일상적인 작업을 돌렸다. 로컬 배포나 롤백 도중 컨텍스트가 로컬 개발에서 운영으로 바뀌었고, 이때 잘 알려진 오픈소스 도구가 예상하지 못한 동작을 해 운영 환경에 변경이 들어갔다.

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

    모니터링과 알림 인프라가 곧바로 경보를 보냈다. 팀은 Consul 클러스터가 내려가 Patroni 클러스터에 영향을 주자마자 큰 장애가 난 것을 알았고, 근본 원인도 몇 분 안에 찾았다.

    조치
    • 지워진 Consul 릴리스를 운영에 다시 적용했다. Consul 클러스터가 올라오자 데이터베이스 클러스터가 회복했다.
    후속 조치
    • Kubernetes 배포 방식을 개선해 로컬 환경에서 운영 환경을 대상으로 위험한 배포 작업이 돌아갈 가능성을 줄인다. 개념 검증은 reliability 이슈 16875 에서 진행한다.
    • Teleport 를 Kubernetes 클러스터와 연동한다. 이렇게 하면 SRE 에게 기본으로 읽기 전용 역할을 줄 수 있어 실수로 운영 환경을 바꿀 위험이 줄어든다.
    교훈

    로컬 개발 환경에서 운영 클러스터에 접근할 수 있으면 도구가 컨텍스트를 예상과 다르게 바꾸는 순간 일상 작업이 운영 장애가 된다. GitLab 은 Kubernetes 배포 방식을 개선하고, Teleport 로 SRE 의 기본 권한을 읽기 전용으로 둘 수 있게 하면 이런 위험이 크게 줄어든다고 봤다. 알림과 원인 파악은 빨랐다. 지워진 릴리스를 다시 배포하는 데는 손으로 해야 할 일이 있었지만 비교적 빨리 끝났다.

  2. 증상

    새벽 1시쯤 DataHub 에 로그인하려는 사용자가 프록시 오류를 받았다. hub 파드는 떠 있었지만 로그가 sqlite 오류로 가득했다.

    촉발

    엔지니어가 앞서 난 400 오류를 디버깅하려고 hub 파드 안에서 sqlite3 를 다시 열고, 데이터베이스를 ATTACH 하지 않은 채 .save jupyterhub.sqlite 를 실행했다. 이 명령이 JupyterHub 데이터베이스 파일을 빈 데이터베이스로 덮어썼다.

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

    새벽 1시쯤 DataHub 가 다운됐다는 신고가 들어왔다. 1:12 에는 한 사용자가 로그인은 되지만 노트북이 모두 사라졌다고 알렸다.

    조치
    • hub 파드의 replicas 를 0으로 줄여 hub 를 내렸다.
    • 쿠버네티스 PVC 를 사용자 id 와 다시 짝지어 JupyterHub sqlite 데이터베이스를 다시 만들었다. PVC 이름에 정리된 사용자 이름과 사용자 id 가 들어 있어서 할 수 있었다.
    • 처음 넣은 가짜 cookie_id 값을 null 로 바꾸고, sqlite 파일을 DataHub 에 다시 붙였다.
    • 모든 사용자를 로그아웃시키려고 hub 파드의 /srv/jupyterhub/jupyterhub_cookie_secret 을 바꿨다. 끝 근처 한 글자를 바꿨을 때는 효과가 없었고, 앞쪽 한 글자를 바꾸고 재시작하자 모두 로그아웃됐다.
    • 사용자 파드를 모두 지워 모든 사용자를 확실히 로그아웃시켰다.
    • 모든 사용자의 cookie_id 를 채우는 스크립트를 돌렸고, 메모리에 남은 오래된 캐시를 없애려고 hub 를 재시작한 뒤 사용자 파드를 다시 모두 지웠다.
    • 이름에 '.' 이 들어간 새 사용자를 지우고, 이름에 '-' 가 있는 모든 사용자의 '-' 를 '.' 으로 바꾸는 스크립트를 돌렸다.
    후속 조치
    • JupyterHub 가 cookie secret 의 일정 길이만 쓰고 나머지를 버려서, 로그아웃시키려고 값을 바꿀 때 혼란이 생긴다는 문제를 JupyterHub 에 보고한다.
    • users 테이블의 cookie_id 열에 UNIQUE 와 NOT NULL 제약을 두자고 JupyterHub 에 제안한다.
    • 데이터베이스가 지워져도 파드와 PVC 이름이 그대로 남도록, 이름에 사용자 id 대신 사용자 이름 해시를 쓰는 기능을 KubeSpawner 에 요청한다.
    • 사용자 테이블의 id 를 Google 인증이 주는 'id' 와 같게 두어, 처음 로그인한 때와 상관없이 사용자 id 가 바뀌지 않게 하는 기능을 OAuthenticator 에 요청한다.
    • 관리형 MySQL 서비스인 Google Cloud SQL 로 옮긴다.
    • 데이터베이스를 정기적으로 백업하고 그 백업을 시험한다.
    • 해야 할 일과 하지 말아야 할 일을 담은 운영 FAQ 를 쓰기 시작한다.
    • 모니터링과 호출 체계를 개선한다.
    • 에스컬레이션 절차를 분명하게 문서로 남긴다.
내 클러스터에도 있는지 확인하기

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

원인별1