HomeAbout
[Kubernetes] Kubernetes Volume 완벽 정리: 실제 예제를 통한 PV, PVC, 그리고 StorageClass
Docker & Kubernetes
[Kubernetes] Kubernetes Volume 완벽 정리: 실제 예제를 통한 PV, PVC, 그리고 StorageClass
NASA1515
NASA1515
June 25, 2021
4 min

목차

01
✔ Kuberntes의 Volume
02
✌ PV, PVC
03
👍 PV, PVC LIFECYCLE
04
🐱‍🏍 PV, PVC 생성
05
🌹 Volume Plugin

✔ Kuberntes의 Volume

POD의 Container는 이미지로부터 파일시스템을 제공받는데, POD가 종료되면 POD내의 데이터(파일)은 더 이상 사용할 수 없게 됩니다.
Controller에의해 새 POD가 생성되면 이미지로부터 새로운 파일시스템을 제공받는 구조로 설계되어 있기 때문입니다.
즉 Container는 기본적으로 데이터를 유지하지 않으며, 이런 형태를 상태가 없다(Stateless) 라고 합니다.
POD는 데이터 보존을 위해 Volume을 생성하고 이런 Volume을 Container에 Mount해서 사용하게됩니다. 물론 Volume은 여러 POD에서 동시에 접근이 가능하구요
기본적인 Volume의 LifeCycle은 POD의 LifeCycle과 같은데, POD가 생성되고 삭제됨에 따라 Volume도 같이 생성되고 삭제되기 때문입니다.
그러나 POD가 재 시작되면 Volume의 데이터는 삭제되지 않고 유지되며, 재 시작 된 POD에게 해당 Volume의 데이터를 다시 제공해줍니다.
PersistentVolume, PersistentVloumeClaim로 Volume만의 LifeCycle은 분리할 수 있고, POD의 로직과 별도로 Volume(스토리지)을 사용 할 수 있습니다.


✌ PV, PVC


(PersistentVolume, PV)

  • Kuberntes에서 Volume을 사용하는 구조는 2개로 분리되어 있습니다.
    PV는 Volume 자체를 의미합니다. Cluster내에서 Resource로 다뤄집니다. POD 하고는 별개로 관리되고 별도의 생명주기를 가지고 있습니다.

(PersistentVolumeClaim, PVC)

  • PVC는 사용자가 PV에 보내는 자원 요청입니다.
    사용하고 싶은 용량은 얼마인지 읽기/쓰기는 어떤 모드로 설정하고 싶은지 등을 정해서 요청합니다.

내용

Kuberntes는 Volume을 POD에 직접 할당하는 방식이 아닌 PVC를 둠으로 POD와 스토리지를 분리했습니다.
이 구조는 각자의 상황에 맞게 다양한 스토리지를 사용할 수 있게 해줍니다. CLOUD를 사용하는 경우에는 본인이 사용하는 CLOUD SaaS를 Volume 서비스를 사용할 수도 있고
직접 구축해서 사용 중인 스토리지가 있다면 그것 또한 사용할 수도 있습니다. 이렇게 다양한 스토리지를 PV로 사용할 수 있지만 POD에 직접 연결하는게 아니라 PVC를 통해서 사용하기 때문에 POD는 자신이 어떤 스토리지를 사용하는지 신경쓰지 않아도 됩니다.


👍 PV, PVC LIFECYCLE


PV-PVC의 로직은 다음 그림에서 보이는 것 같은 로직입니다.

스크린샷, 2020-08-14 17-30-59


PV와 PVC는 다음 그림에서 보이는 것 같은 LIFECYCLE을 가집니다.

스크린샷, 2020-08-14 12-11-40


프로비저닝(Provisioning)

  • PV를 사용하기 위해선 먼저 PV가 만들어져 있어야 합니다. 이 PV를 만드는 단계를 Provisioning이라고 합니다.

PV 프로비저닝 방법에는 2가지가 있습니다.


정적(static) : PV를 미리 만들어두고 사용합니다.

  • static PV라는 것은 Cluster 관리자가 미리 적정 용량의 PV를 만들어 두고 사용자들의 요청이 있으면 미리 만들어둔 PV를 할당해 주는 방식입니다.
    사용할 수 있는 스토리지 용량에 제한이 있을 때 유용하게 사용할 수 있는 방법입니다. 사용자들에게 미리 만들어둔 PV의 용량이 100기가라면 150기가를 사용 요청들은 실패하게 됩니다. 큰 용량 스토리지를 사용합니다고 해도 만들어둔 PV의 용량이 150기가이상 되는 것이 없다면 요청이 실패하게 됩니다.

동적(dynamic) : 요청이 있을때마다 PV를 만드는 방법.

  • 동적으로 PV를 준비하는건 미리 PV를 준비해두는 것이 아니고 사용자가 PVC를 통해서 요청을 했을때 PV를 생성해서 제공해 주는 방식입니다.
    Kuberntes Cluster를 위해 1테라짜리 스토리지를 준비해 뒀다고 하면 사용자가 필요할 때 원하는 용량만큼을 생성해서 사용할 수 있습니다.
    정적 PV생성과 달리 한번에 200기가 짜리도 필요하면 만들어 쓸 수 있습니다. 동적 프로비저닝을 위해서 PVC는 스토리지클래스(StorageClasses)를 사용합니다. StorageClasses를 이용해서 원하는 스토리지에 PV를 생성합니다.

바인딩(Binding)

  • PV를 PVC에 연결시키는 단계 입니다.
    PVC는 사용자가 요청하는 Volume을 PV에 요청하고 PV는 그에 맞는 Volume이 있으면 할당해주게 됩니다. 만약 PVC가 요청하는 Volume이 PV에 없다면 해당 요청은 무한정 남아있게 되고, PVC가 요청하는 Volume이 PV에 생성되면 그 요청은 받아들여져 할당해주게 됩니다.
    PVC와 PV는 ClaimRef를 사용하는 1:1 관계이며 바인딩이 정상적으로 완료될 경우 bound 상태가 됩니다.

사용 (using)

  • Pod는 PVC를 Volume으로 사용 합니다. Cluster는 PVC를 확인하여 바인딩된 PV를 찾고 해당 Volume을 Pod에서 사용할 수 있도록 해줍니다.
    만약 Pod가 사용중인 PVC를 삭제하려고 하면 Storage Object in Use Protection에 의해 삭제되지 않습니다.
    만약 삭제 요청을 하였다면 Pod가 PVC를 사용하지 않을때까지 삭제 요청은 연기 됩니다.

회수 (Reclamiming)

  • PV는 기존에 사용했던 PVC가 아니더라도 다른 PVC로 재활용이 가능 합니다. 때문에 사용이 종료된 PVC를 삭제할 때, 사용했던 PV의 데이터를 어떻게 처리할지에 대한 설정을 하게 됩니다.
    • Retain : PV의 데이터를 그대로 보존 합니다.
    • Recycle : 재사용하게될 경우 기존의 PV 데이터들을 모두 삭제 후 재사용 합니다.
    • Delete : 사용이 종료되면 해당 Volume을 삭제 합니다.

🐱‍🏍 PV, PVC 생성


PV 생성

apiVersion: v1
kind: PersistentVolume
metadata:
name: dev-pv
spec:
capacity:
    storage: 2Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
storageClassName: manual
persistentVolumeReclaimPolicy: Delete
hostPath:
    path: /tmp/log_backup
  • path: /tmp/log_backup
  • spec.capacity.storage → 사용할 용량을 2GB로 설정 합니다.
  • spec.volumeMode → Volume을 Filesystem으로 사용 합니다.
  • spec.accessModes → Pod의 접근 제어를 합니다.
  • ReadWriteOnce : 하나의 Pod에서만 읽고 쓸 수 있습니다.
  • ReadOnlyMany : 여러개의 Pod에서 읽을 수 있습니다.
  • ReadWriteMany : 여러개의 Pod에서 읽고 쓸 수 있습니다.
  • spec.storageClassName → 스토리지 클래스를 지정, 클래스에 맞는 PVC와 연결
  • spec.persistentVolumeReclaimPolicy → Delete는 Volume의 사용이 종료되면 Volume을 삭제 합니다. 회수 단계에서 설명한 필드
  • hostPath → 노드에 저장되는 디렉토리를 설정 합니다.

accessModes는 Volume의 읽기/쓰기에 관한 옵션을 지정합니다.

Volume은 한번에 하나의 accessModes만 설정할 수 있고 다음 3가지중 하나를 지정할 수 있습니다.

  • ReadWriteOnce : 하나의 노드가 Volume을 읽기/쓰기 가능하게 마운트할 수 있음.
  • ReadOnlyMany : 여러개의 노드가 읽기 전용으로 마운트할 수 있음.
  • ReadWriteMany : 여러개의 노드가 읽기/쓰기 가능할게 마운트할 수 있음

해당 파일로 생성 후 정상 PV 확인 - 아직 PVC가 생성이 되지 않아 STATUSAvailable 입니다.

스크린샷, 2020-08-14 16-02-05

pv의 상태는 Available을 포함해서 다음 4가지가 있습니다.

  • Available : PVC에서 사용할 수 있게 준비된 상태
  • Bound : 특정 PVC에 연결된 상태
  • Released : PVC는 삭제된 상태이고 PV는 아직 초기화되지 않은 상태
  • Failed : 자동 초기화가 실패한 상태


PVC 생성

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dev-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
    requests:
    storage: 1Gi
storageClassName: manual
  • accessModes: (PV와 동일) 어떤 모드로 연결할지 지정합니다. [ReadWriteOnce, ReadOnlyMany, ReadWriteMany]
  • volumeMode: PV와 동일) 파일시스템인지 블록 디바이스인지를 filesystem, raw등을 통해 설정할 수 있습니다.
  • resources: 얼만큼의 자원을 사용할 것인지에 대한 요청(request)을 입력합니다. (여기서는 1기가를 요청했습니다) 앞에서 만들어둔 PV의 용량이 2기가였기 때문에 현재 PVC에서 사용할 수 있습니다. 만약에 PVC가 requests의 storage에 2기가 이상의 용량을 입력했다면 거기에 맞는 PV가 없어 PVC는 Pending상태로 남습니다.
  • storageClassName: 사용할 스토리지클래스를 명시해 줍니다.

해당 파일로 생성 후 정상 PV,PVC 확인 PV <-> PVC가 연결되어 STATUSBOUND로 바뀐 것을 확인합니다.

스크린샷, 2020-08-14 16-05-48


PVC 를 사용할 DEP 생성 후 확인합니다

apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
labels:
    app: test-deployment
spec:
replicas: 1
selector:
    matchLabels:
    app: test-deployment
template:
    metadata:
    labels:
        app: test-deployment
    spec:
    containers:
    - name: test-deployment
        image: nginx
        ports:
        - containerPort: 8080
        volumeMounts:
        - mountPath: "/var/log/test.log"
        name: dev-volume
    volumes:
    - name: dev-volume
        persistentVolumeClaim:
        claimName: dev-pvc    ----------pvc 의 이름을 입력
  • spec.template.spec.containers.volumeMounts: Volume 마운트할 Container 안의 경로를 작성하고 이 경로를 저장한 Volume 마운트 정보를 dev-volume 이라는 이름으로 지정합니다.
  • spec.template.spec.volumes: 위에 작성한 Container에서 사용할 Volume 마운트 이름(dev-volume)을 가져오고 이 정보와 연결 요청을 보낼 pvc를 2번에서 생성한 dev-pvc로 지정 합니다.

파일 생성 테스트

  • MASTER 서버의 PV-PATH 경로에 다음과 같은 파일을 만들었습니다.
vagrant@kube-master1:~/wonseok$ ls -alrt /pv-pvc/pv-pvc-test.txt
-rw-r--r-- 1 root root 12 Aug 14 07:35 /pv-pvc/pv-pvc-test.txt
vagrant@kube-master1:~/wonseok$ cat /pv-pvc/pv-pvc-test.txt 
PV-PVC-TEST
vagrant@kube-master1:~/wonseok$ 

새로 만들어진 PODS에 /home/pv-pvs 디렉토리가 자동 생성되었고 pv-pvc-txt 파일의 내용도 들어있는 것을 확인합니다.

vagrant@kube-master1:~/wonseok$ kubectl exec -it pod/nasa1515-deployment-b664c7ff5-jh677 bas

root@nasa1515-deployment-b664c7ff5-jh677:/# ls -lart /home/pv-pvs
total 12
drwxr-xr-x 2 root root 4096 Aug 14 07:33 .
-rw-r--r-- 1 root root   12 Aug 14 07:33 pv-pvc.txt
drwxr-xr-x 1 root root 4096 Aug 14 07:43 ..
root@nasa1515-deployment-b664c7ff5-jh677:/# 
root@nasa1515-deployment-b664c7ff5-jh677:/# cat /home/pv-pvs/pv-pvc.txt
PV-PVC TEST

PV와 PVC는 POD와 서비스를 연결할 때처럼 레이블 / 셀렉터를 사용할 수도 있습니다.

  • PV

apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-hostpath-label
labels:
    location: local             -----------local
spec:
capacity:
    storage: 2Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
storageClassName: manual
persistentVolumeReclaimPolicy: Delete
hostPath:
    path: /home/nasa1515

  • PVC

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc-hostpath-label
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
    requests:
    storage: 1Gi
storageClassName: manual
selector:
    matchLabels:
    location: local            ---------------local


🌹 Volume Plugin

  • Kuberntes 에서 사용할 수 있는 Volume Plugin은 무수히 많습니다.

[몇가지 예시]

스크린샷, 2020-08-14 14-04-52


대표적인 3가지는 아래 가지가 있습니다.

empty : 임시로 데이터를 저장하는 빈 Volume

  • 호스트의 디스크를 임시로 Container Volume에 할당해서 사용합니다.
  • POD가 사라지면 emprtDir 에 할당했던 Container Volume의 데이터도 사라진다.
  • 단순히 Container를 재시작 했을 때 데이터를 보존하는 역할.
  • 메모리와 디스크를 함께쓰는 대용량 데이터 계산을 하는 경우와 연산 결과를 중간 저장용 필요할 때 사용합니다.

[아래의 예시는 두 개의 Container가 하나의 Pod에서 emptyDir을 공유하는 것을 보여줍니다]

1 apiVersion: v1
2 kind: Pod
3 metadata:
4 name: test-pod
5 spec:
6 containers:
7    - image: ubuntu:14.04
8    name: ubuntu-container              --- 우분투라는 이름의 pods
9    command: ["tail","-f", "/dev/null"]
10    volumeMounts:
11        - mountPath: /data
12        name: my-empty-volume
13
14    - image: nginx                     --- nginx라는 이름의 pods
15    name: nginx-containe
16    volumeMounts:
17        - mountPath: /data
18        name: my-empty-volume
19
20 volumes:
21    - name: my-empty-volume
22    emptyDir: {}                 ----empty에 대한 설정

  • spec.containers.volumeMounts.mountPath: 실행될 Container 안에 마운트할 경로 입니다. Container 안에 해당 디렉토리가 없더라도 자동으로 생성 해줍니다
  • spec.containers.volumeMounts.mountPath: 마운트할 Volume의 이름 입니다.
  • spec.voluems: 위에 작성한 my-empty-volume을 사용하도록 지정 해줍니다.

PODS 생성 후 정상 구동 확인

[root@nasa1515]# kubectl create -f emp.yaml
pod/emp-pod created
--------------------------------------------------------------------------
[root@nasa1515]# kubectl get po
NAME                                   READY     STATUS    RESTARTS   AGE
emp-pod                                 2/2       Running   0          39s

한 Container에서 /data에 파일을 생성할 경우 다른 Container에서도 해당 파일에서 접근할 수 있습니다.

[root@nasa1515]# docker ps | grep ubuntu
78a266359307        ubuntu@nasa1515:885bb6705b0... 
--------------------------------------------------------------------------
[root@nasa1515]# docker exec -it 78 bash
root@emp-pod:/# ls
bin  boot  data  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@emp-pod:/# cd data/
root@emp-pod:/data# echo test >> Test
root@emp-pod:/data# exit
exit

--------------------------------------------------------------------------
[root@nasa1515# docker ps | grep nginx
7c72d8409845        nginx@nasa1515:d85914d547a6...
[root@nasa1515]# docker exec -it 7c bash
root@test-pod:/# ls data/
Test

hostPath : POD가 실행된 호스트의 파일이나 디렉토리를 POD에 마운트합니다.

  • hostpath는 호스트의 디렉터리를 Pod와 공유해 사용하는 방식입니다.
  • Container 재시작시 데이터를 보존하는 역할입니다.
  • 도커 스웜 모드의 호스트 Volume 마운트와 비슷한 방식이라고 생각하면 쉽습니다.
  • Pod가 삭제되어도 hostpath에 저장된 파일들은 호스트에 저장되어 남아있게 됩니다.
  • 그러나 당연하게도 Container가 할당될 특정 호스트를 nodeSelector를 통해 지정해주지 않으면 매번 Container가 다른 호스트에 할당되므로 이 방식은 persistent storage와는 거리가 있다고 볼 수 있습니다.

hostpath는 아래와 같이 정의해 사용할 수 있다.

apiVersion: v1
kind: Pod
metadata:
name: nasa1515-hostpath-pod
spec:
containers:
- name: nasa1515-hostpath-pod
    image: arisu1000/simple-container-app:latest
    volumeMounts:
    - mountPath: /test-volume
    name: hostpath-vol
    ports:
    - containerPort: 8080
volumes:
- name: hostpath-vol
    hostPath:
    path: /tmp
    type: Directory
  • spec.containers.volumeMounts.mountPath: 실행된 Container 안에 마운트할 경로 입니다. Container 안에 해당 디렉토리가 없더라도 자동으로 생성 해줍니다.
  • spec.containers.volumeMounts.name: 마운트할 Volume의 이름 입니다.
  • spec.voluems.name: 위에 작성한 hostpath-volume을 사용하도록 지정 해줍니다.
  • spec.voluems.hostPath: 노드에 마운트할 경로를 정해주고 해당 경로는 Directory 라는것을 명시 합니다.
    해당 디렉토리는 노드에 생성되어 있어야 하며, DirectoryOrCreate를 사용하면 디렉토리를 생성 해줍니다.

NFS 서버

  • 호스트에 설정한 NFS 디렉토리를 공유하는 네트워크 Volume 공유입니다.
    NFS Volume은 기존에 사용하는 NFS 서버를 POD에 Mount하고, .spec.containers[].securityContext 는 Container의 보안 설정을 합니다.

Container가 실행중인 호스트 장치의 접근권한을 설정하는 priviledged 필드값으로 모든 호스트 장치에 접근할 수 있도록 할 수 있습니다.

apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-server
labels:
    app: nfs-server
spec:
replicas: 1
selector:
    matchLabels:
    app: nfs-server
template:
    metadata:
    labels:
        app: nfs-server
    spec:
    containers:
    - name: nfs-server
        image: arisu1000/nfs-server:latest
        ports:
        - name: nfs
        containerPort: 2049             --nfs 연결 Port
        - name: mountd
        containerPort: 20048
        - name: rpcbind
        containerPort: 111
        securityContext:
        privileged: true
        volumeMounts:
        - mountPath: /exports
        name: hostpath-vol
    volumes:
    - name: hostpath-vol
        hostPath:
        path: /tmp
        type: Directory

Tags

#Kubernetes
NASA1515

NASA1515

Data Engineer

Hello I'M Wonseok aka NASA1515

Expertise

Public Cloud
k8s/Docker
Python

Social Media

instagramwebsitelinkedingithub

Related Posts

[Kubernetes] VSCode (VisualStudio Code)로 Kubernetes 클러스터 관리 : 초보자를 위한 완벽 가이드
[Kubernetes] VSCode (VisualStudio Code)로 Kubernetes 클러스터 관리 : 초보자를 위한 완벽 가이드
2021-08-19
2 min

Topics

CloudDevelop

Social Media