Jay's <Devlog />Jay's Devlog
HomeBlogAbout
Login

© 2026 Jay's <Devlog />. All Rights Reserved.

GitHubLinkedIn
Gravatar
  1. Home
  2. Blog
  3. k3s
  4. [Kubernetes] K3s 환경에서 PostgreSQL Master-Replica HA 구성하기 (Helm + hostPath PV 완벽 가이드)
ORCHESTRATION
k3s개인서버 22 min read

[Kubernetes] K3s 환경에서 PostgreSQL Master-Replica HA 구성하기 (Helm + hostPath PV 완벽 가이드)

jay

jay

2026년 1월 12일 23:01

목차

  • 🏗️ 목표 아키텍처
  • 1. Primary용 정적 PV/PVC 생성 (고정 경로 사용)
  • 2. Helm Values 설정 (dev-values.yaml)
  • 🚨 트러블 슈팅 (삽질 로그)
    • Issue 1. “Replica 파드가 아예 안 뜸”
    • Issue 2. FATAL: password authentication failed for user “repl_user”
    • Issue 3. Replica Scale-out 시 ProvisioningFailed
    • Issue 4. “StatefulSet is invalid … Forbidden”
  • 🚀 배포 및 확인
  • 📝 마무리

최근 미니피씨에 K3s를 구축하고 서비스를 올리는 작업을 진행 중이다. DB는 가장 익숙한 PostgreSQL을 선택했는데, 단순히 파드 하나 띄우는 것(Standalone) 말고, 읽기 부하 분산과 가용성을 위해 Master-Replica(Primary-ReadReplica) 구조를 잡고 싶었다.

Cloud 환경이었다면 EBS나 블록 스토리지로 뚝딱했겠지만, 맨땅에 헤딩하는 온프레미스 환경이라 스토리지부터 Helm 설정까지 꽤나 삽질을 했다. 그 과정과 최종 설정을 기록해둔다.

🏗️ 목표 아키텍처

  • Cluster: K3s (Single Node ‘jay’)
  • Install Tool: Helm (bitnami/postgresql)
  • Architecture:
    • Primary (Write): 고정된 hostPath 경로(/srv/k3s/data/postgresql/master)를 사용하여 데이터 영속성 보장.
    • Read Replicas (Read): HPA를 통해 부하에 따라 자동 스케일링(Scale-out). 스토리지는 K3s 기본 local-path를 통한 동적 프로비저닝 사용.

1. Primary용 정적 PV/PVC 생성 (고정 경로 사용)

Primary DB는 가장 중요하므로, 관리가 용이한 특정 경로에 데이터를 저장하기 위해 hostPath를 이용한 PV를 수동으로 생성하고 바인딩했다.

file: postgresql-master-pv-pvc.yaml

# PV: 실제 서버의 경로와 매핑
apiVersion: v1
kind: PersistentVolume
metadata:
  name: postgresql-dev-master-pv
  labels:
    type: local
spec:
  storageClassName: postgresql-dev-pv # PVC와 매핑될 키값
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/srv/k3s/data/postgresql/master" # 실제 데이터 저장 경로
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
                - jay # 노드 호스트네임 (kubectl get nodes로 확인)

---
# PVC: Helm 차트가 사용할 요청서
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgresql-dev-master-pvc
spec:
  storageClassName: postgresql-dev-pv # PV와 동일한 이름 사용
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  selector:
    matchLabels:
      type: local # PV의 라벨과 일치해야 함

2. Helm Values 설정 (dev-values.yaml)

Bitnami 차트를 커스터마이징 했다. Primary는 정적 PVC를 쓰고, Replica는 동적 프로비저닝 + HPA를 쓰는 하이브리드 구성이다. (HPA는 설정이 제대로 먹지 않았는데,, 그 과정이 2편에서 계속된다.)

file: dev-values.yaml

## Bitnami PostgreSQL Helm Chart Values

# [중요] 이거 안 쓰면 Replica 안 뜬다. (기본값이 standalone임)
architecture: replication

global:
  defaultStorageClass: "local-path"

auth:
  existingSecret: "postgresql-secret"
  secretKeys:
    adminPasswordKey: "postgres-password"
    userPasswordKey: "password"
    replicationPasswordKey: "replication-password"
  database: "firebat"
  username: "devdb"

primary:
  name: "primary"
  persistence:
    enabled: true
    existingClaim: "postgresql-dev-master-pvc" # 위에서 만든 정적 PVC 연결
    volumeName: "data"
    size: 5Gi
  resources:
    limits:
      cpu: "500m"
      memory: "512Mi"
    requests:
      cpu: "250m"
      memory: "256Mi"

readReplicas:
  autoscaling:
    enabled: true
    minReplicas: 1 # [주의] 0으로 설정 시 트래픽 발생하면 장애로 이어짐. 최소 1 유지.
    maxReplicas: 3
    targetCPUUtilizationPercentage: 80
  persistence:
    enabled: true
    existingClaim: "" # 동적 할당을 위해 비워둠
    storageClass: "local-path" # K3s 기본 StorageClass 사용
    size: 5Gi
    accessModes:
      - ReadWriteOnce

volumePermissions:
  enabled: true
  containerSecurityContext:
    runAsUser: 0
    privileged: true

🚨 트러블 슈팅 (삽질 로그)

Helm 배포 과정에서 겪었던 주요 이슈들과 해결 방법이다.

Issue 1. “Replica 파드가 아예 안 뜸”

  • 현상: helm install을 했는데 Primary 파드 하나만 뜨고 Replica는 감감무소식.
  • 원인: Bitnami 차트의 기본 모드는 standalone이다. Replica 설정을 아무리 적어도 architecture가 지정되지 않으면 무시된다.
  • 해결: values.yaml 최상단에 architecture: replication 추가.

Issue 2. FATAL: password authentication failed for user "repl_user"

  • 현상: Primary는 정상인데 Replica 파드가 무한 재시작되며 로그에 인증 실패가 뜸. 비밀번호를 바꾼 적이 없음.
  • 원인: “기존 데이터 잔존 문제”. 처음에 Standalone 모드로 띄웠을 때 PVC에 데이터가 생성되었는데, 이때는 복제가 필요 없어 repl_user가 생성되지 않음. 이후 설정을 바꿔 재배포했지만 데이터가 남아있어 초기화 스크립트가 스킵됨.
  • 해결: 개발 환경이므로 Primary용 PVC를 삭제하고 재배포하여 초기화 스크립트가 다시 돌게 함. (운영 환경이라면 Primary DB에 접속해 CREATE ROLE repl_user ...로 수동 생성 필요)

Issue 3. Replica Scale-out 시 ProvisioningFailed

  • 현상: Replica 개수를 늘렸는데 파드가 Pending 상태. storageclass.storage.k8s.io "postgresql-dev-pv" not found 에러 발생.
  • 원인: Primary는 내가 만든 정적 PV를 쓰지만, Replica는 HPA로 늘어날 때마다 새로운 PV가 자동으로 생성되어야 한다. 그런데 존재하지 않는 StorageClass 이름을 적었거나, selector를 남겨둬서 자동 생성을 막고 있었음.
  • 해결: readReplicas.persistence.storageClass를 클러스터에 실제 존재하는 "local-path"로 변경하고 selector 삭제.

Issue 4. “StatefulSet is invalid … Forbidden”

  • 현상: 설정을 수정하고 helm upgrade를 쳤는데 업데이트 실패.
  • 원인: StatefulSet의 volumeClaimTemplates(스토리지 설정)은 Immutable(변경 불가) 필드다. 한 번 생성되면 StorageClass 등을 바꿀 수 없다.
  • 해결: 기존 Replica용 StatefulSet을 삭제하고 다시 배포.

🚀 배포 및 확인

모든 설정을 마치고 배포를 진행한다.

확인 1: 파드 상태

> kubectl get pods
---------------------------------------------------------------
NAME                       READY   STATUS    RESTARTS   AGE
postgresql-dev-primary-0   1/1     Running   0          4h49m
postgresql-dev-read-0      1/1     Running   0          4h49m

확인 2: PV/PVC 연결 상태

  • Primary는 내가 지정한 master-pv와 연결됨.
  • Replica는 pvc-xxxxx 처럼 랜덤한 이름으로 local-path를 통해 자동 생성됨.

구성 요약:

  1. Primary: postgresql-dev-master-pvc를 통해 /srv/k3s/data/postgresql/master 경로에 영구 저장.
  2. Replica: local-path StorageClass를 통해 /srv/k3s/data/pvc-xxx 경로에 자동 할당.
  3. HPA: CPU 사용량에 따라 Replica 파드가 1~3개로 자동 조절됨.

📝 마무리

온프레미스 K3s 환경이라 스토리지가 제일 골치였는데, Primary는 정적 할당(안전성), Replica는 동적 할당(유연성/HPA)으로 혼합해서 구성하는 것이 정답이었다.

이제 부하 테스트를 걸어서 HPA가 작동하며 Replica 파드가 늘어나는지(그리고 PV가 자동으로 생기는지) 구경하러 가야겠다. 끝!

📂 [시리즈] K3s 홈 서버 DB 운영 가이드

  • [1편] K3s 환경에서 PostgreSQL Master-Replica HA 구성하기 (Helm, HostPath PV)
  • [2편] PostgreSQL HA 부하 테스트: pgbench 성능 검증과 HPA 오토스케일링

#Helm#hostPath#k3s#k8s#Kubernetes#Postgresql#PV#PVC#개인서버#홈 서버

You might also like

[Jenkins] Docker로 띄운 Jenkins, 데이터 그대로 Kubernetes로 이관하기

#Helm#Jenkins#k3s

[Next.js + WordPress] 홈서버 배포기: ETIMEDOUT 해결부터 성능 최적화까지

#DevOps#Docker#Jenkins

Kubernetes K3s 환경에서 PostgreSQL HA 부하 테스트: pgbench로 검증하는 성능과 오토스케일링(HPA)

#Autoscaling#Helm#Home Lab

Comments (0)

Leave a Reply

Or login to comment with your account.

No comments yet. Be the first to share your thoughts!