PV와 PVC — Kubernetes에서 데이터를 영속적으로 저장하는 방법
컨테이너를 재시작하면 내부 데이터가 사라지는데, 데이터베이스처럼 데이터를 영구 보존해야 하는 경우에는 어떻게 해야 할까요?
컨테이너의 파일 시스템은 기본적으로 임시(ephemeral)입니다. Pod이 재시작되거나 다른 노드로 이동하면 데이터가 사라집니다. Kubernetes는 PersistentVolume(PV)과 PersistentVolumeClaim(PVC)으로 Pod의 라이프사이클과 독립적인 영속 스토리지를 제공합니다.
PV와 PVC의 개념
- PV (PersistentVolume): 클러스터 수준의 스토리지 리소스. 관리자가 미리 준비하거나 동적으로 생성됩니다.
- PVC (PersistentVolumeClaim): Pod이 스토리지를 요청하는 수단. 네임스페이스에 속합니다.
이 분리 설계의 핵심은 관심사 분리입니다. 인프라 관리자는 스토리지를 프로비저닝하고(PV), 개발자는 필요한 스토리지를 요청(PVC)하기만 하면 됩니다.
관리자: PV 생성 (스토리지 종류, 용량, 접근 모드)
개발자: PVC 생성 (필요한 용량, 접근 모드)
Kubernetes: PV-PVC 바인딩 → Pod에서 사용
Static Provisioning — PV를 미리 생성
# 1단계: 관리자가 PV 생성
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath: # 로컬 테스트용
path: /mnt/data
---
# 2단계: 개발자가 PVC 생성
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: manual # PV의 storageClassName과 일치
---
# 3단계: Pod에서 PVC 사용
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: my-app:1.0
volumeMounts:
- name: data
mountPath: /app/data
volumes:
- name: data
persistentVolumeClaim:
claimName: my-pvc
바인딩 과정
PVC가 생성되면 Kubernetes는 조건에 맞는 PV를 찾아 바인딩합니다.
바인딩 조건:
- 용량: PVC가 요청한 크기 이상의 PV
- accessModes: PVC가 요청한 모드를 PV가 지원
- storageClassName: PVC와 PV의 storageClassName이 일치
- 레이블 셀렉터: PVC에 selector가 있으면 해당 조건
# PV 상태 확인
kubectl get pv
# NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM
# my-pv 10Gi RWO Retain Bound default/my-pvc
# PVC 상태 확인
kubectl get pvc
# NAME STATUS VOLUME CAPACITY ACCESS MODES
# my-pvc Bound my-pv 10Gi RWO
PV의 상태 전이는 다음과 같습니다.
Available → Bound → Released → (Available 또는 삭제)
accessModes
| 모드 | 약어 | 설명 | 사용 사례 |
|---|---|---|---|
| ReadWriteOnce | RWO | 단일 노드에서 읽기/쓰기 | 대부분의 블록 스토리지 |
| ReadOnlyMany | ROX | 여러 노드에서 읽기 전용 | 설정 파일, 정적 자산 |
| ReadWriteMany | RWX | 여러 노드에서 읽기/쓰기 | NFS, CephFS, EFS |
| ReadWriteOncePod | RWOP | 단일 Pod에서만 읽기/쓰기 | 데이터베이스 (1.22+) |
주의: accessModes는 동시 접근을 제어하지, 단일 Pod 내 권한을 제어하는 것이 아닙니다.
reclaimPolicy
PVC가 삭제되었을 때 PV를 어떻게 처리할지 결정합니다.
| 정책 | 동작 | 사용 사례 |
|---|---|---|
| Retain | PV와 데이터 보존, 수동 정리 필요 | 프로덕션 데이터 |
| Delete | PV와 실제 스토리지 자동 삭제 | 개발/테스트 환경 |
| Recycle | 데이터만 삭제(rm -rf) 후 재사용 (deprecated) | - |
spec:
persistentVolumeReclaimPolicy: Retain # 프로덕션 권장
프로덕션 환경에서는 반드시 Retain을 사용하세요. Delete를 사용하면 PVC 삭제 시 데이터가 복구 불가능하게 삭제됩니다.
Dynamic Provisioning
StorageClass를 사용하면 PVC 생성 시 자동으로 PV가 생성됩니다. 관리자가 미리 PV를 만들 필요가 없어 운영이 편해집니다.
# StorageClass 정의
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
---
# PVC만 생성하면 PV가 자동 생성됨
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: fast-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast
resources:
requests:
storage: 20Gi
# PV가 자동으로 생성되어 바인딩됨
kubectl get pvc fast-pvc
# NAME STATUS VOLUME CAPACITY
# fast-pvc Bound pvc-a1b2c3d4-e5f6-7890-abcd-ef1234567890 20Gi
볼륨 확장
StorageClass에서 allowVolumeExpansion: true를 설정하면 PVC의 용량을 늘릴 수 있습니다.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: expandable
provisioner: ebs.csi.aws.com
allowVolumeExpansion: true # 확장 허용
# PVC 용량 확장
kubectl patch pvc my-pvc -p '{"spec":{"resources":{"requests":{"storage":"30Gi"}}}}'
축소는 지원하지 않으며, 파일 시스템 확장을 위해 Pod 재시작이 필요할 수 있습니다.
PV/PVC 디버깅
# PVC가 Pending인 경우 — 적합한 PV가 없음
kubectl describe pvc my-pvc
# Events:
# waiting for a volume to be created, either by external provisioner...
# PV 상태 확인
kubectl get pv --sort-by=.spec.capacity.storage
# 사용 중인 볼륨 확인
kubectl get pvc --all-namespaces
# PV가 Released 상태에서 재사용하려면
# 1. PV의 claimRef를 제거
kubectl patch pv my-pv -p '{"spec":{"claimRef": null}}'
실무에서 주의할 점
- PVC 삭제 전에 reclaimPolicy를 확인하세요: Delete 정책이면 실제 데이터가 삭제됩니다
- RWO는 노드 제한이 있습니다: Pod이 다른 노드로 이동하면 볼륨이 따라가지 못할 수 있습니다
- WaitForFirstConsumer: Pod이 스케줄된 노드에서 볼륨을 생성하여 AZ 불일치를 방지합니다
- StatefulSet의 PVC: StatefulSet 삭제 시 PVC는 자동으로 삭제되지 않습니다
정리
PV는 실제 스토리지를, PVC는 스토리지 요청을 나타내며, Kubernetes가 조건에 맞는 PV-PVC를 바인딩합니다. 동적 프로비저닝을 사용하면 PVC만 생성하면 되어 운영이 편해지고, reclaimPolicy와 accessModes를 올바르게 설정하는 것이 데이터 안전성의 핵심입니다.