✔️ 정적 프로비저닝 (Static Provisioning)
PV 및 PVC 리소스를 직접 생성하고 사용하는 방식이다.
✔️ NFS를 사용한 정적 프로비저닝 (Static Provision)
node1
을 임시 NFS 서버로 만들고 데이터를 RWX 형태로 공유해보는 실습을 진행한다.
sudo apt install nfs-kernel-server -y
nfs-kernel-server
패키지를 설치한다.
sudo mkdir /nfsvolume
echo "<h1> Hello NFS Volume </h1>" | sudo tee /nfsvolume/index.html
디렉토리를 만들고 /nfsvolume/index.html
파일을 만든다.
sudo vi /etc/exports
/nfsvolume 192.168.100.0/24(rw,sync,no_subtree_check,no_root_squash)
/etc/exports
파일을 수정한다.
NFS의 경우 노드가 3개 있고 nfs volume
을 공유할 때 파드를 생성하고 파드에 직접적으로 연결하는 것이 아니라 호스트에 마운팅을 시켜서 호스트의 kubelet
이 제공하는 형태이다.
그래서 허용하는 대역을 192.168.100.0/24
- 호스트의 네트워크 대역으로 지정해야 한다.
sudo systemctl restart nfs-kernel-server
systemctl status nfs-kernel-server
서비스를 재시작하고 active(exited)
상태인지 확인한다.
vagrant@k8s-node2:~$ sudo mount -t nfs 192.168.100.100:/nfsvolume /mnt
mount: /mnt: bad option; for several filesystems (e. g nfs, cifs) you might need a /sbin/mount.<type> helper program.
해당 오류는 ubuntu에 지원되는 마운트 파일시스템의 목록에 NFS가 없기 때문에 발생한다.
node 1, node 2, node 3에 nfs-common(NFS client)
패키지를 설치한다.
sudo apt install nfs-common -y
또는
ansible all -i ~/kubespray/inventory/mycluster/inventory.ini -m apt -a 'name=nfs-common' -b
playbook 실행
vagrant@k8s-node2:~$ sudo mount -t nfs 192.168.100.100:/nfsvolume /mnt
mount.nfs: access denied by server while mounting 192.168.100.100:/nfsvolume
권한이 없어서 연결이 되지 않는다.
vagrant@k8s-node1 ~ ls
annotation configure cont deploy kubespray label namespace nfs-subdir-external-provisioner pod podlife svc test test.yml volume
vagrant@k8s-node1 ~ cd /
vagrant@k8s-node1 / ls
a bin boot dev etc home lib lib32 lib64 libx32 lost+found media mnt nfsvolume nfsvolumel opt proc root run sbin snap srv sys tmp usr vagrant var web_contents
vagrant@k8s-node1 / ls -ld /nfsvolume
drwxr-xr-x 2 www-data www-data 4096 May 24 05:25 /nfsvolume
vagrant@k8s-node1 / grep nobody /etc/passwd
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
vagrant@k8s-node1 / grep nogroup /etc/group
nogroup:x:65534:
NFS 에서 사용하는 사용자와 그룹이다.
NFS의 경우 nobody
라는 사용자와 nogroup
이라는 그룹을 사용한다.
curl 192.168.100.240 명령 실행 시 403 Forbidden
응답이 반환되는 이유는 파일의 접근 권한이 없기 때문이다.
/usr/local/apache2/conf/httpd.conf
User www-data
Group www-data
실제 프로세스를 실행하는 사용자는 www-data
이다.www-data
이 디렉토리에 접근할 수 있어야 한다.
vagrant@k8s-node1 ~/volume/nfs kubectl exec -it myweb-rs-42pbg -- bash
root@myweb-rs-42pbg:~# cd /usr/local/apache2/htdocs
root@myweb-rs-42pbg:/usr/local/apache2/htdocs# ls -l
total 4
-rw-r--r-- 1 root root 28 May 24 05:08 index.html
마운팅된 htdocs
디렉토리는 root root만 모든 권한을 가지고 있다.www-data
사용자가 해당 파일에 접근할 수 없는 상태이다.
공유할 때는 NFS 서버쪽에 App에 접근할 수 있는 사용자가 있어야 한다.
vagrant@k8s-node1 ~/volume/nfs grep www-data /etc/group
www-data:x:33:
vagrant@k8s-node1 ~/volume/nfs grep www-data /etc/passwd
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
sudo chown -R www-data:www-data /nfsvolume
현재는 NFS 서버(k8s-node1) 쪽에 www-data
사용자가 있으므로 권한을 주면 된다.
만약 해당 사용자가 NFS 서버에 존재하지 않는다면 사용자를 추가해줘야 한다.
이때 사용자의 UID까지 확인해서 같은 이름의 사용자를 만들어야 한다.
vagrant@k8s-node1 ~/volume/nfs kubectl explain pv.spec.nfs
vagrant@k8s-node1 ~/volume/nfs kubectl explain pv.spec.
PV : mypv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mypv
spec:
accessModes: # 지원하는 모드
- ReadWriteMany # 원하는 모드를 나열한다. (nfs의 accessModes 확인 필수)
capacity: # nfs는 용량을 지정할 수 없다.
storage: 1G # nfs에서는 의미없는 숫자
persistentVolumeReclaimPolicy: Retain # 회수 정책
nfs:
path: /nfsvolume
server: 192.168.100.100
NFS는 공유할 /nfsvolume이라는 디렉토리의 사용 용량을 공유하는 것이므로 용량을 한정지을 수 없다.
정적 프로비저닝은 Retain
이 기본이며, 동적 프로비저닝은 Delete
가 기본이다.
vagrant@k8s-node1 ~/volume/nfs kubectl create -f mypv.yaml
persistentvolume/mypv created
vagrant@k8s-node1 ~/volume/nfs kubectl get all
NAME READY STATUS RESTARTS AGE
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 26h
Ingress
와 마찬가지로 all 이라는 리소스에 포함되지 않는다.
vagrant@k8s-node1 ~/volume/nfs kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv 1G RWX Retain Available 3m51s
별도로 확인해야 하며 STATUS가 Available
상태에서만 pvc
를 연결할 수 있다.
다른 모든 상태에서는 pvc
에 연결할 수 없다. 이후 pvc
에 연결되면 CLAIM
에 pvc
의 이름이 출력된다.
PVC : mypvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
spec:
accessModes:
- ReadWriteMany
resources: #
requests:
storage: 1G
storageClassName: '' # For Static Provisioning
volumeName: mypv
pv
에서 RWO만 지원한다고 하면 pvc
에서 RWX을 요청하더라도 받아주지 않는다.
반드시 accessModes
에서 지원되는 것 중에 선택해야 한다.
vagrant@k8s-node1 ~/volume/nfs kubectl explain pvc.spec.resources
limits
:requests
: 용량을 지정한다. pvc
에서의 용량은 pv
보다 같거나 작아야 허용된다.
vagrant@k8s-node1 ~/volume/nfs kubectl explain pvc.spec.
storageClassName
: 동적 프로비저닝 설정, 정적 프로비저닝을 사용하려면 비워둔다.
vagrant@k8s-node1 ~/volume/nfs kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv 1G RWX Retain Available 12m
vagrant@k8s-node1 ~/volume/nfs kubectl create -f mypvc.yaml
persistentvolumeclaim/mypvc created
vagrant@k8s-node1 ~/volume/nfs kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv 1G RWX Retain Bound default/mypvc 12m
Bound
상태이며 CLAIM
에 default/mypvc
가 출력된다.pv
는 NS를 사용하지 않고 pvc
는 NS를 사용한다.
vagrant@k8s-node1 ~/volume/nfs kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc Bound mypv 1G RWX 64s
pvc
는 Bound
상태이며 연결된 pv
와 같은 상태이다.STORAGECLASS
에 값이 있으면 동적 프로비저닝이다.
RS : 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
index.html
파일이 제공된다.
vagrant@k8s-node1 ~/volume/nfs kubectl get rs,po,pv,pvc
NAME DESIRED CURRENT READY AGE
replicaset.apps/myweb-rs 3 3 3 12s
NAME READY STATUS RESTARTS AGE
pod/myweb-rs-42pbg 1/1 Running 0 12s
pod/myweb-rs-qlr5h 1/1 Running 0 12s
pod/myweb-rs-vm7mh 1/1 Running 0 12s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/mypv 1G RWX Retain Bound default/mypvc 19m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mypvc Bound mypv 1G RWX 7m3s
SVC : myweb-rs.yaml
apiVersion: v1
kind: Service
metadata:
name: myweb-svc-lb
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
selector:
app: web
vagrant@k8s-node1 ~/volume/nfs kubectl get svc,ep
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 27h
service/myweb-svc-lb LoadBalancer 10.233.43.216 192.168.100.240 80:31676/TCP 8s
NAME ENDPOINTS AGE
endpoints/k8s-sigs.io-nfs-subdir-external-provisioner <none> 11h
endpoints/kubernetes 192.168.100.100:6443 27h
endpoints/myweb-svc-lb 10.233.90.75:80,10.233.92.116:80,10.233.96.89:80 8s
vagrant@k8s-node1 ~/volume/nfs curl 192.168.100.240
<h1> Hello NFS Volume </h1>
✔️ 정적 프로비저닝 실습
✔️ 생성
프로비저닝시에는 PV와 PVC의 생성 순서가 매우 중요하다.
반드시 PV를 먼저 생성한뒤에 PVC를 생성해야 한다.
vagrant@node1 ~/volume/nfs kubectl create -f mypv.yaml
persistentvolume/mypv created
vagrant@node1 ~/volume/nfs kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv 1G RWX Retain Available 4s
STATUS
가 Available
상태에서만 pvc
를 연결할 수 있다.
아직 pvc
가 연결되어 있지 않아 CLAIM
에 아무것도 출력되지 않는다.
vagrant@node1 ~/volume/nfs kubectl create -f mypvc.yaml
persistentvolumeclaim/mypvc created
vagrant@node1 ~/volume/nfs kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv 1G RWX Retain Bound default/mypvc 49s
pvc
는 BOUND
상태가 되며 실제 pv
를 요청한 pvc
는 default NS의 mypvc
이다.
vagrant@node1 ~/volume/nfs kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc Bound mypv 1G RWX 23s
Bound
상태이며 연결되어 있는 VOLUME
은 mypv
이다.
vagrant@k8s-node1 ~/volume/nfs kubectl create -f myweb-rs.yaml
vagrant@k8s-node1 ~/volume/nfs kubectl get po
NAME READY STATUS RESTARTS AGE
myweb-rs-42pbg 1/1 Running 0 57m
myweb-rs-qlr5h 1/1 Running 0 57m
myweb-rs-vm7mh 1/1 Running 0 57m
vagrant@k8s-node1 ~/volume/nfs kubectl create -f myweb-svc-lb.yaml
vagrant@k8s-node1 ~/volume/nfs kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 28h
myweb-svc-lb LoadBalancer 10.233.43.216 192.168.100.240 80:31676/TCP 28m
vagrant@k8s-node1 ~/volume/nfs curl 192.168.100.240
<h1> Hello NFS Volume </h1>
vagrant@k8s-node1 ~/volume/nfs curl 192.168.100.240
<h1> Hello NFS Volume </h1>
vagrant@k8s-node1 ~/volume/nfs curl 192.168.100.240
<h1> Hello NFS Volume </h1>
어떤 파드던지 동일한 내용을 출력한다.
✔️ 삭제
삭제도 마찬가지로 순서가 중요하다.
삭제시에는 생성 순서와 역순으로 PVC를 먼저 삭제한뒤 PV를 삭제해야한다.
vagrant@k8s-node1 ~/volume/nfs kubectl delete -f myweb-rs.yaml
replicaset.apps "myweb-rs" deleted
vagrant@k8s-node1 ~/volume/nfs kubectl get po
NAME READY STATUS RESTARTS AGE
myweb-rs
를 삭제한다.
vagrant@k8s-node1 ~/volume/nfs kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/mypv 1G RWX Retain Bound default/mypvc 81m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mypvc Bound mypv 1G RWX 68m
pv
와 pvc
는 아무 변동이 없다. 그대로 Bound
상태이다.
vagrant@k8s-node1 ~/volume/nfs kubectl create -f myweb-rs.yaml
replicaset.apps/myweb-rs created
vagrant@k8s-node1 ~/volume/nfs kubectl get po
NAME READY STATUS RESTARTS AGE
myweb-rs-4csjs 1/1 Running 0 5s
myweb-rs-4xb5m 1/1 Running 0 5s
myweb-rs-pqk42 1/1 Running 0 5s
vagrant@k8s-node1 ~/volume/nfs curl 192.168.100.240
<h1> Hello NFS Volume </h1>
vagrant@k8s-node1 ~/volume/nfs curl 192.168.100.240
<h1> Hello NFS Volume </h1>
파드를 다시 만들면 스토리지에 정상적으로 접근할 수 있다.
RS에 의해 파드 3개가 만들어졌고 모두 동일한 pvc
에 연결되어 있다.pvc
는 pv
에 연결되어 있고 pv
는 실제 NFS 스토리지에 연결되어 있는 형태이다.
파드를 삭제하거나 복제본 개수를 늘리던 간에 항상 같은 pvc
에 연결되며 해당되는 동일한 스토리지를 사용할 수 있게 된다.
vagrant@k8s-node1 ~/volume/nfs kubectl delete -f myweb-rs.yaml
replicaset.apps "myweb-rs" deleted
파드를 지우고 pvc
를 삭제해본다.
현재는 pvc
와 pv
가 Bound
상태로 연결되어 있다. Bound
상태에서 pv
는 지워지지 않는다.
vagrant@k8s-node1 ~/volume/nfs kubectl delete -f mypvc.yaml
persistentvolumeclaim "mypvc" deleted
vagrant@k8s-node1 ~/volume/nfs kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/mypv 1G RWX Retain Released default/mypvc 86m
# 다시 pvc 생성 후 연결하기
vagrant@k8s-node1 ~/volume/nfs kubectl create -f mypvc.yaml
persistentvolumeclaim/mypvc created
vagrant@k8s-node1 ~/volume/nfs kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/mypv 1G RWX Retain Released default/mypvc 88m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mypvc Pending mypv 0 5s
그래서 항상 pvc
를 먼저 지워야 하는데 pvc
를 지우면 pv
는 Released
, 해제된 상태가 되고 이 상태에서 다시 pvc
를 생성해서 연결하면 연결되지 않는다.
pv
는 Released
상태이고 pvc
는 Pending
상태로 아직 연결되지 않았다.
즉, Released
상태의 pv
를 연결할 수 없다. 결국 사용이 불가하다.
그래서 recycle
이라는 정책을 만들었으나 스토리지마다 데이터를 삭제하는 방법이 다양하고 각각 달라서 k8s에서 구현하기 어렵다. 그래서 해당 정책은 폐지됐다.
vagrant@k8s-node1 ~/volume/nfs kubectl describe pvc mypvc
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedBinding 4s (x15 over 3m27s) persistentvolume-controller volume "mypv" already bound to a different claim.
시간이 지나도 연결되지 않으며 FailedBinding
, 마운팅이 되지 않는다.mypv
가 이미 바운드된 상태이기 때문에 claim
하기 어렵다.
그렇지만 Bound
상태가 아닌 Released
상태에서도 연결되지 않는다.
vagrant@k8s-node1 ~/volume/nfs kubectl delete -f mypvc.yaml -f mypv.yaml
persistentvolumeclaim "mypvc" deleted
persistentvolume "mypv" deleted
vagrant@k8s-node1 ~/volume/nfs kubectl create -f mypv.yaml
persistentvolume/mypv created
vagrant@k8s-node1 ~/volume/nfs kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv 1G RWX Retain Available 16s
vagrant@k8s-node1 ~/volume/nfs kubectl create -f mypvc.yaml
persistentvolumeclaim/mypvc created
vagrant@k8s-node1 ~/volume/nfs kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/mypv 1G RWX Retain Bound default/mypvc 25s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mypvc Pending mypv 0 6s
따라서 우선 pv
, pvc
를 모두 삭제하고 pv
→ pvc
순서로 생성해야 Bound
상태가 되며 파드가 사용할 수 있게 된다.
vagrant@k8s-node1 ~/volume/nfs kubectl delete -f mypv.yaml
persistentvolume "mypv" deleted # forground로 열려있는 상태
# 다른 터미널에서 pvc를 삭제하면
vagrant@k8s-node1 ~/volume/nfs kubectl delete -f mypvc.yaml
persistentvolumeclaim "mypvc" deleted
# 그때 pv도 삭제되며 모두 삭제된다.
vagrant@k8s-node1 ~/volume/nfs kubectl get pv,pvc
No resources found
바운드 상태에서 pv
를 먼저 지우면 지워지지 않는다.
forground로 열려있는 상태에서 다른 터미널 창을 열어 pvc
를 삭제하면 그때 삭제된다.
✔️ 정적 프로비저닝의 문제점
파드, pvc
, pv
를 모두 지운 상태에서 NFS 스토리지를 다시 사용해야 한다면 매번 pv
를 만들고 pvc
를 만들고 파드를 만들어서 연결시켜야 하는 작업을 반복해야 한다.
매우 번거로운 작업을 반복해야 할지도 모른다.
따라서 보통 동적 프로비저닝을 사용한다.
동적 프로비저닝을 사용하면 pvc
를 만들면 pvc
에 바운딩 될 pv
를 자동으로 만들어준다.
그리고 pv
가 실제 스토리지에 연결된다.
그렇다면 어떤 근거에 의해 pv
를 만들것인가 ? template
이 있는가 ?
그것을 storageClass
라고 한다.
storageClass
는 pv
를 만들기 위한 템플릿을 가지고 있다.pvc
를 만들 때 storageClass
를 지정하면 해당 storageClass
의 정보를 가지고 pv
를 만들어서 스토리지에 연결시킨다.
관리자는 storageClass
를 만들어 놓으면 되고 사용자는 pvc
를 만들 때 어떤 pvc
를 사용할 것인지를 결정만 하면 된다. 그러면 해당 storageClass
에서 pv
를 자동으로 만들어준다.
'DevOps > Kubernetes' 카테고리의 다른 글
[Kubernetes] 동적 프로비저닝 (Dynamic Provisioning) ( + NFS 동적 프로비저닝) (0) | 2022.05.29 |
---|---|
[Kubernetes] Storage Classes (스토리지 클래스) (0) | 2022.05.29 |
[Kubernetes] PV(PersistentVolume), PVC(PersistentVolumeClaim) (0) | 2022.05.29 |
[Kubernetes] Volume (emptyDir, gitRepo, initContainer, hostPath) (0) | 2022.05.29 |
[Kubernetes] Readiness Probe (준비성 프로브) (0) | 2022.05.29 |
영차영차 성장 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!