Code Place를 운영하던 중 PostgreSQL 인스턴스가 정상적으로 실행되지 않는 상황을 겪었다. 처음에는 DB 자체 문제처럼 보였다. CNPG 상태에는 인스턴스가 활성화되지 않았다는 메시지가 보였고, system ID를 보고하지 못했다는 메시지도 함께 나왔다.
하지만 Kubernetes 이벤트와 Longhorn 상태를 함께 확인하니 단순히 PostgreSQL만의 문제로 보기 어려웠다. DB도 이상해 보이고, PVC도 비정상적으로 보였으며, Longhorn 볼륨에도 다른 단서가 있었다.
이럴 때 가장 위험한 건 원인을 너무 빨리 하나로 찍는 일이라고 생각했다. 그래서 DB, Kubernetes, Longhorn, 노드 레이어를 나눠서 확인했다. 이 글은 그 장애를 어떤 순서로 좁혀갔는지 정리한 기록이다.
처음 보인 문제
가장 먼저 눈에 띈 것은 CNPG 상태 메시지였다.
Detected low-disk space condition, avoid starting the instanceWaiting for the instances to become activeInstances are present, but none have reported a system ID- 상황에 따라
Dangling PVC처럼 보이는 상태
처음 보면 PostgreSQL 인스턴스 자체가 잘못된 상태라고 생각하기 쉬운 메시지였다. 저도 처음에는 PostgreSQL 내부 문제를 먼저 떠올렸다.
하지만 여기서 바로 Pod를 재시작하거나 오퍼레이터를 다시 올리지는 않았다. 원인 확인 없이 증상만 바꿀 가능성이 더 컸기 때문이다.
운영 환경
환경은 k3s 기반 멀티 노드 클러스터였고, PostgreSQL은 CloudNativePG(CNPG)로 운영하고 있었다. 영속 스토리지는 Longhorn을 사용했다.
이 조합은 평소에는 각자 자기 역할을 잘 하지만, 한 번 문제가 생기면 확인 범위가 빠르게 넓어진다. DB가 안 뜬다고 해서 DB만 확인하면 끝나는 구조가 아니었다. Kubernetes, CNPG, PVC, Longhorn 볼륨, 실제 노드의 장치 상태까지 함께 확인해야 했다.
처음 세운 가설
처음에는 대략 세 가지 가능성을 두고 확인했다.
- PostgreSQL 인스턴스 자체 상태가 깨져서 정상 기동이 안 되는 경우
- CNPG가 PVC나 볼륨 상태를 정상으로 보지 못해 인스턴스를 실행하지 못하는 경우
- 실제 원인은 Longhorn 계층인데, 그 결과가 CNPG 상태 이상으로 드러나는 경우
어떤 가설이 더 가능성 있어 보이는지보다, 어느 레이어에서 실제로 막히는지를 분리해서 확인하는 일이 더 중요했다.
원인을 확인한 과정
이 문제에서 가장 먼저 한 일은 장애를 단순히 "DB 문제"로 묶지 않는 것이었다. 대신 아래처럼 레이어를 나눠 확인했다.
- CNPG 레이어: 클러스터 상태 메시지, primary/replica 인식, 인스턴스 활성화 여부
- Kubernetes 레이어: Pod 이벤트, PVC 상태, volume attachment, mount 실패 여부
- Longhorn 레이어: replica 상태, 볼륨 확장, share-manager 상태, 디스크 스케줄링 가능 여부
- 노드/리눅스 레이어: 실제 마운트 충돌, 장치 사용 상태, 시스템 프로세스 간섭 여부
이렇게 나눠 확인하니, CNPG 메시지는 원인이라기보다 결과일 수도 있다는 판단이 가능했다.
CNPG 메시지를 다시 읽었다
예를 들어 system ID를 보고하지 못했다는 것은 PostgreSQL 인스턴스가 정상 기동까지 가지 못했다는 뜻이다. 하지만 그 이유가 꼭 PostgreSQL 내부 손상이라고 단정되지는 않는다.
데이터를 올려야 할 스토리지가 정상적으로 연결되지 않아 기동이 끝까지 가지 못했을 수도 있었다. 그래서 이 상태를 보고는 "DB가 왜 깨졌지"보다 "DB가 왜 여기서 멈췄지"라는 관점으로 확인했다.
low-disk condition도 마찬가지였다. 실제 디스크가 부족한지, PVC 확장 상태에 문제가 있는지, Longhorn에서 볼륨을 정상적으로 사용할 수 없는지까지 함께 확인해야 했다.
오퍼레이터의 메시지는 중요하다. 다만 그 메시지를 곧바로 원인으로 단정하면 안 된다.
스토리지 계층에서 나온 단서
스토리지 계층을 확인하기 시작하자 CNPG보다 아래 레이어를 더 의심할 만한 단서가 늘어났다.
- PVC 확장 작업은 일부 성공한 것처럼 보였다.
- 그런데도 CNPG는 인스턴스를 활성화하지 못했다.
- Longhorn에서는 replica 스케줄링 문제, share-manager 이상, mount 관련 충돌 흔적이 보였다.
여기서 핵심은 "리소스가 있다"와 "실제로 그 리소스를 쓸 수 있다"가 다르다는 점이었다.
PVC가 Bound라고 해서 실제 워크로드가 그 볼륨을 문제없이 mount해 쓰고 있다는 뜻은 아니었다. 볼륨 확장이 끝났다고 해서 attach나 mount까지 다 끝난 것도 아니었다.
이 시점부터는 CNPG가 기동하지 않는 이유를 DB 내부보다 스토리지 레이어에서 더 집중적으로 찾았다.
원인을 좁혀간 순서
실제로는 아래 순서로 생각이 바뀌었다.
1. DB 자체가 깨졌다고 단정하지 않았다
처음부터 PostgreSQL 내부 상태만 의심하지 않았다. 오퍼레이터 상태 메시지와 스토리지 상태를 함께 확인했다. DB가 실행되지 않는 것은 맞지만, DB가 원인이라고 단정하기에는 아래 레이어의 단서가 너무 많았다.
2. PVC가 있는지보다 실제로 쓸 수 있는지를 봤다
PVC가 있고 확장도 됐다는 사실보다, 그 볼륨이 attach·mount까지 정상적으로 되는지를 더 집중적으로 확인했다. Kubernetes에서는 리소스 상태가 정상처럼 보여도 실제 노드에서 장치 상태에 문제가 있을 수 있다.
3. Longhorn 상태를 원인 후보로 확인했다
replica 스케줄링, share-manager 이상, mount 충돌 같은 단서가 쌓이면서 DB보다 스토리지 레이어에서 먼저 막혔을 가능성이 커졌다.
4. CNPG 메시지를 결과로 읽기 시작했다
low-disk condition, system ID 미보고, 인스턴스 비활성 같은 메시지를 각각 따로 보지 않았다. 아래 스토리지 이상이 위로 올라오면서 CNPG 상태 이상으로 드러난 결과라고 보고 다시 연결했다.
이쯤 되니 처음에는 "PostgreSQL이 안 뜬다"였던 문제가, 나중에는 "PostgreSQL이 기동하려면 먼저 스토리지가 정상적으로 연결되어야 한다"는 문제로 바뀌었다.
정리한 기준
이번 일을 겪고 나서 확인한 것은, 오퍼레이터가 상태를 잘 보여준다고 해서 원인까지 바로 드러나는 것은 아니라는 점이었다.
CloudNativePG도 Longhorn도 많은 것을 자동화해준다. 하지만 자동화 계층이 많을수록 상태 메시지를 더 조심해서 읽어야 했다.
이후로는 비슷한 상황에서 아래 순서로 먼저 확인한다.
- CNPG 상태 메시지를 본다.
- Kubernetes 이벤트와 PVC 상태를 함께 확인한다.
- Longhorn의 replica, share-manager, volume scheduling 상태를 확인한다.
- 필요하면 노드 레벨에서 실제 장치와 mount 상태까지 내려간다.
- 그 다음에야 PostgreSQL 내부 복구 여부를 판단한다.
마무리
이번 일은 장애를 확인하는 순서를 다시 잡는 계기였다. 예전에는 DB 인스턴스가 비정상처럼 보이면 DB부터 의심했지만, 이제는 그 상태를 만든 하위 레이어를 먼저 함께 확인한다.
운영 장애는 한 줄짜리 에러 메시지로 깔끔하게 정리되지 않는 경우가 많았다. 여러 레이어에 흩어진 단서를 함께 확인해야 원인 범위가 좁혀졌다. 이번 일은 그 점을 명확히 확인한 사례였다.