본문으로 건너뛰기

11.2 트러블슈팅

문제가 생겼을 때 무엇을 어떤 순서로 봐야 할까요? CloudNativePG 트러블슈팅은 두 층을 오갑니다. 하나는 Kubernetes 층 — Pod가 스케줄되었는가, 볼륨이 붙었는가, 이벤트에 무슨 경고가 있는가. 다른 하나는 PostgreSQL 층 — postgres가 떴는가, 로그에 FATAL이 있는가, 복제가 따라오는가. 증상만 보고 한쪽만 파면 원인을 놓칩니다.

진단 분기​

1단계: 정보 수집​

가장 먼저 클러스터 상태를 봅니다. 대부분의 문제는 여기서 방향이 잡힙니다.

kubectl cnpg status -n <NS> <CLUSTER>

상태만으로 부족하면 Cluster 리소스와 Pod를 직접 들여다봅니다.

kubectl get cluster -n <NS> <CLUSTER>
kubectl describe cluster <CLUSTER> -n <NS>

# 인스턴스별 역할 확인
kubectl get pod -l cnpg.io/cluster=<CLUSTER> -L cnpg.io/instanceRole -n <NS>

Operator 자체가 의심되면 cnpg-system 네임스페이스의 컨트롤러를 봅니다.

kubectl get pods -n cnpg-system
kubectl logs -n cnpg-system deployment/cnpg-controller-manager --all-containers=true

지원 요청까지 갈 상황이면 kubectl cnpg report로 자료를 한 번에 묶습니다(11.1).

2단계: 로그 읽기​

Pod 로그는 JSON lines입니다. 그냥 보면 잡음이 많으므로 jq로 PostgreSQL 메시지만 걸러 냅니다.

# postgres 로거 메시지만
kubectl logs -n <NS> <CLUSTER>-<N> | \
jq 'select(.logger=="postgres") | .record.message'

# FATAL만
kubectl logs -n <NS> <CLUSTER>-<N> | \
jq -r '.record | select(.error_severity == "FATAL")'

# 직전 크래시 로그
kubectl logs -n <NS> --previous <CLUSTER>-<N>

--previous는 Pod가 재시작을 반복(CrashLoopBackOff)할 때 특히 중요합니다. 지금 뜬 컨테이너가 아니라 죽기 직전 컨테이너의 로그를 봐야 원인이 나옵니다.

노트

필수 도구 세 가지를 미리 갖춰 둡니다 — cnpg 플러그인, jq(JSON 로그 파싱), grep. 그리고 문제 진단에 들어가기 전에 반드시 백업 상태를 먼저 확인합니다. PVC 삭제 같은 파괴적 조치를 취하기 전에 복구 지점이 살아 있는지 아는 것이 순서입니다.

흔한 문제​

Pod가 Pending에서 멈춤​

  • 증상: Pod가 Pending으로 뜨지 않고 대기
  • 원인: nodeSelector 불일치, toleration 누락, 노드 부족, autoscaler 한계

대응: 이벤트에서 스케줄 실패 사유를 읽습니다.

kubectl describe pod -n <NS> <POD>
kubectl get events -n <NS> --sort-by=.metadata.creationTimestamp

FailedScheduling 메시지에 원인이 그대로 적힙니다. nodeSelector·taint 설정(Part V)과 노드 여유 자원을 대조합니다.

스토리지 가득 참​

  • 증상: Pod가 쓰기 실패, disk-full 메시지로 crash-loop
  • 원인: PVC 용량 소진

대응: PVC의 spec.resources.requests.storage를 늘린 뒤, Cluster 리소스의 storage 크기도 같은 값으로 맞춥니다. storage class가 volume expansion을 지원해야 합니다.

replica가 동기화 안 됨 (백업 미구성)​

  • 증상: 유지보수 후 replica 재시작 시 따라오지 못함
  • 원인: primary에 이미 재활용된 WAL을 replica가 요구

대응: 해당 replica의 PVC를 지우면 Operator가 primary에서 새로 base backup을 받아 재구성합니다.

PODNAME=<POD>
VOLNAME=$(kubectl get pv -o json | \
jq -r '.items[]|select(.spec.claimRef.name=='\"$PODNAME\"')|.metadata.name')
kubectl delete pod/$PODNAME pvc/$PODNAME pvc/$PODNAME-wal pv/$VOLNAME
경고

이 조치는 primary가 아니라 replica에만 합니다. primary의 PVC를 지우면 데이터가 사라집니다. 삭제 전 cnpg status로 대상 Pod가 replica인지 반드시 확인합니다. object store 백업이 구성돼 있으면 애초에 이 문제가 잘 생기지 않습니다.

동기화가 끊긴 replica 재구성 전 안전 확인 순서

Pod 간 통신 실패 (NetworkPolicy)​

  • 증상: Operator 로그에 "Cannot extract Pod status" 또는 "i/o timeout"
  • 원인: NetworkPolicy가 상태 포트(보통 8000)를 막음

대응: NetworkPolicy를 점검해 Operator와 Pod 사이 포트를 엽니다.

kubectl get networkpolicies -n <NS>

"Creating new replica"에서 오래 멈추거나 "HTTP communication issue"가 보이는 것도 대개 같은 네트워크 원인입니다.

hugepages 초기화 오류​

  • 증상: 초기화 중 "Bus error (core dumped) ... exit code 135"
  • 원인: hugepages 지원이 불완전

대응: 리소스에 hugepages 한계를 명시합니다.

resources:
limits:
hugepages-2Mi: "512Mi"

failover 후 standby 재접속이 느림​

  • 증상: primary 전환 뒤 standby가 2분 이상 재접속 못 함
  • 원인: kube-proxy 경로 갱신 지연 + 커널 TCP 재시도 backoff

대응: Operator 설정에서 STANDBY_TCP_USER_TIMEOUT을 조정해 죽은 연결을 더 빨리 끊게 합니다.

백업·아카이빙 확인​

백업 상태와 WAL archiving은 조건(condition)으로 확인합니다.

kubectl get backup -l cnpg.io/cluster=<CLUSTER>

kubectl wait --for=condition=LastBackupSucceeded cluster/<CLUSTER> -n <NS>
kubectl wait --for=condition=ContinuousArchiving cluster/<CLUSTER> -n <NS>

세 가지 핵심 조건을 기억해 둡니다.

조건의미
Ready클러스터 초기화 완료, primary 준비됨
ContinuousArchivingWAL archiving 정상 동작
LastBackupSucceeded마지막 백업 성공 여부

비상 시 논리 백업·복구​

물리 백업 경로가 막힌 급박한 상황에서는 Pod 안에서 직접 pg_dump·pg_restore를 돌릴 수 있습니다.

# 논리 백업
kubectl exec cluster-example-1 -c postgres -- \
pg_dump -Fc -d app > app.dump

# 새 클러스터로 복구
kubectl exec -i new-cluster-example-1 -c postgres -- \
pg_restore --no-owner --role=app -d app --verbose < app.dump

이것은 어디까지나 임시 수단입니다. 정규 복구는 Part VII의 object store·PITR 경로를 따릅니다.

정리​

  • 진단 순서 = cnpg status → Kubernetes 층(describe·events) 또는 PostgreSQL 층(logs)
  • 로그는 JSON — jq로 postgres·FATAL만 걸러 읽고, crash-loop은 --previous
  • Pending은 스케줄링, disk-full은 PVC 확장, replica 깨짐은 PVC 재구성(primary 금지), 통신 오류는 NetworkPolicy·포트 8000
  • 파괴적 조치 전 백업 상태(Ready·ContinuousArchiving·LastBackupSucceeded)부터 확인