5.1 Storage
PostgreSQL은 상태를 가진 워크로드다. Pod가 재시작되거나 다른 노드로 옮겨가도 데이터는 그대로 살아 있어야 한다. Kubernetes에서 이 영속 스토리지를 표현하는 리소스가 PersistentVolumeClaim(PVC)이다. CloudNativePG는 인스턴스마다 PVC를 하나씩(또는 WAL·tablespace를 분리하면 여러 개) 만들어 PostgreSQL의 데이터 디렉토리 PGDATA를 담는다.
CNPG가 StatefulSet을 쓰지 않고 각 인스턴스를 개별 Pod와 PVC로 직접 관리한다는 점은 앞서 짚었다. 스토리지 관점에서 이 선택의 결과가 여기서 드러난다. Operator가 PVC의 생성·확장·재부착을 직접 통제하므로, failover나 노드 이동 시에도 어느 볼륨을 어느 인스턴스에 붙일지 세밀하게 제어할 수 있다.
PVC와 StorageClass
.spec.storage에 크기와 StorageClass만 지정하면 나머지는 Operator가 처리한다.
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: postgresql-storage-class
spec:
instances: 3
storage:
storageClass: standard
size: 1GiStorageClass는 “어떤 종류의 볼륨을 어떻게 프로비저닝할지"를 정의하는 Kubernetes 리소스다. 클라우드라면 gp3·premium SSD 같은 디스크 타입, 온프레미스라면 Ceph·Longhorn 같은 스토리지 백엔드에 대응한다. storageClass를 생략하면 클러스터의 기본 StorageClass가 쓰인다.
flowchart TD
CL[Cluster 리소스] --> OP[CNPG Operator]
OP --> PVC[PVC 생성]
PVC --> SC[StorageClass]
SC --> PROV[프로비저너]
PROV --> PV[(PersistentVolume)]
PV --- POD[PostgreSQL Pod]
더 세밀한 제어가 필요하면 pvcTemplate로 PVC 전체를 직접 기술한다. accessMode나 volumeMode까지 지정해야 하는 경우다.
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: postgresql-pvc-template
spec:
instances: 3
storage:
pvcTemplate:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: standard
volumeMode: FilesystemWAL을 별도 볼륨으로 분리
WAL(Write-Ahead Log)은 모든 변경을 먼저 기록하는 순차 쓰기 로그다. 데이터 파일에 대한 랜덤 쓰기와 WAL의 순차 쓰기가 같은 볼륨에서 경합하면 I/O 특성이 서로 다른 두 작업이 서로를 방해한다. walStorage를 선언하면 WAL을 전용 PVC로 떼어낸다.
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: separate-pgwal-volume
spec:
instances: 3
storage:
size: 1Gi
walStorage:
size: 1GiWAL을 분리하면 얻는 것은 다음과 같다.
- 성능: 데이터와 WAL의 I/O를 병렬로 처리해 경합을 줄인다.
- 안정성:
PGDATA볼륨이 가득 차도 WAL 쓰기가 막히지 않는다. 반대 방향도 마찬가지다. - 운영 유연성: WAL에만 더 빠른(또는 다른 크기의) StorageClass를 붙일 수 있다.
- 모니터링: WAL의 부하를 별도 볼륨 단위로 추적한다.
flowchart TD
POD[PostgreSQL Pod] --> DATA[(PVC PGDATA)]
POD --> WAL[(PVC walStorage)]
DATA --> SC1[StorageClass 표준]
WAL --> SC2[StorageClass 고속]
walStorage는 제거할 수 없다. 기존 클러스터에서 WAL 전용 볼륨을 도로 없애는 동작은 지원되지 않으므로, 분리 여부는 처음 설계할 때 결정한다.볼륨 확장
데이터가 늘어 볼륨을 키워야 할 때, StorageClass가 확장을 허용하면 크기만 바꾸면 된다. 먼저 해당 StorageClass가 allowVolumeExpansion을 지원하는지 확인한다.
kubectl get storageclass premium-storage \
-o jsonpath='{.allowVolumeExpansion}'지원한다면 .spec.storage.size를 키우기만 하면 된다.
볼륨 축소
볼륨을 줄이는 것은 자동화된 경로가 없고 잘못하면 데이터가 사라질 수 있는 예민한 작업이다. CNPG는 이를 자동으로 지원하지 않는다. 굳이 줄여야 한다면 다음과 같이 인스턴스를 하나씩 교체하는 우회 절차를 따른다.
스토리지 선택 시 유의점
- 사전 벤치마크: 운영에 투입하기 전
fio로 스토리지를,pgbench로 데이터베이스 성능을 반드시 측정한다. 스토리지와 DB 성능을 미리 재 보는 일이 가장 중요하다. - 암호화(encryption at rest): CNPG는 저장 데이터 암호화를 StorageClass 설정에 위임한다. 암호화가 필요하면 StorageClass 수준에서 구성한다.
- 정적 프로비저닝 지양: 볼륨을 미리 수동으로 붙여 두는 static provisioning은 high availability와 선언형 모델을 해치므로 권장하지 않는다.
- 블록 스토리지(Ceph·Longhorn): 스토리지 계층의 복제본 수를 1로 낮춰 write amplification을 줄인다. 복제는 CNPG의 다중 인스턴스 구성이 담당한다.
다음 절에서는 이 스토리지 위에서 도는 Pod에 CPU·메모리를 어떻게 할당하고, QoS class로 어떻게 안정성을 확보하는지 다룬다.