
Container Volume에 대해 공부한 내용을 정리한 글입니다.
쿠버네티스 공식 홈페이지 - Kubernetes Volumes를 참고하여 진행하였습니다.
또한, 마스터 노드1, 워커노드 2로 실습 진행하였습니다.
🤣🤩😊CKA 자격증 준비 및 쿠버네티스 공부 정리입니다.
컨테이너를 실행한 이미지는 변경이 불가능합니다. 따라서 컨테이너를 실행하면 변경이 없다는 것을 보장하여 동일한 데이터를 유지합니다.
이는 데이터의 무결성이 유지된다고 볼 수 있습니다.
빠르게 배포하기 위한 구조라고 할 수 있습니다.컨테이너 안에서 생성되는 데이터들은 어떻게 처리해야 할까요?

컨테이너의 데이터를 관리하기 위해서는 volume이라는 리소스를 사용하게 됩니다. 기본적으로 volume은 디렉터리이며, 파드 내 컨테이너에서 마운트해 접근을 할 수 있습니다.
volume의 종류는 다양하지만, 2가지 유형이 존재합니다.
임시볼륨을 컨테이너에 마운트하면 데이터는 임시로 저장되어, 나중에 포드를 삭제했을 때 데이터 또한 함께 삭제됩니다.
영구볼륨을 사용하면 데이터를 다시 사용할 수 있도록 보존합니다.
PV(영구볼륨)의 대표적인 예로는 NFS, Ceph, local, hostPath 등이 존재합니다.
버전별로 매우 상이하기 때문에 꼭 document에서 확인할 것!
hostPath는 PV의 일종으로, 포드가 실행되는 노드의 디렉토리를 볼륨으로 구성하여 포드에 마운트합니다.
다음은 hostPath 유형의 PV를 구성하여 nginx 컨테이너에 마운트하는 예제 입니다.
apiVersion: v1
kind: Pod
metadata:
name: web-pod
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- mountPath: /usr/share/nginx/html
name: test-volume # volume과 같은 이름에 마운트!!!! 아래와 같아야됨
volumes: # volume 정의
- name: test-volume
hostPath:
path: /data
type: Directory
# node의 /data를 pod의 /usr/share/nginx/html에 마운트 함
# pod에서 /usr/share/nginx/html에 파일이 추가되면 노드의 /data에 파일이 생성됨.
node02에 할당이 되기 때문에 node02 /(root)에 data 디렉토리를 만들어주고 nginx의 기본 html파일 위치에 html파일 하나 만들어둡니다.
그리고 다음과 같이 명령어를 입력합니다.
$ kubectl get pod -o wide
$ cd /
$ mkdir data
$ ssh node02
$ ls /data
$ curl {pod-ip}

그리고 pod를 삭제하고 다시 생성해보겠습니다.

이처럼 pod안에 volume을 정의하고 hostPath방식의 PV를 사용해보았습니다. 데이터가 사라지지 않고 잘 보존이 되었습니다.
하지만, host path는 한 노드에 국한되어 사용되기 때문에 디플로이먼트 pod에 문제가 생겨 다른 노드로 pod가 옮겨지게 된다면 문제가 생기게 됩니다.
따라서, 특정 노드에만 포드를 배치하는 방법도 생각할 수 있지만, 호스트 노드에 문제가 생길 경우 데이터가 손실될 수 있습니다.

PV는 사용자 및 관리자가 pod로 연결할 volume을 미리 구성하고 사용할 방법과 제공하는 방식 등을 추상화하는 API로 제공합니다.
실제 어플리케이션을 개발한 뒤 yaml파일로 배포할 때는 위와 같이 pod에 volume을 직접 정의하고 마운트하는 작업은 바람직하지 않습니다.
Pod의 속성으로 정의하지 않고 별도의 오브젝트를 구성해서 분리된 방법으로 제공하여 Pod와는 별개의 lifecycle을 가지도록 구성합니다.
관리자는 PV리소스를 미리 프로비저닝하거나 storageClass를 미리 정의해두어 동적으로 프로비저닝되도록 구성할 수 있습니다.

volume 사용자(개발자)는 pod나 deployment에 별도의 volume을 정의하지 않아도 되며, yaml파일을 좀 더 보편적인 방식으로 정의할 수 있습니다.
파드는 분리되어 있는 PV 리소스를 사용하기 위해서 PVC(Persistent Volume Claim) 유형으로 volume을 구성합니다.
PVC는 볼륨에 대한 사용 요청(Claim)을 작성하여 APIServer에 전달하면 동적으로 볼륨을 구성하거나 클러스터에 이미 구성되어 있는 볼륨을 파드로 전달하여 컨테이너가 마운트 할 수 있도록 제공합니다.

다음은 pv 생성 예시이다.
# nginx-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
labels:
app: test-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce # PVC와 같아야 합니다!
hostPath:
path: /app/volume
$ kubectl get pv

이렇게 구성된 PV는 PVC를 생성하여 바인딩합니다.
# nginx-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteOnce # PV와 같아야 합니다!
resources:
requests:
storage: 1Gi
volumeName: nfs-pv
storageClassName: "" # 미리 생성한 PV들 (정적 프로비저닝 한) 안에서
# 가능한 PV를 바인딩하겠다는 것이다.
PV와 PVC를 생성했으니 pod에 적용해보겠습니다.

이렇게 하시면 바인딩이 됩니다.
PV - PVC 바인딩에 대해 여러 방법들이 존재했었지만, 잘 안되었고.. 공식문서의 Persistent Volume에서 방법을 알아서 사용해보았습니다.
PVC에서는 PV를 지정하기 위해
spec.volumeName에 pv이름을 입력하였고, PV에서는spec.claimRef로 PVC를 가르켰지만, PV에서 claimRef를 지정했을 경우에 PVC 생성 전부터 PVC에 할당된 것이라고 에러가 떠서..claimRef를 지우고 적용하니 bound가 되었습니다.
# nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 5
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- mountPath: /usr/share/nginx/html
name: nfsvolume
volumes:
- name: nfsvolume
persistentVolumeClaim:
claimName: nginx-pvc

잘 적용되었는지 PV에 정의해둔 것처럼 app/volume에 디렉토리를 만들어서 파일을 생성하고 pod에 접속하여 mount가 잘 되었는지 확인해보겠습니다.

/app/volume에는 아무 파일이 존재하지 않으니 pod에서 nginx를 표시하지 못할 것 입니다.

그럼 node01의 /app/volume에 index.html파일을 하나 생성해보겠습니다.
그리고 node01에 할당된 pod의 nginx를 동작시켜 보겠습니다.

하지만, node02에 할당된 pod은 node02의 /app/volume에 index.html이 없기 때문에 에러가 발생합니다.

실습을 통해, pod - pvc - pv로 이어지는 바인딩작업에 대해 알 수 있었습니다.
- PV: PV는 관리자가 사용자의 스토리지 요청에 맞게 프로비저닝하여 파드에서 사용할 수 있는 쿠버네티스 클러스터의 스토리지입니다.
- PVC: PVC는 사용자가 PV에 요구하는 스펙입니다. 사용하려는 용량, 접근 모드 등을 PV에 요청합니다.
다음에는 StorageClass와 동적프로비저닝에 대해 공부해보겠습니다.