영구 볼륨을 미리 생성해두고, 영구 볼륨 클레임 요청에 따라 바인딩하여 사용하는 기본 방식에는 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

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,