[클라우드/K8S 기본(8) - PV와 PVC]

SooYeon Yeon·2022년 9월 13일
0

클라우드 K8S

목록 보기
10/18

PV(Persistent Volume)과 PVC(Persistent Volume Claim)

볼륨(Volume) vs PV/PVC

볼륨

  • 관리자가 볼륨 제공, 요청을 동시에 수행
  • 관리자는 포드 구성 및 포드 내에 저장소의 위치 (IP), 디렉토리 명 등을 정확히 알고 있어야 한다.

PV/PVC

  • PVC는 개발자가, PV는 관리자가 작성한다.
  • PVC는 볼륨이 어떤 형태로 제공되는 지 (NFS, iscsi ..) 몰라도 된다. 단지, 자신이 필요한 볼륨의 유형과 크기만 작성하면 된다. (rw, ro 등(읽고쓰기) / one to one, many to one 등 / 1G, 10G 등)
  • PV는 관리자가 NFS, ISCSI 등을 이용하여 적절한 크기의 볼륨을 만들어 이를 pool에 보관한다.
  1. master 노드에 NFS 마운트 위한 서버 설치
    1. 211.183.3.100에 nfs-server를 구축한다.

manager

apt install -y nfs-server # manager에는 nfs 서버 설치
systemctl enable nfs-server --now
  1. manager에 /shared 디렉토리를 생성하고 퍼미션을 777로 조정한다.

mkdir -p ~/shared
chmod 777 shared/
  1. /etc/exports에 /shared를 외부에 공개하도록 설정한다. 단, pod에서만 접속이 가능하게 한다. 어떤 주소를 허용해야 하는가? /shared 허용할주소(rw,no_root_squash,sync)
vi /etc/exports
/root/shared 211.183.3.0/24(rw,no_root_squash,sync)

해당 내용 추가

no_root_squash : 외부 노드에서 작성한 파일을 로컬(nfs-server)에서 확인했을 때 root가 작성한 것으로(소유주가 root) 간주해 준다.

  1. nfs-server 활성화/실행
ufw disable
systemctl restart nfs-server
  • worker1~3에 nfs client 설치
apt install -y nfs-common # worker에는 nfs client 설치
  1. 아래 pod 구성을 위한 매니페스트 파일을참고해 포드3개를 배포하고, 포드의 /mnt를 nfs-server의 /shared와 마운트 한다.

생성된 공유 저장소 마운트를 위한 pod 배포

27페이지 2 예시

root@master1:~/k8s# cat nfs-pod.yaml 
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           # 포드 컨테이너 내부의 /mnt 디렉터리에 마운트합니다.
  volumes:
  - name : nfs-volume
    nfs:                            # NFS 서버의 볼륨을 포드의 컨테이너에 마운트합니다.
      path: /k8s
      server: 211.183.3.99
  • nfs-pod,yaml
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           # 포드 컨테이너 내부의 /mnt 디렉터리에 마운트합니다.
  volumes:
  - name: nfs-volume
    nfs:                            # NFS 서버의 볼륨을 포드의 컨테이너에 마운트합니다.
      path: /shared  
      server: 211.183.3.100
root@manager:~# kubectl apply -f nfs-pod.yaml
pod/nfs-pod created
  1. manager에서 /shared에 임의 파일을 생성하고 pod에서 exec를 활용하여 해당 파일을 볼 수 있어야 한다. 포드에서 볼 수 있어야 한다
root@manager:~/k8slab# kubectl exec nfs-pod -- ls /mnt
nfsvolume.txt

기본적으로 nfs 의 공유 저장소에 외부 사용자가 접속하여 파일을 생성하게 되면 이 소유주는 "nfsnobody" 로 작성된다. 하지만 /etc/exports 에 no_root_squash 가 옵션으로 작성되어 있다면 외부 사용자가 파일을 생성하더라도 root 로 기록된다.

볼륨, PV/PVC

볼륨 사용하기

  1. host path, localhost: 데이터를 영구적으로 보관하기 어렵다.
  2. 포드간 스토리지 공유 → 포드 하나를 스토리지 용으로 활용하고, 클러스터를 통해 타 호스트에 있는 포드에서도 접근 할 수 있다. 스토리지용 포드가 삭제된다면?
  3. 외부에 스토리지를 두고 이를 연결하는 방법을 사용해야 한다.
    1. file storage - 서버 → 디렉토리 → NFS (/shared)
    2. block storage - 서버→ 볼륨제공 → /dev/sda (장치)
    3. object storage - 사용자별 일정 공간제공→ 사용자별(계정)로 지정된 공간, 위치에 상관 X, 버킷 이름 유니크 해야 함

운영자와 개발자의 구분에 따른 이용

  1. yaml 파일 내에 볼륨을 정의한다. 해당 정의에는 nfs, 주소, 디렉토리명 등을 기입하고 이를 포드에 연결하는 형태로 작성한다.
  2. 운영자와 개발자가 별도인 경우 개발자가 저장소의 위치, 프로토콜, 볼륨 등을 세세히 알 수 없는 문제가 있다. 이 경우 운영자는 볼륨을 만들어 이를 pool에 보관하고, 개발자는 자신이 필요한 정보(볼륨 크기, Many/Once, PVC 없을 경우 재사용 여부)만을 요청하면 해당 정보와 매칭되는 볼륨(풀에 담겨 있는)을 자동으로 연결시켜 준다.

개발자가 10GB(최소용량) — pool에 담긴 볼륨(20GB) : 10G보다 많더라도 연결된다

반대로 개발자가 20GB 필요 — pool에 담긴 볼륨(10GB) : 연결되지 않는다

Storage class (ACL) - 동적 프로비저닝에 많이 활용

Selector + label

실습

  • lb-config 먼저 배포 해야함
  • lb-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: | # 이게 없다면 그대로 찍어내지 못하게 됨i
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 211.183.3.201-211.183.3.210
    - name: kia
      protocol: layer2
      addresses:
      - 211.183.3.211-211.183.3.220
    - name: sk
      protocol: layer2
      addresses:
      - 211.183.3.221-211.183.3.230
root@manager:~/k8slab/lab1# kubectl apply -f lb-config.yaml
configmap/config created

pool에서 차례대로 받아오게 될 것

  • /shared 만들고 /etc/exports에 등록
root@manager:~# mkdir /shared
root@manager:~# curl -L http://www.nginx.com > /shared/index.html
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--   0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--   0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--   0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--   0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--   0     0    0     0    0     0      0      0 --:--:--  0:00:04 --:--:--   0     0    0     0    0     0      0      0 --:--:--  0:00:05 --:--:-- 100   162    0   162    0     0     28      0 --:--:--  0:00:05 --:--:--    36
100  4947    0  4947    0     0    810      0 --:--:--  0:00:06 --:--:-- 100  399k    0  399k    0     0  62736      0 --:--:--  0:00:06 --:--:--  959k
vi /etc/exports
/shared 211.183.3.0/24(rw,no_root_squash,sync)
/kia 211.183.3.0/24(rw,no_root_squash,sync)
/sk 211.183.3.0/24(rw,no_root_squash,sync)

해당 내용이 들어가 있는 지 확인 /shared

  • nfs-ip.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-ip
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nfs-ip
  template:
    metadata:
      name: my-nfs-ip
      labels:
        app: nfs-ip
    spec:
      containers:
      - name: webserver
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nfs-vol
          mountPath: /usr/share/nginx/html/lab3
      volumes:
      - name: nfs-vol
        nfs:
          server: 211.183.3.100
          path: /shared
---
apiVersion: v1
kind: Service
metadata:
  name: nfslb
spec:
  ports:
  - name: nfslb-port
    port: 80 # 서비스의 포트, LB니까 LB의 80포트
    targetPort: 80
  selector:
    app: nfs-ip
  type: LoadBalancer

systemctl status nfs-server로 nfs 켜져있는 지 확인하고 배포(restart도)

  • 배포하기
root@manager:~/k8slab/lab3_volume# kubectl apply -f nfs-ip.yaml
deployment.apps/nfs-ip created
service/nfslb created
  • 확인
root@manager:~/k8slab/lab3_volume# kubectl get pod,deploy,svc
NAME                        READY   STATUS             RESTARTS   AGE
pod/nfs-ip-cf4bb796-cnh5f   1/1     Running            0          8s
pod/nfs-ip-cf4bb796-d9zpb   1/1     Running            0          8s
pod/nfs-ip-cf4bb796-n8sb2   1/1     Running            0          8s
pod/nfs-pod                 1/1     Running            1          25h
pod/private-reg             0/1     CrashLoopBackOff   28         17h

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nfs-ip   3/3     3            3           8s

NAME                 TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)        AGE
service/kubernetes   ClusterIP      10.96.0.1        <none>          443/TCP        47h
service/nfslb        LoadBalancer   10.106.128.233   211.183.3.211   80:30492/TCP   8s

윈도우에서 http://211.183.3.2xx→ nginx 기본페이지, http://211.183.3.2xx/lab3 → 미리 /shared에 복사해둔 nginx 홈페이지 내용이 보여야한다

PV와 PVC

PV, PVC 실습

  • 파일 만들기
root@manager:~/k8slab/pvpvclab# touch pv.yaml pvc.yaml deploy.yaml

pv : ops가 함

pvc, deploy : dev가 함

  • pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: "100Mi"
  accessModes:
    - ReadWriteMany # r,w,여러사람동시접속가능, 혼자만 접속한다면 Once
  persistentVolumeReclaimPolicy: Retain # PVC가 제거됐을 때 PV가 작동하는 방법정의(
유지는 Retain, 삭제는 Delete, Recycle:데이터는 삭제하는데 볼륨은 남겨둠(잘 쓰지않음))
  nfs:
    server: 211.183.3.100
    path: /shared
  • pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 50Mi
  • pv, pvc 배포하기
root@manager:~/k8slab/pvpvclab# kubectl apply -f .
persistentvolume/nfs-pv created
persistentvolumeclaim/pvc created
root@manager:~/k8slab/pvpvclab# kubectl get pv,pvc
NAME                      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM         STORAGECLASS   REASON   AGE
persistentvolume/nfs-pv   100Mi      RWX            Retain           Bound    default/pvc                           37s

NAME                        STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/pvc   Bound    nfs-pv   100Mi      RWX                           38s

pv가 넣어둔 것은 100Mi고, pvc가 요구한 것은 50Mi일때 Bound되고, 용량이 100Mi가 된 것을 볼 수 있다.

pvc를 바꿔서 만약, pv가 넣어둔 것은 100Mi이고 pvc가 요구한 것은 200Mi일 때

root@manager:~/k8slab/pvpvclab# kubectl get pv,pvc
NAME                      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
persistentvolume/nfs-pv   100Mi      RWX            Retain           Available                                   5s

NAME                        STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/pvc   Pending                                                     5s

PVC는 Pending 상태이고, PV는 연결안되어서 Available(독립적인상태)임.

PV의 상태

  1. Available : 독립적인 상태
  2. Bound : 연결이 된 상태
  3. Release : 연결이 되었다가 해제 된 상태
  • 다시 pvc를 똑같이 100으로 바꿔서 배포해보기
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 100Mi
root@manager:~/k8slab/pvpvclab# kubectl apply -f .
persistentvolume/nfs-pv created
persistentvolumeclaim/pvc created
  • shared 밑에 index 파일 넣어두기
root@manager:~/k8slab/pvpvclab# mkdir /shared ; chmod 777 /shared
root@manager:~/k8slab/pvpvclab# echo "HELLO ALL" > /shared/index.html

nfs-server 동작 확인

vi /etc/exports

/shared 211.183.3.0/24(rw,no_root_squash,sync) #추가
  • deploy.yaml
  • 요청서를 pod 안에 넣는다
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-pvc-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: testnginx
        image: nginx
        volumeMounts:
        - name: pvpvc
          mountPath: /usr/share/nginx/html
      volumes:
      - name: pvpvc
        persistentVolumeClaim:
          claimName: pvc
root@manager:~/k8slab/pvpvclab# kubectl apply -f deploy.yaml
deployment.apps/nfs-pvc-deploy created
root@manager:~/k8slab/pvpvclab# kubectl exec nfs-pvc-deploy-7694f559b4-q9vtj -- ls /usr/share/nginx/html
index.html
root@manager:~/k8slab/pvpvclab# kubectl exec nfs-pvc-deploy-7694f559b4-q9vtj -- df -h
Filesystem             Size  Used Avail Use% Mounted on
overlay                 20G  9.9G  8.2G  55% /
tmpfs                   64M     0   64M   0% /dev
tmpfs                  971M     0  971M   0% /sys/fs/cgroup
/dev/sda5               20G  9.9G  8.2G  55% /etc/hosts
shm                     64M     0   64M   0% /dev/shm
**211.183.3.100:/shared   20G  9.8G  8.3G  55% /usr/share/nginx/html**
tmpfs                  971M   12K  971M   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                  971M     0  971M   0% /proc/acpi
tmpfs                  971M     0  971M   0% /proc/scsi
tmpfs                  971M     0  971M   0% /sys/firmware

포드 안에 마운트 정보가 있다. 100Mi했었는데, 지금 보면 20G 쓸 수 있다고 나온다. 원래 /shared가 211.183.3.100에 있었고, 실제로는 host의 /dev/sda5에 해당하기 때문에 이 정보를 그대로 보여주는 것

만약 pod 생성이 안된다면 nfs 서버를 restart 해보자. /etc/exports가 반영이 안되어서 그런 것일지도

볼륨 용량 제한

쿼터

  • 파일 시스템마다 사용자나 그룹이 생성할 수 있는 파일의 용량과 개수를 제한하는 것

soft : 20 MB

hard: 30 MB 이면 , 20넘고 30에 warning뜨는데, 20넘는 부분부터는 7일 이내에 삭제된다.

  • quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: testquota
spec:
  hard:
    persistentvolumeclaims: "5" # 5개까지 제공하도록 제한
    requests.storage: "250Mi" # 용량 25Mi 넘지 않도록 제한
root@manager:~/k8slab/pvpvclab# kubectl apply -f quota.yaml
resourcequota/testquota created
root@manager:~/k8slab/pvpvclab# cp pvc.yaml pvc2.yaml
root@manager:~/k8slab/pvpvclab# cp pvc.yaml pvc3.yaml
root@manager:~/k8slab/pvpvclab# cp pvc.yaml pvc4.yaml

요청하기 위해 여러개 복사해서 각각 이름 pvc2, pvc3, pvc4로 바꾸기

root@manager:~/k8slab/pvpvclab# kubectl apply -f pvc2.yaml
persistentvolumeclaim/pvc2 created
root@manager:~/k8slab/pvpvclab# kubectl apply -f pvc3.yaml
Error from server (Forbidden): error when creating "pvc3.yaml": persistentvolumeclaims "pvc3" is forbidden: exceeded quota: testquota, requested: requests.storage=100Mi, used: requests.storage=200Mi, limited: requests.storage=250Mi

2까지는 되고, 3부터는 quota를 (용량)넘어서서 제한되었다.

storageclass는 PV와 PVC를 일종의 그룹으로 묶는 역할을 한다. 주로 동적 프로비저닝에서 사용한다.

0개의 댓글