
쿠버네티스 파드 내부의 데이터는 파드의 생명 주기를 따라갑니다. 파드가 내려가면 데이터도 삭제되죠. 파드가 내려가더라도 파드에서 생성한 데이터를 유지하기 위해 볼륨을 사용합니다. 도커에서 사용하는 볼륨과 동일한 개념이라고 봐도 무방합니다.
호스트의 디렉토리를 볼륨으로 사용하는 가장 기본적인 형태부터 알아봅시다.
yml 파일에 정의된 파드는 1~100 사이 임의의 숫자를 /opt/number.out 파일에 저장합니다.

여기서 볼륨은 volumes에 정의합니다. 호스트의 /data 디렉토리를 사용하도록 정의하고 있습니다.
그리고 spec 하위의 volumeMounts에 사용할 볼륨, 마운트할 경로를 지정합니다.
주의❗️
멀티노드 클러스터에서 호스트 볼륨 사용은 주의해야 합니다. 아래 그림처럼 각 노드마다 디렉토리가 생성되는데, 이 디렉토리들이 항상 같은 데이터를 저장하고 있다고 보장할 수 없기 때문이죠.
물론 단일 노드로 구성된 환경이거나spec.nodeSelector를 사용해 단일 노드에서 사용하는 Pod라면 호스트 볼륨을 사용해도 무방합니다.
호스트가 아닌 외부 스토리지 서비스를 이용할 수도 있습니다. AWS EBS나 ceph, NFS 등 다양한 스토리지 서비스를 이용할 수 있습니다.

사용 방법은 크게 다르지 않습니다. volumes에 사용할 외부 스토리지 서비스에 대한 정보를 입력하고 volumeMounts.name에 해당 볼륨을 작성하면 됩니다.

쿠버네티스 환경에서 볼륨만으로는 한계가 있습니다. 굉장히 많은 파드가 떠있는 상황에서 일일이 파드 spec에 정의된 볼륨을 수정, 관리해줘야 하기 때문이죠.
이러한 문제를 해결하기 위해 파드와 볼륨을 디커플링하는 목적으로 사용하는 오브젝트가 Persistent Volume(PV)과 Persistent Volume Claim(PVC)입니다.

PV들이 스토리지 풀 역할을 하고 PVC가 이 스토리지 풀에 요청을 보내는 중간 다리 역할을 하는 것이죠.
PV는 스토리지 역할을 하는 오브젝트입니다.

위와 같이 어떤 스토리지를 사용할 것인지, 얼마만큼의 용량을 설정할 것인지, 읽기/쓰기 옵션은 어떻게 할 것인지 등을 지정해 생성합니다. 여기서 읽기/쓰기 옵션으로는 4가지를 선택할 수 있습니다.
accessModeReadWriteOnce (RWO) : 하나의 노드에서 해당 볼륨이 읽기-쓰기로 마운트 될 수 있습니다.ReadOnlyMany (ROX) : 볼륨이 다수의 노드에서 읽기 전용으로 마운트 될 수 있습니다.ReadWriteMany (RWX) : 볼륨이 다수의 노드에서 읽기-쓰기로 마운트 될 수 있습니다.ReadWriteOncePod (RWOP) : 볼륨이 단일 파드에서 읽기-쓰기로 마운트 될 수 있습니다.PVC는 PV에 대한 요청을 보내는 오브젝트입니다.

위와 같이 PVC를 생성하면 스토리지 용량(resources.requests.storage), accessModes, volumeMode, storageClass, selector가 최대한 일치하는 PV에 바인딩 됩니다.
또한 PV와 PVC는 1:1 관계로 바인딩 됩니다. 위 yml 파일을 보면 PV는 1Gi의 용량을 가지고 있지만 PVC는 500Mi 용량을 요청하고 있습니다. 만약 위의 두 PV, PVC가 바인딩 된다면 아래 이미지처럼 PV의 용량이 더 크더라도 바인딩이 됩니다. 그리고 바인딩된 PVC의 용량은 500Mi가 아닌 1Gi가 됩니다.

PV 생성 시 persistentVolumeReclaimPolicy를 설정할 수 있습니다.
retain: PVC가 삭제되어도 PV의 데이터를 보존합니다. 하지만 해당 PV를 다른 PVC가 사용하지 못하고, 재사용하기 위해서는 수동으로 PV를 반환해야 합니다.delete: PVC가 삭제되면 PV의 데이터를 비롯해 PV 자체가 삭제됩니다.recycle: PVC가 삭제되면 PV의 데이터만 삭제하고 볼륨 자체는 보존하여 곧바로 다른 PVC에 사용할 수 있습니다. 하지만 현재는 deprecated 되어 권장되지 않는 옵션입니다.볼륨 설정과 동일합니다. volumes에 PVC를 작성하고 spec.containers.volumeMounts에 마운트할 경로, PVC 이름을 선언합니다.
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim
PV, PVC, Pod의 yaml 파일을 한 눈에 보이도록 정리하면 다음과 같습니다.

프로비저닝은 사용자가 요청한 IT 자원을 사용할 수 있는 상태로 준비하는 것을 말합니다. 이 글에서는 주로 스토리지 프로비저닝에 대한 내용을 다루고 있었던 것이겠네요.
특히 지금까지 다룬 내용은 정적 프로비저닝에 해당됩니다.

직접 스토리지를 생성하고, PV를 생성해서 자원을 준비했으니까요. 하지만 매번 스토리지 자원을 수동으로 생성하는 정적 프로비저닝은 한계가 분명해보입니다.
그래서 스토리지에 대한 요청이 있을 때 프로비저닝을 수행하는 동적 프로비저닝 방법인 Storage Class가 등장합니다. Storage Class를 사용한 동적 프로비저닝 과정을 살펴봅시다.

storageClassName에 지정합니다.이처럼 Storage Class를 사용하면 PVC가 요청할 때 동적으로 프로비저닝을 수행하게 됩니다.
Storage Class를 생성할 때 볼륨 바인딩 모드를 지정해 볼륨 바인딩과 동적 프로비저닝 시작 시기를 제어할 수 있습니다.
볼륨 바인딩 모드를 별도로 설정하지 않으면 Immediate가 기본으로 사용됩니다.
Immediate 모드는 PVC가 생성되면 볼륨 바인딩과 동적 프로비저닝이 즉시 발생하는 것을 말합니다.
WaitForFirstConsumer 모드를 지정하면 PVC를 사용하는 파드가 생성될 때까지 PV의 바인딩과 프로비저닝을 지연시킵니다.