관리형 DB 없이 PostgreSQL을 클러스터 안에 직접 두기로 한 이유
외부 관리형 DB 대신 CloudNativePG 오퍼레이터로 PostgreSQL+PostGIS를 클러스터 안에서 직접 운영하기로 한 선택과, 오퍼레이터가 대신 떠맡아주는 것들.
문제: 관리형 DB를 쓰지 않는다면, 그 몫은 누가 지나?
MSA 전환 과정에서 DB는 관리형 서비스를 쓰지 않고 클러스터 안에 직접 두기로 했다. 이유는 온프레미스·하이브리드 환경 특성상 외부 관리형 DB에 대한 의존을 최소화하고, PostGIS(공간 데이터 확장)를 포함한 구성을 클러스터 라이프사이클 안에서 함께 관리하기 위해서였다.
문제는 "관리형 DB를 안 쓴다"고 선언하는 순간, 관리형 DB가 자동으로 해주던 것들 - 장애 시 자동 failover, 백업 스케줄링, 복제본 관리 - 을 직접 구현해야 한다는 뜻이 된다는 것이다. PostgreSQL을 그냥 파드 하나로 띄우면 이런 것들이 전혀 없다. 파드가 죽으면 DB가 죽고, 백업은 누군가 크론잡을 만들어야 하고, 복제본을 두려면 복제 설정과 장애 전환 로직을 직접 짜야 한다.
시도한 것: 오퍼레이터에게 "PostgreSQL 운영"을 맡기기
Kubernetes Operator 패턴은 사람이 반복적으로 하던 운영 작업(failover 판단, 백업 실행, 복제본 승격)을 컨트롤러 코드로 대신하게 하는 것이다. CloudNativePG는 PostgreSQL 전용 오퍼레이터로, Cluster라는 커스텀 리소스 하나를 선언하면 그 뒤의 운영을 대신 맡는다.
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: nipa-postgres
spec:
instances: 3 # 프라이머리 1 + 레플리카 2
postgresql:
parameters:
shared_preload_libraries: "postgis"
storage:
size: 100Gi
backup:
retentionPolicy: "30d"
이 선언 하나로 CloudNativePG가 떠맡는 일:
- 자동 failover: 프라이머리 인스턴스에 장애가 감지되면, 정상 상태의 레플리카 중 하나를 새 프라이머리로 승격하고 나머지를 그 아래로 재구성한다. 사람이 개입해서 "어느 걸 프라이머리로 올릴지" 판단할 필요가 없다.
- 선언적 백업: 백업 주기·보존 기간을 스펙에 선언하면 별도 크론잡 없이 오퍼레이터가 스케줄링부터 실행까지 담당한다.
- 롤링 업그레이드: PostgreSQL 버전을 올릴 때도 레플리카부터 순차적으로 갱신하고 마지막에 프라이머리를 전환하는 식으로, 오퍼레이터가 무중단에 가까운 절차를 대신 수행한다.
- PostGIS 포함 구성 관리: 공간 데이터 확장(PostGIS)이 필요한 이 프로젝트 특성상, 확장 모듈이 포함된 이미지·파라미터 구성도
Cluster스펙 안에서 함께 선언된다.
결과
관리형 DB를 쓰지 않기로 한 선택이 "운영 부담을 직접 짊어지겠다"는 뜻은 아니게 됐다. CloudNativePG 덕분에 "관리형 DB가 자동으로 해주던 것"의 상당 부분이 클러스터 안에서 선언적으로 재현된다 - 다만 그 선언과 실행의 책임이 외부 클라우드 사업자에서 클러스터 안의 오퍼레이터로 옮겨왔을 뿐이다.
이 선택의 트레이드오프도 분명하다. 오퍼레이터 자체의 장애나 버그는 이제 우리가 감당해야 할 몫이고, 클러스터 인프라(스토리지, 노드) 상태가 곧 DB 가용성에 직결된다. 하지만 온프레미스·하이브리드 환경에서 외부 관리형 DB에 대한 의존을 최소화하면서도, "DB를 손으로 운영한다"는 부담까지 짊어지지 않는 절충점으로는 이 구조가 맞다고 판단했다.