본문으로 건너뛰기

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/Writeinfra-db-rw.infra-db.svc.cluster.local5432Primary 연결
Read Onlyinfra-db-ro.infra-db.svc.cluster.local5432Replica 연결
Read/Write (Any)infra-db-r.infra-db.svc.cluster.local5432모든 인스턴스

사용자 및 데이터베이스

기본 사용자

-- 슈퍼유저 (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_upPostgreSQL 인스턴스 상태
cnpg_pg_replication_lag복제 지연 시간
cnpg_pg_database_size_bytes데이터베이스 크기
cnpg_pg_wal_filesWAL 파일 수
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

보안

DB 역할 분리 (RLS 필수)

앱 클러스터(lumie-db, lumie-dev-db)는 두 역할을 명확히 분리합니다.

역할속성용도
lumie_appNOSUPERUSER NOBYPASSRLSHikariCP 런타임 연결 풀 — RLS 정책 완전 적용
postgresSUPERUSERFlyway 마이그레이션 전용

NOSUPERUSER NOBYPASSRLS가 설정된 lumie_app 역할을 사용해야 테넌트 격리 RLS 정책이 올바르게 동작합니다. 런타임 연결에서 postgres SUPERUSER를 사용하면 모든 RLS 정책이 우회됩니다.

lumie_app의 비밀번호는 Vault infrastructure/lumie-db 경로에서 관리됩니다 (CNPG 오퍼레이터가 생성하지 않음 — CNPG #3788).

CNPG 오퍼레이터가 생성하는 *-superuser Secret은 Vault에 미러링하지 않습니다 (오퍼레이터가 소유권을 가짐).

인증 및 권한

  • 슈퍼유저 접근: enableSuperuserAccess: true로 활성화
  • 자격 증명: Vault Static Secret을 통해 관리
  • 네트워크: 클러스터 내부에서만 접근 가능

TLS 암호화

# TLS 설정 (향후 구성)
certificates:
serverTLSSecret: "infra-db-server-tls"
serverCASecret: "infra-db-ca-tls"
clientCASecret: "infra-db-client-ca-tls"

감사 로깅

postgresql:
parameters:
log_statement: "all"
log_min_duration_statement: "1000"
log_connections: "on"
log_disconnections: "on"

문제 해결

일반적인 문제

1. Pod가 시작되지 않음

# 이벤트 확인
kubectl describe pod infra-db-1 -n infra-db

# 스토리지 확인
kubectl get pvc -n infra-db
kubectl describe pvc postgres-infra-db-1 -n infra-db

2. 복제 지연

# 복제 상태 확인
kubectl exec infra-db-1 -n infra-db -c postgres -- psql -c "SELECT * FROM pg_stat_replication;"

# WAL 상태 확인
kubectl exec infra-db-1 -n infra-db -c postgres -- psql -c "SELECT pg_current_wal_lsn();"

3. 백업 실패

# 백업 상태 확인
kubectl get backup -n infra-db

# 백업 로그 확인
kubectl describe backup <backup-name> -n infra-db

복구 시나리오

전체 클러스터 장애

  1. 백업 확인: 최신 백업 및 WAL 아카이브 상태 점검
  2. 새 클러스터 생성: 백업에서 복구하여 새 클러스터 생성
  3. 서비스 재연결: 애플리케이션 연결 문자열 업데이트
  4. 데이터 검증: 복구된 데이터 무결성 확인

단일 노드 장애

CloudNativePG가 자동으로 처리하므로 별도 조치 불필요. 모니터링을 통해 상태만 확인합니다.


성능 튜닝

PostgreSQL 설정

postgresql:
parameters:
# 메모리 설정
shared_buffers: "128MB"
effective_cache_size: "384MB"
work_mem: "4MB"

# 체크포인트 설정
checkpoint_completion_target: "0.9"
wal_buffers: "16MB"

# 연결 설정
max_connections: "100"

# 로깅 설정
log_min_duration_statement: "1000"
log_checkpoints: "on"

리소스 할당

resources:
requests:
memory: "512Mi"
cpu: "50m"
limits:
memory: "512Mi"
# CPU 제한 없음 (안정성 우선)

스토리지 최적화

  • 로컬 SSD: 가능한 경우 SSD 스토리지 사용
  • 볼륨 크기: 워크로드에 따라 적절한 크기 설정
  • 백업 주기: 데이터 중요도에 따라 백업 빈도 조정

이 문서는 CloudNativePG의 설치, 구성, 운영에 대한 포괄적인 가이드를 제공합니다. 추가적인 고급 설정이나 특정 사용 사례에 대해서는 CloudNativePG 공식 문서를 참조하세요.