CloudNativePG
CloudNativePG(CNPG)는 Kubernetes Native PostgreSQL 오퍼레이터입니다. PostgreSQL 인스턴스의 프로비저닝, 고가용성 복제, 자동 백업, 페일오버를 Kubernetes CRD로 선언적으로 관리합니다.
개요
주요 기능
| 기능 | 설명 |
|---|---|
| PostgreSQL 버전 | 18.1 (wal2json 플러그인 포함) |
| 고가용성 | Primary-Replica 스트리밍 복제 |
| 자동 페일오버 | Primary 장애 시 Replica 자동 승격 |
| 백업 | WAL 아카이브 + 베이스백업 → MinIO |
| 모니터링 | Prometheus 메트릭 및 PodMonitor |
아키텍처
설치 및 구성
Helm 차트 설정
# CloudNativePG Operator
image:
repository: zot.lumie-infra.com/cloudnative-pg/cloudnative-pg
tag: "1.28.1"
pullPolicy: IfNotPresent
replicaCount: 1
resources:
requests:
cpu: 15m
memory: 100Mi
limits:
memory: 100Mi
monitoring:
podMonitorEnabled: true
grafanaDashboard:
create: false # 수동 임포트 (Grafana.com ID: 20417)
webhook:
port: 9443
mutating:
create: true
validating:
create: true
priorityClassName: high-priority
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: cloudnative-pg
topologyKey: kubernetes.io/hostname
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 10001
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
스토리지 클래스
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-path-retain
provisioner: rancher.io/local-path
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
특징:
- Retain 정책: PVC 삭제 시에도 데이터 보존
- WaitForFirstConsumer: Pod 스케줄링 후 볼륨 바인딩
- Local Path: 각 노드의 로컬 디스크 사용
PostgreSQL 클러스터
infra-db 클러스터
공유 인프라 서비스용 PostgreSQL 클러스터입니다.
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: infra-db
spec:
instances: 3
imageName: zot.lumie-infra.com/storage/postgresql-wal2json:18.1
bootstrap:
initdb:
database: teleport
owner: postgres
secret:
name: infra-db-bootstrap-secret
postInitSQL:
- "CREATE USER grafana WITH PASSWORD 'VAULT_PASSWORD'"
- "CREATE DATABASE grafana OWNER grafana"
- "CREATE USER umami WITH PASSWORD 'VAULT_PASSWORD'"
- "CREATE DATABASE umami OWNER umami"
- "CREATE USER keycloak WITH PASSWORD 'VAULT_PASSWORD'"
- "CREATE DATABASE keycloak OWNER keycloak"
- "CREATE USER openclaw WITH PASSWORD 'VAULT_PASSWORD'"
- "CREATE DATABASE openclaw OWNER openclaw"
- "CREATE USER coder WITH PASSWORD 'VAULT_PASSWORD'"
- "CREATE DATABASE coder OWNER coder"
- "CREATE USER gitea WITH PASSWORD 'VAULT_PASSWORD'"
- "CREATE DATABASE gitea OWNER gitea"
storage:
storageClass: local-path-retain
size: 2Gi
resources:
requests:
memory: "384Mi"
cpu: "50m"
limits:
memory: "384Mi"
enableSuperuserAccess: true
postgresql:
parameters:
wal_level: "logical"
max_replication_slots: "8"
affinity:
enablePodAntiAffinity: true
topologyKey: kubernetes.io/hostname
podAntiAffinityType: required
monitoring:
enablePodMonitor: true
주요 설정 설명
WAL 설정
wal_level = logical
max_replication_slots = 8
- logical WAL: 논리적 복제 및 CDC(Change Data Capture) 지원
- replication_slots: 최대 8개의 복제 슬롯 허용
안티 어피니티
affinity:
enablePodAntiAffinity: true
topologyKey: kubernetes.io/hostname
podAntiAffinityType: required
- required: 각 PostgreSQL 인스턴스를 서로 다른 노드에 배치 (강제)
- topologyKey: 노드 단위로 분산 배치
데이터베이스 관리
연결 정보
| 서비스 | 엔드포인트 | 포트 | 용도 |
|---|---|---|---|
| Read/Write | infra-db-rw.infra-db.svc.cluster.local | 5432 | Primary 연결 |
| Read Only | infra-db-ro.infra-db.svc.cluster.local | 5432 | Replica 연결 |
| Read/Write (Any) | infra-db-r.infra-db.svc.cluster.local | 5432 | 모든 인스턴스 |
사용자 및 데이터베이스
기본 사용자
-- 슈퍼유저 (CNPG 오퍼레이터 관리, Teleport 기본 DB 소유자)
postgres (owner of teleport database)
-- 서비스별 사용자
grafana (owner of grafana database)
umami (owner of umami database)
keycloak (owner of keycloak database)
openclaw (owner of openclaw database)
coder (owner of coder database)
gitea (owner of gitea database)
권한 관리
-- 새 서비스 사용자 추가 예시
CREATE USER newservice WITH PASSWORD 'secure_password';
CREATE DATABASE newservice OWNER newservice;
GRANT CONNECT ON DATABASE newservice TO newservice;
백업 및 복구
WAL 아카이브
CloudNativePG는 자동으로 WAL(Write-Ahead Log) 파일을 Cloudflare R2에 아카이브합니다. infra-db 클러스터는 R2 Barman Object Store를 사용하며, 보존 기간은 365일입니다.
backup:
barmanObjectStore:
destinationPath: "s3://lumie-dr/cnpg/infra-db"
endpointURL: "https://a0884dfaf71a61fe7cb952fb9d69eb68.r2.cloudflarestorage.com"
s3Credentials:
accessKeyId:
name: r2-barman-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: r2-barman-creds
key: ACCESS_SECRET_KEY
wal:
compression: gzip
maxParallel: 4
data:
compression: gzip
retentionPolicy: "365d"
앱 클러스터(lumie-db, lumie-dev-db)도 동일한 R2 Barman 구성으로 백업됩니다. 자세한 내용은 infra-db 문서를 참조하세요.
복구 절차
1. Point-in-Time Recovery (PITR)
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: infra-db-restored
spec:
instances: 3
bootstrap:
recovery:
source: infra-db-backup
recoveryTarget:
targetTime: "2024-01-15 10:30:00"
externalClusters:
- name: infra-db-backup
barmanObjectStore:
destinationPath: s3://cnpg-backups/infra-db
endpointURL: http://minio.minio.svc.cluster.local:9000
2. 베이스백업에서 복구
# 사용 가능한 백업 확인
kubectl get backup -n infra-db
# 특정 백업에서 복구
kubectl apply -f - <<EOF
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: infra-db-restored
namespace: infra-db
spec:
instances: 3
bootstrap:
recovery:
backup:
name: backup-20240115-020000
EOF
모니터링
Prometheus 메트릭
CloudNativePG는 다음 메트릭을 제공합니다:
| 메트릭 | 설명 |
|---|---|
cnpg_pg_up | PostgreSQL 인스턴스 상태 |
cnpg_pg_replication_lag | 복 제 지연 시간 |
cnpg_pg_database_size_bytes | 데이터베이스 크기 |
cnpg_pg_wal_files | WAL 파일 수 |
cnpg_backup_duration_seconds | 백업 소요 시간 |
PodMonitor 설정
monitoring:
enablePodMonitor: true
이 설정으로 Prometheus가 자동으로 PostgreSQL 메트릭을 수집합니다.
Grafana 대시보드
대시보드 ID: 20417 (Grafana.com) URL: https://grafana.com/grafana/dashboards/20417-cloudnativepg/
수동으로 임포트하여 사용합니다 (ConfigMap 크기 제한으로 자동 생성 비활성화).
운영 가이드
클러스터 상태 확인
# 클러스터 상태 조회
kubectl get cluster -n infra-db
# 상세 정보 확인
kubectl describe cluster infra-db -n infra-db
# Pod 상태 확인
kubectl get pods -n infra-db -l postgresql=infra-db
페일오버 테스트
# Primary Pod 삭제 (자동 페일오버 테스트)
kubectl delete pod infra-db-1 -n infra-db
# 페일오버 상태 확인
kubectl get cluster infra-db -n infra-db -o yaml | grep -A 10 status
스케일링
# 인스턴스 수 변경 (4 → 5)
kubectl patch cluster infra-db -n infra-db --type='merge' -p='{"spec":{"instances":5}}'
# 스케일링 진행 상황 확인
kubectl get pods -n infra-db -w
로그 확인
# Primary 로그 확인
kubectl logs infra-db-1 -n infra-db -c postgres
# Operator 로그 확인
kubectl logs -n cnpg -l app.kubernetes.io/name=cloudnative-pg