티스토리 뷰

반응형

쿠버네티스 실습: StatefulSet으로 PostgreSQL 배포하기 (PVC 연동)

앞선 글에서는 **PersistentVolume(PV)**와 **PersistentVolumeClaim(PVC)**을 이용해 데이터가 유지되는 스토리지를 경험했습니다.
이번 글에서는 이를 실제 데이터베이스에 적용해봅니다. 우리가 자주 사용하는 PostgreSQLStatefulSet으로 배포하고 PVC와 연결해 Pod가 재시작되더라도 데이터가 유지되는 것을 실습합니다.


1) 왜 StatefulSet인가?

  • Deployment는 무상태(Stateless) 애플리케이션에 적합합니다. Pod 이름이 랜덤하고, IP도 바뀔 수 있습니다.
  • StatefulSet은 상태를 가진 애플리케이션(DB, MQ 등)을 위한 컨트롤러입니다.
    • Pod 이름이 순차적으로 부여됨 (postgres-0, postgres-1 등).
    • Pod와 PVC를 1:1로 바인딩해 재시작해도 동일 스토리지를 사용합니다.
  • 따라서 DB, 캐시, 메시지 큐 같은 애플리케이션은 StatefulSet으로 배포하는 게 원칙입니다.

2) PersistentVolume & PersistentVolumeClaim 준비

postgres-pv.yaml 작성:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: postgres-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/data/postgres"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

적용:

kubectl apply -f postgres-pv.yaml
kubectl get pv,pvc

예상 출력:

NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                 STORAGECLASS   AGE
postgres-pv   1Gi        RWO            Retain           Bound    default/postgres-pvc   manual         5s

3) Secret으로 DB 패스워드 저장

반응형

postgres-secret.yaml 작성:

apiVersion: v1
kind: Secret
metadata:
  name: postgres-secret
type: Opaque
data:
  POSTGRES_PASSWORD: c3VwZXJzZWNyZXQ=   # "supersecret"을 base64 인코딩

적용:

kubectl apply -f postgres-secret.yaml

4) StatefulSet 작성

postgres-statefulset.yaml 작성:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: "postgres"
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:15
        ports:
        - containerPort: 5432
        env:
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: postgres-secret
              key: POSTGRES_PASSWORD
        volumeMounts:
        - name: postgres-storage
          mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
  - metadata:
      name: postgres-storage
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi

적용:

kubectl apply -f postgres-statefulset.yaml

확인:

kubectl get statefulsets
kubectl get pods

5) Service 생성 (내부 연결용)

postgres-service.yaml 작성:

apiVersion: v1
kind: Service
metadata:
  name: postgres
spec:
  ports:
  - port: 5432
    targetPort: 5432
  selector:
    app: postgres

적용:

kubectl apply -f postgres-service.yaml

6) PostgreSQL 접속 확인

Pod에 직접 들어가서 DB 접속:

kubectl exec -it postgres-0 -- psql -U postgres

패스워드는 Secret에 저장한 값(supersecret)을 사용합니다.

테스트용 DB와 테이블 생성:

CREATE DATABASE testdb;
\c testdb
CREATE TABLE greetings (id serial primary key, msg text);
INSERT INTO greetings (msg) VALUES ('Hello Kubernetes StatefulSet');
SELECT * FROM greetings;

7) 데이터 영속성 검증

Pod 삭제 후 재생성:

kubectl delete pod postgres-0
kubectl get pods

다시 psql 접속 후:

\c testdb
SELECT * FROM greetings;

→ 이전에 입력한 데이터(Hello Kubernetes StatefulSet)가 그대로 유지됨을 확인할 수 있습니다.


8) 정리

  • StatefulSet은 Pod 이름과 스토리지를 1:1로 바인딩해 DB 같은 상태ful 앱에 적합.
  • Secret으로 패스워드를 안전하게 주입.
  • PVC를 통해 Pod가 삭제되어도 데이터가 유지됨을 검증.

다음 글에서는 Redis를 쿠버네티스 환경에 배포하고, NestJS 애플리케이션과 연결해 캐싱 레이어를 구성하는 실습을 진행합니다.


 

쿠버네티스,StatefulSet,PostgreSQL,PersistentVolume,PersistentVolumeClaim,DB배포,쿠버네티스스토리지,Secret,데이터영속성,K8s실습

 

 

1. Minikube에서 hostPath 기반 PV의 동작 방식

Minikube는 hostPath 타입 PV를 지원하지만, 해당 경로가 Minikube VM 내에 존재해야만 영속성이 보장됩니다. 일반적으로 /data, /var/lib/minikube 등이 VM 내부에 자동 생성되어 따로 설정 없이도 유지되는 경로입니다.
(minikube)

하지만, 사용자가 지정한 "/data/postgres" 경로나 로컬 macOS 경로는 VM 내부에 없을 수 있고, 이 경우 데이터가 보존되지 않거나 권한 문제가 발생할 수 있습니다.

개선 포인트

  • VM 내부 안전한 경로 사용 추천: 예를 들어 /data/postgres는 Minikube가 기본 관리하는 경로 중 하나라면 안정적입니다.
  • macOS 로컬 경로를 사용하려면 minikube mount 기능 활용이 필요합니다. 아래 예처럼 로컬 폴더를 명시적으로 마운트해야 VM 내부에서 사용할 수 있습니다:이후 hostPath: /data/postgres를 지정하면, Pod에서 macOS의 해당 경로를 활용 가능하게 됩니다.
    (Stack Overflow)
  • minikube mount /Users/youruser/data:/data/postgres

2. 권한 문제, 특히 PostgreSQL에서 종종 발생

특히 PostgreSQL은 데이터 디렉토리에 대한 쓰기 권한 제한 때문에 에러가 발생할 수 있습니다.

  • hostPath 대상 디렉토리가 root 소유이거나 권한이 부족한 경우, 내부 컨테이너에서 쓰기 실패가 발생할 수 있습니다.
  • 해결 방법 중 하나로, securityContext를 사용해 컨테이너가 **root 권한(UID 0)**으로 실행되도록 설정할 수 있습니다:
securityContext:
  runAsUser: 0

이 설정은 퍼미션 오류를 회피하는 유용한 방법입니다.
(Stack Overflow)


3. 여건이 된다면: 동적 프로비저닝(Dynamic Provisioning)도 고려해보기

Minikube는 hostPath 외에도 기본 Storage Provisioner 를 내장하여 PVC 생성 시 자동으로 PV를 생성 및 할당하는 동적 프로비저닝 기능을 제공합니다.

  • 이 방식을 사용하면, 실습이 더욱 클라우드 환경과 유사하게 전개되어 학습 효과가 높아집니다.
    (minikube)

보완 정리 요약

항목 권장 방식

hostPath 경로 VM 내부의 /data, /var/lib/minikube 등 안정적인 경로 사용 권장
macOS 로컬 경로 활용 시 minikube mount로 로컬 디렉토리 마운트 + hostPath 연동 필요
PostgreSQL 쓰기 권한 문제 해결 securityContext: runAsUser: 0 추가
더 현실적인 실습 구성 Minikube 내 자동 dynamic provisioning 활용 가능

 

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
글 보관함
반응형