Incident Library

IL-0506 UC Berkeley · 2017-02-09kubernetesdatabase

UC Berkeley DataHub 의 JupyterHub sqlite 데이터베이스가 빈 데이터베이스로 덮어써져 로그인이 실패하고 홈 디렉터리가 비어 보이고 다른 사용자로 로그인되는 문제가 났다

2017년 2월 9일 0:25 무렵, 엔지니어가 앞서 난 400 오류를 디버깅하려고 hub 파드에서 sqlite3 로 servers 테이블의 ip 와 base_url 을 일부러 틀리게 바꿔 봤다. 바뀐 것이 없어 보이자 새 sqlite3 세션에서 .save jupyterhub.sqlite 를 실행했고, 먼저 ATTACH 를 하지 않았기 때문에 JupyterHub sqlite 데이터베이스가 빈 데이터베이스로 덮어써졌다. 나중에 로컬에서 sqlite3 의 .save <filename> 이 확인 없이 파일을 덮어쓴다는 것을 확인했다.

테이블이 모두 사라지자 hub 는 sqlite 오류를 냈고 사용자는 프록시 오류를 받았다. 로그인한 사용자는 새 사용자 id 를 받았고, 그 때문에 새 빈 디스크가 만들어졌다. 1:28 에 hub 파드의 replicas 를 0으로 줄이고, PVC 이름에 담긴 사용자 이름과 사용자 id 를 짝지어 데이터베이스를 다시 만들었다. 2:42 에 다시 만든 데이터베이스를 붙이자 관리자 화면의 사용자 수가 1000명쯤으로 돌아왔다.

다시 만든 데이터베이스에서는 여러 사용자의 cookie_id 가 비어 있었다. 이 사용자들은 id 순으로 맨 앞에 있고 cookie_id 가 빈 사용자 한 명의 노트북으로 로그인됐다. 10:11 에 cookie secret 을 바꿔 모두 로그아웃시키려 했는데, 끝 근처 글자를 바꿨을 때는 효과가 없었고 앞쪽 글자를 바꾸자 로그아웃됐다. JupyterHub 는 cookie secret 의 일정 길이만 쓰고 나머지를 버렸다. 10:45 에 모든 사용자의 cookie_id 를 채우고 hub 를 재시작한 뒤 사용자 파드를 다시 모두 지우자 대부분의 사용자가 돌아왔다.

이름에 '.' 이 들어간 사용자는 옛 레코드에 '.' 대신 '-' 가 들어가 있었고, 로그인하면서 '.' 이 들어간 새 사용자가 생겨 빈 PVC 를 받았다. 11:15 에 '.' 이 들어간 새 사용자를 지우고 '-' 를 '.' 으로 바꾸는 스크립트를 돌렸고, 11:17 에 DataHub 가 모두 복구됐다고 알렸다. 그 사이 학생들에게 ds8.berkeley.edu 를 쓰라는 안내가 나갔지만, ds8.berkeley.edu 는 data8 규모 수업을 감당할 자원이 없어 곧 다운됐다.

심각도
–
영향 범위
UC Berkeley DataHub: logins failed with proxy errors, users saw empty home directories, and some were logged in as another user
영향 사용자
DataHub users, about 1000 accounts
지역
–
감지까지
35m
복구까지
10h 52m

증상

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

hub 로그의 오류는 sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: proxies [SQL: 'SELECT proxies.id AS proxies_id, proxies._public_server_id AS proxies__public_server_id, proxies._api_server_id AS proxies__api_server_id \nFROM proxies \nWHERE proxies.id = ?'] [parameters: (1,)] 였다. 가장 자주 쓰이는 hub 테이블에도 같은 오류가 이어졌다.

1:12 에 한 사용자가 로그인은 되지만 노트북이 모두 사라졌다고 알렸다. JupyterHub 관리자 화면의 사용자는 1000명쯤에서 50명쯤으로 줄어 있었다. 사용자 데이터베이스가 지워져서 hub 가 로그인한 사용자를 새 계정으로 만들었다. hub 는 예전 디스크를 찾지 못해 새 영구 디스크를 만들었고, 그래서 홈 디렉터리가 비어 보였다.

kubectl --namespace=datahub get pvc 로 보면 같은 사용자의 PVC 가 claim-<username>-257 과 claim-<username>-51 두 개였고, 뒤의 것은 만든 지 5분밖에 되지 않았다.

데이터베이스를 다시 만든 뒤에도 일부 사용자가 로그인하면 특정 사용자 한 명의 계정으로 들어갔다. cookie secret 을 바꿔 모두 로그아웃시키고 사용자 파드를 모두 지워도 계속됐다.

다른 사용자가 모두 정상이 된 뒤에도 이름에 '.' 이 들어간 사용자는 빈 홈 디렉터리를 받았다.

증상 서비스 중단데이터 유실요청 오라우팅

원인

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

감지

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

조치

후속 조치

교훈

–

출처

참고 문서

관련 사례

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

kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이 사례와 같은 상태를 점검합니다. 이 사례의 구성 요소: 데이터베이스, 영구 볼륨과 스테이트풀셋, JupyterHub. 점검 항목의 근거는 이 사례 같은 공개 보고서입니다.

AI 도구와 스크립트용

API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.