[Kubernetes] 동적 프로비저닝 (Dynamic Provisioning) ( + NFS 동적 프로비저닝)
✔️ Dynamic Provisioning (동적 프로비저닝)
지금까지 PV를 사용하려면 미리 외부 스토리지를 준비해야만 했다.
예를 들어 AWS EBS를 PV로 사용하려면 EBS를 미리 생성한 뒤, 볼륨 ID를 YAML 파일에 직접 입력하는 방식으로 사용했다. 하지만 매번 이렇게 볼륨 스토리지를 직접 수동으로 생성하고 스토리지에 대한 접근 정보를 YAML 파일에 적는 것은 귀찮은 일이다.
이를 위해 쿠버네티스는 Dynamic Provisioning 기능을 제공한다.
다이나믹 프로비저닝은 PVC이 요구하는 조건과 일치하는 PV이 존재하지 않는다면 자동으로 PV와 외부 스토리지를 함께 프로비저닝하는 기능이다. 따라서 Dynamic Provisioning을 사용하면 EBS와 같은 외부 스토리지를 직접 미리 생성해 둘 필요가 없다. PVC를 생성하면 외부 스토리지가 자동으로 생성되기 때문이다.
Dynamic Provisioning에서도 스토리지 클래스를 사용할 수 있는데 Dynamic Provisioning은 스토리지 클래스의 정보를 참고해 외부 스토리지를 생성한다.
즉, 클러스터 관리자가 PV provisioner
를 배포하고 하나 이상의 스토리지 클래스 객체를 정의해서 개발자가 작성한 PVC 요청이 있을 때 마다 새 PV를 생성할 수 있게 한다.
단, Dynamic Provisioning을 모든 쿠버네티스 클러스터에서 범용적으로 사용할 수 있는 것은 아니며, 다이나믹 프로비저닝 기능이 지원되는 스토리지 프로비저너가 미리 활성화돼 있어야 한다.
✔️ NFS Dynamic Provisioner 구성
쿠버네티스에는 내장 NFS 프로비저너가 없다. NFS를 위한 스토리지 클래스를 생성하려면 외부 프로비저너를 사용해야 한다.
예시는 다음과 같다.
NFS subdir external provisioner
vagrant@k8s-node1 ~ sudo mkdir /nfsvolume
root 밑에 nfsvolume
디렉토리를 만든다.
vagrant@k8s-node1 ~ git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner.git
git 레포지토리를 동기화 시킨다.
vagrant@k8s-node1 ~ ls
annotation cont deploy kubespray label namespace nfs-subdir-external-provisioner pod podlife svc test test.yml volume
vagrant@k8s-node1 ~ cd nfs-subdir-external-provisioner
vagrant@k8s-node1 ~/nfs-subdir-external-provisioner master ls
CHANGELOG.md Dockerfile LICENSE OWNERS README.md SECURITY_CONTACTS cloudbuild.yaml code-of-conduct.md docker go.sum vendor
CONTRIBUTING.md Dockerfile.multiarch Makefile OWNERS_ALIASES RELEASE.md charts cmd deploy go.mod release-tools
vagrant@k8s-node1 ~/nfs-subdir-external-provisioner master cd deploy
deploy
디렉토리에 들어온다.
vagrant@k8s-node1 ~/nfs-subdir-external-provisioner/deploy master ls
class.yaml deployment.yaml objects rbac.yaml test-claim.yaml test-pod.yaml
vagrant@k8s-node1 ~/nfs-subdir-external-provisioner/deploy master kubectl create -f rbac.yaml
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rbac.yaml
파일 적용하기
vagrant@k8s-node1 ~/nfs-subdir-external-provisioner/deploy master vi deployment.yaml
env: # App에 제공할 환경 변수
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 192.168.100.100
- name: NFS_PATH
value: /nfsvolume
volumes:
- name: nfs-client-root
nfs:
server: 192.168.100.100
path: /nfsvolume
deployment.yaml
수정해서 NFS 서버 위치 지정하기
vagrant@k8s-node1 ~/nfs-subdir-external-provisioner/deploy master ± kubectl create -f deployment.yaml
deployment.apps/nfs-client-provisioner created
deployment.yaml
파일 적용하기
vagrant@k8s-node1 ~/nfs-subdir-external-provisioner/deploy master ± cat class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
archiveOnDelete: "false"
vagrant@k8s-node1 ~/nfs-subdir-external-provisioner/deploy master ± kubectl create -f class.yaml
storageclass.storage.k8s.io/nfs-client created
class.yaml
파일까지 적용하면 설치 완료
vagrant@k8s-node1 ~/nfs-subdir-external-provisioner/deploy master ± kubectl get deploy,rs,po
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nfs-client-provisioner 1/1 1 1 64s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nfs-client-provisioner-758f8cd4d6 1 1 1 64s
NAME READY STATUS RESTARTS AGE
pod/nfs-client-provisioner-758f8cd4d6-wpjbt 1/1 Running 0 64s
확인
vagrant@k8s-node1 ~/nfs-subdir-external-provisioner/deploy master ± kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 39s
클라우드가 아니므로 기본적으로 Immediate
로 설정된다.
mypvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc-dynamic
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1G
storageClassName: 'nfs-client'
vagrant@k8s-node1 ~/volume/nfs-dynamic kubectl create -f mypvc.yaml
persistentvolumeclaim/mypvc-dynamic created
vagrant@k8s-node1 ~/volume/nfs-dynamic kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-cf9ea92a-aa68-4df1-9fa4-91d953c04d2d 1G RWX Delete Bound default/mypvc-dynamic nfs-client 6s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mypvc-dynamic Bound pvc-cf9ea92a-aa68-4df1-9fa4-91d953c04d2d 1G RWX nfs-client 6s
mypvc-dynamic
를 생성했고 Bound
상태이며 연결될 볼륨은 랜덤한 이름으로 생성된 pvc-cf9ea92a-aa68-4df1-9fa4-91d953c04d2d
로 pv
의 이름과 일치한다. 용량은 1G이고 STORAGECLASS
가 nfs-client
이다.
pvc
입장에서 CLAIM
은 default NS의 mypvc-dynamic
이다.
이와 같이 pvc
만 만들면 STORAGECLASS
에 의해 자동으로 pv
가 생성된다.
vagrant@k8s-node1 ~/volume/nfs-dynamic sudo ls -l /nfsvolume
total 8
drwxrwxrwx 2 root root 4096 May 24 05:18 default-mypvc-dynamic-pvc-cf9ea92a-aa68-4df1-9fa4-91d953c04d2d
디렉토리가 만들어진 것을 확인할 수 있다.
NS명 + pvc
명 + pv
명으로 디렉토리가 생성되었고 데이터는 해당 디렉토리에 저장된다.
vagrant@k8s-node1 ~/volume/nfs-dynamic sudo ls -l /nfsvolume/default-mypvc-dynamic-pvc-cf9ea92a-aa68-4df1-9fa4-91d953c04d2d
total 0
vagrant@k8s-node1 ~/volume/nfs-dynamic echo "<h1> Hello NFS Dynamic Provision </h1>" | sudo tee /nfsvolume/default-mypvc-dynamic-pvc-cf9ea92a-aa68-4df1-9fa4-91d953c04d2d/index.html
<h1> Hello NFS Dynamic Provision </h1>
디렉토리에 index.html
파일을 만든다.
myweb-rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myweb-rs
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: myweb
image: httpd
volumeMounts:
- name: myvol
mountPath: /usr/local/apache2/htdocs
volumes:
- name: myvol
persistentVolumeClaim:
claimName: mypvc-dynamic
vagrant@k8s-node1 ~/volume/nfs-dynamic kubectl create -f myweb-rs.yaml -f myweb-svc-lb.yaml
replicaset.apps/myweb-rs created
service/myweb-svc-lb created
리소스를 생성한다.
vagrant@k8s-node1 ~/volume/nfs-dynamic kubectl get po
NAME READY STATUS RESTARTS AGE
myweb-rs-lsmnd 1/1 Running 0 9s
myweb-rs-st9d4 1/1 Running 0 9s
myweb-rs-xhv65 1/1 Running 0 9s
nfs-client-provisioner-758f8cd4d6-wpjbt 1/1 Running 0 11m
vagrant@k8s-node1 ~/volume/nfs-dynamic curl 192.168.100.240
<h1> Hello NFS Dynamic Provision </h1>
vagrant@k8s-node1 ~/volume/nfs-dynamic kubectl delete -f .
persistentvolumeclaim "mypvc-dynamic" deleted
replicaset.apps "myweb-rs" deleted
service "myweb-svc-lb" deleted
vagrant@k8s-node1 ~/volume/nfs-dynamic kubectl get pv,pvc
No resources found
vagrant@k8s-node1 ~/volume/nfs-dynamic kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client (default) k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 28h
RECLAIMPOLICY
이 Delete
이므로 pvc
를 지우면 pv
도 같이 지워진다.
데이터를 남기고 싶으면 Retain
정책을 사용하면 된다.