영구 볼륨을 미리 생성해두고, 영구 볼륨 클레임 요청에 따라 바인딩하여 사용하는 기본 방식에는 2가지 단점이 있다.
- 사전에 영구 볼륨을 미리 생성해두어야 한다는 번거로움
- 영구 볼륨 클레임이 요청하는 용량 이상의 영구 볼륨이 할당되어 사용되지 못하는 용량이 발생되는 문제
2번째 문제에 대해서, 영구 볼륨의 용량이 10Gi 이고, 영구 볼륨 클레임이 요청하는 용량이 5Gi 인 경우를 예를 들어보자.
쿠버네티스에서 PV 와 PVC 의 바인딩은 1:1 관계이다. 따라서 아래와 같은 특징이 있다.
- 독점적 바인딩: PVC가 특정 PV와 연결(Bound)되면, 해당 PV 전체가 그 PVC의 소유가 됨
- 분할 불가: 10GiB 용량의 PV 하나를 여러 개의 PVC(예: 5GiB + 5GiB)가 나누어 가질 수 없음
결과적으로, 5Gi 만 요청했더라도 바인딩 되는 순간 그 PV는 사용중 상태가 되어 다른 PVC 에 바인딩 되지 못하는 상태가 된다. 단, PVC의 5Gi 요청은 바인딩을 위한 "신청서" 일 뿐, 실제 볼륨의 물리적 크기를 제한하지는 않기 때문에, 파드에서는 실제로 10Gi 만큼의 공간을 다 쓸 수 있긴 하다.
여튼, 이러한 문제를 해결하는 것이 동적 프로비저닝(Dynamic Provisioning)이다. 동적 프로비저닝을 사용하면 영구 볼륨 클레임이 생성되는 시점에 동적으로 영구 볼륨을 생성하고 할당한다. 따라서 미리 영구 볼륨을 생성할 필요가 없고, 딱 필요한 용량만큼만 보유한 영구 볼륨을 생성할 수 있게 된다.
1. 동적 프로비저닝 설정
간단히 설명하면 스토리지 클래스의 provisioner 를 동적 프로비저너로 지정하고, 이를 영구 볼륨 클레임에서 사용하면 된다. 파드 매니페스트에 컨테이너 템플릿을 지정하듯이, 스토리지 클래스 매니페스트에 어떤 영구 볼륨을 동적으로 생성할지 정의한다.
퍼블릭 클라우드 프로바이더의 관리형 k8s 플랫폼에서는 기본적으로 동적 프로비저닝을 사용하는 스토리지 클래스가 생성되어 있지만, 지금처럼 따로 구축한 쿠버네티스 클러스터에서 static NFS 타입의 스토리지에서 동적 프로비저닝을 사용하기 위해서는 아래와 같이 진행한다.
1.1 RBAC 권한 설정
프로비저너가 PV를 생성/삭제할 수 있는 권한을 부여하기 위해 아래 매니페스트로 권한을 생성/할당한다.
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default # 프로비저너를 배포할 네임스페이스
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
$ kubectl get sa nfs-client-provisioner
NAME SECRETS AGE
nfs-client-provisioner 0 77m
1.2 프로비저너를 Deployment 로 배포
아래 매니페스트를 이용하여 배포한다. 단, <NFS_SERVER_IP> 는 본인의 NFS 서버 IP로, <NFS_EXPORT_PATH> 는 본인의 NFS 서버 경로로 하여 환경변수를 세팅한다. 지정하는 serviceAccount 이름이 RBAC 의 serviceAccount 이름인 "nfs-client-provisioner" 와 일치해야 한다. "registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2" 버전은 본인이 사용하는 쿠버네티스 버전과 호환되는 버전을 사용한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: <NFS_SERVER_IP>
- name: NFS_PATH
value: <NFS_EXPORT_PATH>
volumes:
- name: nfs-client-root
nfs:
server: <NFS_SERVER_IP>
path: <NFS_EXPORT_PATH>
$ kubectl get deployment nfs-client-provisioner
NAME READY UP-TO-DATE AVAILABLE AGE
nfs-client-provisioner 1/1 1 1 62m
1.3 스토리지 클래스 생성
아래 매니페스트로 스토리지 클래스를 생성해둔다.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # 위 Deployment의 PROVISIONER_NAME과 일치해야 함
parameters:
archiveOnDelete: "false"
reclaimPolicy: Delete
$ kubectl get sc nfs-client
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 51m
1.4 PVC 생성하여 동적 프로비저닝 확인
아래 매니페스트처럼 "nfs-client" 스토리지 클래스를 지정한 PVC 를 생성한 후 동적 프로비저닝이 되었는지 확인한다.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: sample-nfs-provisioning-pvc
spec:
storageClassName: nfs-client
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Mi
# PVC 확인
$ kubectl get pvc sample-nfs-provisioning-pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
sample-nfs-provisioning-pvc Bound pvc-49196cda-866a-4210-b7a7-7fad1e092a64 200Mi RWO nfs-client <unset> 48m
# 동적 프로비저닝된 PV 확인
$ kubectl get pv pvc-49196cda-866a-4210-b7a7-7fad1e092a64
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
pvc-49196cda-866a-4210-b7a7-7fad1e092a64 200Mi RWO Delete Bound default/sample-nfs-provisioning-pvc nfs-client <unset> 49m
이렇게 PV 가 동적 프로비저닝 된 후에는, 수동으로 영구 볼륨을 생성한 경우와 동일하게 파드에서 사용하면 된다.
2. 동적 프로비저닝 된 PV 삭제
위에서 스토리지 클래스 설정에 reclaimPolicy: Delete 를 지정했기 때문에, PVC 를 삭제하여 바인딩이 해제되면 자동으로 PV가 삭제된다.
# PVC 삭제
$ kubectl delete -f sample-nfs-provisioning-pvc.yaml
persistentvolumeclaim "sample-nfs-provisioning-pvc" deleted
$ kubectl get pv
No resources found
'Kubernetes' 카테고리의 다른 글
| [Kubernetes] 블록 장치를 영구 볼륨으로 사용하기 (0) | 2026.02.22 |
|---|---|
| [Kubernetes] volumeBindingMode 영구 볼륨 할당 타이밍 제어 (0) | 2026.02.18 |
| [Kubernetes] PersistentVolumeClaim 이해 (0) | 2026.02.16 |
| [Kubernetes] PersistentVolume 이해 (0) | 2026.02.11 |
| [Kubernetes] Volume 이해와 종류 (0) | 2026.01.31 |
