PostgreSQL Cluster 설치 가이드

1. 개요

본 문서는 gitops 저장소의 /postgresql/cluster 디렉터리 구조를 기반으로 CloudNativePG 기반 PostgreSQL 클러스터를 Kubernetes에 설치하는 전체 과정을 안내합니다. Kustomize, Helm, Makefile을 활용한 배포 자동화, 환경별 설정, 주요 커스텀 옵션, 운영 팁을 포함합니다.


2. 사전 요구사항

  • Kubernetes 클러스터: v1.30 이상
  • 로컬 도구: kubectl, kustomize, helm 설치 완료

3. 디렉터리 구조 및 역할

cluster/
├── Makefile                           # 배포 자동화 스크립트
├── kustomize/
│   ├── base/                          # 공통 리소스(Helm 차트, CRD 등)
│   └── overlays/
│       └── dev/                       # dev 환경 설정
│           ├── kustomization.yaml     # Kustomize 구성
│           └── helm/
│               ├── values.yaml        # Cluster 설정
│               └── helm-chart.yaml    # HelmChartInflationGenerator
  • Makefile: apply, delete, preview 등 배포 자동화 명령어
  • kustomize/base/: 모든 환경에 공통 적용될 리소스(Helm 차트, CRD 등)
  • kustomize/overlays/dev/: dev 환경 특화 설정
  • helm/values.yaml: PostgreSQL Cluster Helm Chart 커스터마이징 설정

4. 설치 단계

4.1. values.yaml 커스터마이징

kustomize/overlays/dev/helm/values.yaml 파일을 열어 주요 설정을 수정합니다.

4.1.1. 클러스터/스토리지/복제본 설정

type: postgresql
version:
  postgresql: "16"
mode: standalone
cluster:
  instances: 3
  storage:
    size: 8Gi
  walStorage:
    enabled: true
    size: 1Gi

4.1.2. 리소스 제한 및 보안

cluster:
  resources:
    limits:
      cpu: 2000m
      memory: 8Gi
    requests:
      cpu: 2000m
      memory: 8Gi

4.1.3. 모니터링 및 백업

cluster:
  monitoring:
    enabled: true
    prometheusRule:
      enabled: true
  additionalLabels:
    prometheus: main

4.1.4. 슈퍼유저/시크릿/오브젝트스토어

  • superuserSecret, secretGenerator, barman-object-store 등 민감 정보는 Secret으로 별도 관리 권장

4.2. Kustomize 구성

4.2.1. kustomization.yaml 구성

kustomize/overlays/dev/kustomization.yaml에서 namespace, generators, secretGenerator, patches 등 지정

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: database
generators:
  - ./helm/helm-chart.yaml
resources:
  - ../../base
  - ./resources/barman-object-store.yaml
  - ./resources/backup-schedule.yaml
secretGenerator:
  - name: s3-store-creds
    literals:
      - ACCESS_KEY_ID=***
      - ACCESS_SECRET_KEY=***
    type: Opaque
generatorOptions:
  disableNameSuffixHash: true
patches:
  - target:
      kind: Cluster
      name: pg-cluster
    patch: |-
      - op: add
        path: /spec/plugins
        value:
          - name: barman-cloud.cloudnative-pg.io
            isWALArchiver: true
            parameters:
              barmanObjectName: s3-store

4.2.2. 백업 스케줄 설정

resources/backup-schedule.yaml에서 백업 스케줄을 설정합니다.

apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
  name: pg-cluster-daily-backup
spec:
  schedule: "0 0 0 * * *"  # 매일 자정 백업
  backupOwnerReference: self
  cluster:
    name: pg-cluster
  method: plugin
  pluginConfiguration:
    name: barman-cloud.cloudnative-pg.io

4.2.3. 오브젝트 스토어 설정

resources/barman-object-store.yaml에서 백업 저장소를 설정합니다.

apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
  name: s3-store
spec:
  configuration:
    destinationPath: s3://postgresql-backups/
    endpointURL: http://minio.storage.svc.cluster.local:9000
    s3Credentials:
      accessKeyId:
        name: s3-store-creds
        key: ACCESS_KEY_ID
      secretAccessKey:
        name: s3-store-creds
        key: ACCESS_SECRET_KEY
    wal:
      compression: gzip
  retentionPolicy: "5d"

4.3. 배포 프로세스 (Makefile 활용)

Step 1: Namespace 생성

make namespace DEPLOY_ENV=dev

Step 2: 배포 미리보기

make preview DEPLOY_ENV=dev

Step 3: 배포 실행

make apply DEPLOY_ENV=dev

Step 4: 배포 상태 확인

kubectl get pods -n database -w

5. 설치 후 검증

5.1. 리소스 상태 확인

kubectl get pods,svc,pvc -n database

확인 사항:

  • 모든 Pod이 Running 상태
  • PVC가 Bound 상태
  • Service, CRD, Barman Cloud 리소스 생성 확인

5.2. Grafana/Prometheus 연동 확인

  • Grafana 대시보드가 정상 생성되었는지 확인
  • Prometheus에서 메트릭 수집 여부 확인

5.3. 백업 구성 확인

  • ScheduledBackup 리소스 상태 확인:
    kubectl get scheduledbackup -n database
    
  • ObjectStore 리소스 상태 확인:
    kubectl get objectstore -n database
    
  • 백업 실행 상태 확인:
    kubectl get backup -n database
    

5.4. 클러스터 구성 검증

PostgreSQL 클러스터의 고가용성 구성과 복제 상태를 확인합니다.

5.4.1. 클러스터 리소스 확인

kubectl -n database get svc,sts,pod,pvc | grep pg-cluster

확인 사항:

  • Service: pg-cluster-r (읽기 전용), pg-cluster-ro (읽기 전용), pg-cluster-rw (읽기/쓰기) 서비스 존재

5.4.2. 복제 상태 확인

PostgreSQL 클러스터의 Pod에 접속하여 데이터베이스에 연결합니다.

kubectl -n database exec -it pod/pg-cluster-1 -- bash
$ psql -U postgres -h pg-cluster-rw 
Password for user postgres:

클러스터 노드 구성을 확인하는 SQL을 실행합니다.

WITH nodes AS (
    SELECT
        application_name,
        client_addr,
        'replica' AS role
    FROM pg_stat_replication
)
SELECT
    inet_server_addr() AS node_ip,
    'primary' AS role
UNION ALL
SELECT
    client_addr,
    role
FROM nodes;

예상 결과:

   node_ip   |  role   
-------------+---------
 10.244.x.x  | primary
 10.244.x.x  | replica
 10.244.x.x  | replica
(3 rows)

확인 사항:

  • Primary 노드 1개, Replica 노드 2개로 구성
  • 모든 노드가 정상 연결 상태
  • IP 주소가 클러스터 내 Pod IP와 일치

5.4.3. Grafana Dashboard

CloudNativePG 클러스터의 성능 및 상태를 모니터링할 수 있는 Grafana 대시보드입니다. PostgreSQL 메트릭(CPU, 메모리 사용량), 복제 상태, 쿼리 성능, WAL 아카이브 상태 등을 시각적으로 확인할 수 있습니다.

https://grafana.cnapcloud.com/d/cloudnative-pg/cloudnativepg

6. 클러스터 복구 (Recovery)

recovery 오버레이를 사용하여 백업에서 클러스터를 복구합니다.

6.1. Recovery 오버레이 적용

make apply DEPLOY_ENV=recovery

6.2. 주요 설정

  • 클러스터 이름: pg-cluster-recovery
  • 복구 모드: standalone (백업에서 복구)
  • 복구 시점: targetTime 설정 (예: “2025-12-14 09:00:00+00”)
  • 백업 소스: source (ObjectStore에서 읽기)
  • ObjectStore: s3-store-recovery (MinIO S3 호환 스토리지)

6.3. 복구 확인

kubectl get pods -n database -l app.kubernetes.io/name=pg-cluster-recovery
kubectl logs -f pg-cluster-recovery-1 -n database

7. 운영 및 Troubleshooting

7.1. Pod가 Running 상태가 아닌 경우

kubectl get pods -n database
kubectl describe pod <pod명> -n database
kubectl logs <pod명> -n database

주요 원인:

  • PVC 미바인딩 → StorageClass 확인
  • 리소스 부족 → kubectl top nodes로 노드 상태 확인
  • 이미지 Pull 오류 → values.yaml의 image.repository, image.tag 확인

7.2. CRD/리소스 생성 오류

  • values.yaml에서 crds.create 옵션 확인
  • Helm/Kustomize 버전 호환성 문제 발생 시 공식 문서 참고

7.3. 네임스페이스/권한 문제

  • 네임스페이스 미존재: kubectl create namespace database로 생성
  • rbac/serviceAccount 설정 확인

7.4. Secret 관리

민감 정보(슈퍼유저 비밀번호, S3 키 등)는 별도 Secret으로 관리하고 values.yaml에서 참조하도록 권장합니다.

kubectl create secret generic postgres-superuser-secret --from-literal=password='your-strong-password' -n database

7.5. 노드 Drain 및 Failover

CNPG에서 노드 drain이 발생하면 Primary Pod는 즉시 종료되지 않고 Eviction(계획된 종료) 이벤트를 통해 이를 인식합니다. Primary가 살아 있는 동안 CNPG는 이를 장애가 아닌 계획된 종료로 판단하며, 먼저 Replica Pod들을 다른 노드로 이동시킨 뒤 그중 하나를 새 Primary로 승격(switchover)합니다. 이후 클러스터 가용성이 확보된 것을 확인한 다음 기존 Primary를 마지막으로 종료합니다. 이 과정은 PodDisruptionBudget과 termination grace period가 보장되는 한 무중단을 목표로 수행합니다.

노드 Drain 예시:

kubectl drain kind-worker3 --ignore-daemonsets --delete-emptydir-data

7.6. Network Policy

PostgreSQL Pod 간 네트워크 통신을 제한하는 NetworkPolicy 적용을 권장합니다.


8. 보안 및 운영 권장사항

8.1. Secret 관리

민감 정보(슈퍼유저 비밀번호, S3 키 등)는 별도 Secret으로 관리하고 values.yaml에서 참조하도록 권장합니다.

kubectl create secret generic postgres-superuser-secret --from-literal=password='your-strong-password' -n database

8.2. Network Policy

PostgreSQL Pod 간 네트워크 통신을 제한하는 NetworkPolicy 적용을 권장합니다.


9. 배포 제거

9.1. Cluster 삭제

make delete DEPLOY_ENV=dev

9.2. Namespace 삭제 (선택사항)

kubectl delete namespace database

주의: Namespace를 삭제하면 PVC를 포함한 모든 데이터가 영구 삭제됩니다.


10. 부록: 최종 체크리스트

설치 전:

  • Kubernetes 클러스터 준비 (v1.20+)
  • kubectl, kustomize, helm 설치
  • 네임스페이스(database) 생성

설치:

  • values.yaml 커스터마이징 완료
  • kustomization.yaml 구성 완료
  • make namespace 실행
  • make preview 실행 및 확인
  • make apply 실행

검증:

  • 모든 Pod이 Running 상태
  • PVC가 Bound 상태
  • Service/CRD/Barman 리소스 생성 확인
  • Grafana/Prometheus 연동 확인

운영:

  • Secret 관리 적용
  • Network Policy 구성
  • 백업 전략 수립
  • 모니터링 및 알림 설정
💬 무료 컨설팅 신청