# 3. PV와 PVC
쿠버네티스에서도 도커와 같이 호스트에 위치한 디렉터리를 각 포드와 공유함으로써 데이터를 보존하는 것이 가능
그렇지만 쿠버네티스와 같이 다중 서버로 구성된 환경에서는 적합하지 않음
→ 그럴 때 사용하는 것이 PV(Persistent Volume)
# PV

- 워커 노드들이 네트워크상에서 스토리지를 마운트해 영속적으로 데이터를 저장할 수 있는 볼륨
- 포드에 장애가 생겨 다른 노드로 옮겨가더라도 해동 노드에서 PV에 네트워크로 연결해 데이터를 계속 사용 가능
# NFS
- 여러 서버 혹은 Pod에서 동시에 접근 가능한 파일 시스템을 NFS(Network File System)이라 함
# NFS를 네트워크 볼륨으로 사용하기
# 호스트(Raspberry Pi)에 직접 NFS 서버 설치 후 연결
apiVersion: v1
kind: Pod
metadata:
name: nfs-pod
spec:
containers:
- name: nfs-mount-container
image: busybox
args: ["tail", "-f", "/dev/null"]
volumeMounts:
- name: nfs-volume
mountPath: /mnt
volumes:
- name: nfs-volume
nfs:
path: "/export/nfs"
server: 192.168.0.7
- AWS나 GCP에서 제공하는 NFS 사용해도 됨
dgh0001@rpi4b:~/study$ kubectl exec -it nfs-pod -- sh
/ # df -h
Filesystem Size Used Available Use% Mounted on
192.168.0.7:/export/nfs 219.6G 28.2G 182.5G 13% /mnt
# PV와 PVC를 이용한 볼륨 관리
- 위 방식으로 NFS를 바로 명시해서 사용하면 서로 밀접하게 연관되어 있어 서로 분리할 수 없어짐
- 이를 해결하기 위해 PV와 PVC 사용

- 인프라 관리자가 네트워크 볼륨 서버로 PV 리소스를 미리 생성
- 사용자(개발자)가 포드를 정의하는 YAML 파일 등에 "영속적인 데이터 저장을 위한 외부 볼륨이 필요함"을 명시 후 해당 PVC 생성
- 쿠버네티스가 기존에 생성해뒀던 PV의 속성과 사용자가 요청한 PVC의 요구 사항이 일치하면 두 리소스를 매칭시켜 바인딩함
- 즉, 사용자는 디플로이먼트의 YAML 파일에서 볼륨의 상세한 스펙을 정의하지 않아도 됨
# Before
volumes:
- name: nfs-volume
nfs:
path: /
server: {NFS_SERVER_IP}
# After
volumes:
- name: nfs-volume
persistentVolumeClaim:
claimName: mtpvc
# PV와 PVC 사용하기
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
nfs:
path: "/export/nfs"
server: 192.168.0.7
mountOptions:
- nfsvers=4
# PVC 생성 후 Pod 생성 시 PVC적용
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: ""
accessModes: # 조건 1
- ReadWriteMany
resources:
requests:
storage: 5Gi # 조건 2
---
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-mount-container
image: busybox
args: ["tail", "-f", "/dev/null"]
volumeMounts:
- name: my-volume
mountPath: /mnt
volumes:
- name: my-volume
persistentVolumeClaim:
claimName: my-pvc
# 실행 결과
dgh0001@rpi4b:~/study$ kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS
persistentvolume/nfs-pv 10Gi RWX Retain Bound
NAME STATUS VOLUME CAPACITY ACCESS MODES
persistentvolumeclaim/my-pvc Bound nfs-pv 10Gi RWX
- PV와 PVC의 상태(STATUS)가 Bound로 설정되어 있으면 정상적으로 마운트 된 상태
PV와 PVC의 차이 - 네임스페이스
- PV는 네임스페이스에 속하지 않는 클러스터 단위의 오브젝트
- PVC는 네임스페이스에 속하는 클러스터 단위의 오브젝트
# PV를 선택하기 위한 조건들
# accessModes
| accessModes 이름 | 설명 |
|---|---|
| ReadWriteOnce | 1:1 마운트만 가능, 읽기 쓰기 가능 |
| ReadOnlyMany | 1:N 마운트 가능, 읽기 전용 |
| ReadWriteMany | 1:N 마운트 가능, 읽기 쓰기 가능 |
- 사용하는 NFS 종류에 따라 다름(ex. EBS는 1:1 관계의 마운트만 가능)
- 그 외에도 볼륨의 크기, 스토리지 클래스, 라벨 셀렉터 등이 있음
# PV의 라이프사이클과 Reclaim Policy
dgh0001@rpi4b:~/study$ kubectl delete -f nfs-pod.yaml
persistentvolumeclaim "my-pvc" deleted from default namespace
dgh0001@rpi4b:~/study$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS
nfs-pv 10Gi RWX Retain Released
- Available → Bound → Released
- Released는 해당 PV의 사용이 끝났지만, 실제 데이터들이 안에 Retain이라는 Reclaim Policy로 보존되어 있기 때문에 다시 사용 불가능함
# Retain Policy
- PVC 삭제 시 PV의 데이터를 어떻게 처리할 것인지 별도로 정의 가능
- 보통은 데이터를 영구적으로 저장하기 위해
Retain옵션 사용 Delete사용 시 자동으로 PV까지 삭제Recycle사용 시 PV의 데이터를 모두 삭제한 후 다시 Available 상태로 만들어줌 (Deprecated 예정)
# 다이나믹 프로비저닝과 스토리지 클래스
- PV를 사용하려면 미리 외부 스토리지를 준비해야 햇음
- 쿠버네티스는 다이나믹 프로비저닝을 통해 PVC와 일치하는 PV가 존재하지 않으면 자동으로 PV와 외부 스토리지를 함께 프로비저닝 함

- 위 그림과 같이 만족하는 PV가 없으면 스토리지 클래스에 정의된 속성에 따라 외부 스토리지 생성
- 다이나믹 프로비저닝 기능을 사용하기 위해서는 미리 해당 기능이 지원되는 스토리지 프로비저너가 활성화되어 있어야 함
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: test
provisioner: nfs.csi.k8s.io
parameters:
server: 192.168.0.7
share: "/export/nfs"
reclaimPolicy: Delete
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
spec:
storageClassName: test
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
# 결과
dgh0001@rpi4b:~/study$ kubectl apply -f pvc-test.yaml
persistentvolumeclaim/test-pvc created
dgh0001@rpi4b:~/study$ kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
persistentvolume/pvc-c228acb2-7053-44d4-a499-8b469d5d96c1 5Gi RWX Delete Bound default/test-pvc test <unset> 11s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
persistentvolumeclaim/test-pvc Bound pvc-c228acb2-7053-44d4-a499-8b469d5d96c1 5Gi RWX test <unset> 14s
# 특정 스토리지 클래스 기본값으로 사용
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: test
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: nfs.csi.k8s.io
parameters:
server: 192.168.0.7
share: "/export/nfs"
reclaimPolicy: Delete
- 어노테이션 추가로 사용할 디폴트 스토리지 클래스 설정 가능
# 결과
dgh0001@rpi4b:~/study$ kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
test (default) nfs.csi.k8s.io Delete Immediate false 73s
- 별도로 스토리지 클래스 명시 안하면 자동으로 기본 설정된 스토리지 클래스를 통해 다이나믹 프로비저닝 수행