티스토리 뷰
쿠버네티스 실습: StatefulSet으로 PostgreSQL 배포하기 (PVC 연동)
앞선 글에서는 **PersistentVolume(PV)**와 **PersistentVolumeClaim(PVC)**을 이용해 데이터가 유지되는 스토리지를 경험했습니다.
이번 글에서는 이를 실제 데이터베이스에 적용해봅니다. 우리가 자주 사용하는 PostgreSQL을 StatefulSet으로 배포하고 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 활용 가능 |
'project > 맥미니로 시작하는 쿠버네티스' 카테고리의 다른 글
| 쿠버네티스 실습: Nginx Ingress Controller와 Nginx Proxy Manager로 외부 접근 구성하기 (0) | 2025.08.28 |
|---|---|
| 쿠버네티스 실습: Redis 배포와 NestJS 애플리케이션 연동 (0) | 2025.08.27 |
| 쿠버네티스 실습: PersistentVolume과 PersistentVolumeClaim으로 데이터 저장하기 (0) | 2025.08.25 |
| 쿠버네티스 실습: ConfigMap과 Secret으로 환경 설정 관리하기 (0) | 2025.08.22 |
| 쿠버네티스 실습: YAML 매니페스트로 Nginx 배포하기 (0) | 2025.08.21 |
- Total
- Today
- Yesterday
- SEO최적화
- LangChain
- Express
- fastapi
- Docker
- flax
- node.js
- NestJS
- Next.js
- Prisma
- 생성형AI
- PostgreSQL
- 쿠버네티스
- REACT
- llm
- ai철학
- kotlin
- 개발블로그
- Python
- JAX
- seo 최적화 10개
- 딥러닝
- DevOps
- nextJS
- JWT
- 백엔드개발
- CI/CD
- rag
- 웹개발
- Redis
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |

