IL-0063 AdGuard VPN · 2025-12-02kubernetes
AdGuard VPN 의 핵심 구성 요소인 Redis 는 쿠버네티스 스테이트풀셋으로 돈다. 스테이트풀셋의 저장소는 volumeClaimTemplates 로 정의하는데, 한 번 만들면 이 템플릿을 고쳐 디스크 크기를 늘릴 수 없다. 2025년 12월 2일 디스크 여유 공간이 바닥나고 있다는 알림이 오자, 팀은 저장소가 지원하는 온라인 볼륨 확장으로 PVC 를 직접 늘렸다. 7:00 UTC 에 Git 의 디스크 크기를 올렸고, 7:05 UTC 에 모든 PVC 의 크기를 손으로 바꿨고, 7:10 UTC 에 모든 파드의 온라인 확장이 끝났다. 디스크 문제는 재시작 없이 풀렸다.
그러나 Git 과 스테이트풀셋 템플릿에는 여전히 옛 크기가 적혀 있었다. 이 차이를 없애려고 팀은 8:10 UTC 에 스테이트풀셋을 고아 삭제하고 새 템플릿으로 다시 만들었다. 파드와 디스크는 그대로 두고 관리 객체만 바꾸니 안전하리라 보았다. 하지만 쿠버네티스는 이미 바뀐 것이 다 반영된 줄 모르고 새 스펙에 따라 워크로드를 다시 조정하면서 Redis 클러스터 전체를 재시작했다.
쿠버네티스는 재시작을 너무 서둘렀다. 스타트업 프로브도 레디니스 프로브도 없어서 파드가 running 이기만 하면 정상으로 취급되었다. 그래서 쿠버네티스는 Redis 가 실제로 요청을 받을 수 있게 되기 전에 다음 파드로 넘어갔다. 그 결과 클러스터 일부가 망가진 채 올라왔다. 팀은 마스터에서 쓸모없어진 노드 ID 를 지우고, 해당 레플리카를 리셋하고, 다시 클러스터에 붙여 복제가 따라잡기를 기다렸다. 이 작업이 예상보다 오래 걸리는 동안 백엔드 서비스가 재연결 폭주로 OOM 에 빠졌다.
팀은 처음에 OOM 이 난 구성 요소를 잘못 짚었고, 남은 용량이 부족해 확장도 늦어졌다. OOM 이 난 구성 요소를 제대로 찾은 뒤 백엔드를 늘리고, 그 구성 요소의 메모리 한도를 올리고, 프로브를 잠시 느슨하게 해 인스턴스가 바로 서비스에 들어가게 했다. 다운타임은 8:10 부터 9:00 UTC 까지 약 50분이었다. 10:00 UTC 에 비상용 임시 조치를 되돌렸고 서비스가 완전히 정상으로 돌아왔다.
8:10 UTC 에 팀은 Redis 스테이트풀셋을 고아 삭제했다. 고아 삭제는 파드와 디스크는 그대로 두고 스테이트풀셋 객체만 지우는 방식이다. 스테이트풀셋을 다시 만들자 쿠버네티스가 8:10 부터 8:15 UTC 사이에 스테이트풀셋 전체를 빠르게 재시작했다. 처음에는 백엔드 서비스가 Redis 연결 오류를 냈지만 서비스 전체가 곧바로 무너지지는 않았다.
재시작이 끝나자 Redis 클러스터 일부가 망가진 채 올라왔다. 일부 레플리카가 클러스터에 제대로 다시 붙지 못했고, 자신이 어느 마스터에 속하는지 옛 정보를 그대로 갖고 있었다.
8:15 부터 8:35 UTC 까지 Redis 클러스터를 손으로 복구하는 동안, 백엔드 서비스는 재연결 폭주와 늘어난 부하를 받았고 OOM 오류가 연쇄적으로 났다. 팀은 처음에 어느 구성 요소가 OOM 으로 죽는지 잘못 짚었다. 백엔드를 늘리려 해도 남은 용량이 부족해 늦어졌다.
파드가 ready 가 되면 곧바로 트래픽이 몰려 다시 not ready 로 돌아갔고, 그만큼 다음 파드에 부하가 쏠리는 일이 되풀이되었다. 8:35 부터 8:50 UTC 까지 OOM 오류를 잡은 뒤 서비스는 응답이 느린 채로 돌아왔다.
원인 ? 설정 변경
Redis 클러스터 여러 인스턴스의 디스크 여유 공간이 바닥나고 있다는 알림이 시작이었다. 그 뒤의 장애는 스테이트풀셋을 다시 만든 직후 백엔드 서비스가 Redis 연결 오류를 내면서 드러났다.
장애를 일으킨 것은 디스크 확장이 아니라 상태를 맞추려고 컨트롤러 객체를 다시 만든 단계였다. 고칠 수 없는 필드가 있으면 객체를 통째로 바꾸는 위험한 방법을 쓰게 된다. 그렇게 바꾸면 쿠버네티스가 워크로드를 넓은 범위에서 다시 조정할 수 있다. 스타트업 프로브와 엄격한 레디니스 프로브가 있어야 롤링 재시작이 현재 파드가 정말 준비될 때까지 기다린다. 이번 장애에서 가장 뼈아픈 것은 프로브가 없었다는 점이다. 분산 클러스터가 다시 붙고 복제를 따라잡는 데는 시간이 걸리므로, 의존하는 서비스는 그동안 기능을 줄여서라도 버티도록 설계해야 한다.
같은 원인 · 공통 컨테이너 메모리 한도
같은 원인 · 공통 영구 볼륨과 스테이트풀셋
같은 원인 · 공통 컨테이너 메모리 한도