Container Volume(2) - 동적 프로비저닝

cometLEE·2023년 10월 16일
0

kubernetes

목록 보기
12/16

StorageClass에 대해 공부한 내용을 정리한 글입니다.

쿠버네티스 공식 홈페이지 - Kubernetes StorageClasses를 참고하여 진행하였습니다.
또한, 마스터 노드1, 워커노드 2로 실습 진행하였습니다.
🤣🤩😊CKA 자격증 준비 및 쿠버네티스 공부 정리입니다.


서론

지난 포스팅에서는 VOlUME의 종류와 PV, PVC를 통한 정적프로비저닝에 대해 공부해보았습니다. 이번 포스팅에서는 관리자가 직접 PV를 만들어두지 않아도 자동으로 PV를 생성해주는 방법인 StorageClass를 통한 동적프로비저닝에 대해 다루어보려고 합니다.


복습

클러스터 사용자가 PV(PersistentVolume)을 사용할 때, Pod 정의파일에 직접 PV에 대한 내용을 정의하면 PV에 대한 내용도 공부해야 하고, 실행시키는데 매우 복잡한 과정을 겪을 수 있게됩니다.

따라서 PVC(PersistentVolumeCliam)을 이용하여 PV - PVC를 연결한다면, 클러스터 사용자는 PVC에 자신이 원하는 용량 및 접근방법만 지정하면 PVC의 스펙에 맞는 PV를 바인딩해주게 됩니다. 이를 통해, POD의 가독성도 올라가고, 유지보수가 좋아진다는 장점을 가지게 됩니다.

하지만, 단점으로는 클러스터 관리자가 여러 PV를 생성해두어야 한다는 단점이 존재합니다. 클러스터 관리자가 놓친 부분이 존재한다면 사용자가 요청한 PVC는 대기상태로 남게 될 것입니다.
이 부분을 해결할 수 있는 방법에 대해 공부해보겠습니다.


PV, PVC의 라이프 사이클

PV와 PVC는 4가지 단계로 라이프사이클이 구성됩니다.

  • 프로비저닝(provisioning)
  • 바인딩(binding)
  • 사용(using)
  • 회수(reclaiming)
  • 프로비저닝: PV를 생성하는 단계로 PV를 만드는 것에는 정적(static)인 방법과 동적(dynamic)방법이 존재합니다.

    • 정적 프로비저닝: 클러스터 관리자가 직접 여러 PV를 만들고, 클러스터 사용자가 사용할 수 있는 실제 스토리지의 세부사항을 제공합니다.
    • 동적 프로비저닝: 관리자가 생성한 정적 PV가 사용자의 PVC와 일치하지 않으면 클러스터는 PVC를 위해 특별히 볼륨을 동적으로 프로비저닝할 수 있도록 시도할 수 있습니다. 이 프로비저닝은 StorageClass를 요청해야 하며, 관리자는 동적 프로비저닝을 위해서 StorageClass를 생성하고 구성해두어야 합니다.
  • 바인딩: PV와 PVC를 연결하는 단계입니다. PVC에서는 사용자가 원하는 스토리지 용량과 접근 방법에 대응하는 PV와 연결할 수 있는데, 대응하는 PV가 존재하지 않으면 그에 맞는 PV가 생기기 전까지 Pending상태를 유지합니다.

  • 사용: PVC는 파드에 설정되고, PVC를 볼륨으로 인식하여 사용합니다.

  • 회수: 사용이 끝난 PVC를 삭제하면, PVC가 사용하던 PV를 초기화되는 단계입니다. 이 과정에는 3가지 정책인 보존(Retain), 삭제(Delete), 재사용(Recycle) 이 존재합니다.

    • 보존(Retain): PVC가 삭제 될 때 bound -> Released로 바뀌고, PV의 데이터는 보존합니다. pvc가 삭제되어도 여전히 볼륨안에는 이전의 pvc에 대한 데이터가 존재하기 때문에 다른 PVC에서 할당할 수 없습니다.
      따라서 데이터를 삭제하고 싶은 경우, 직접 관리자가 PV를 삭제하고 관련 스토리지 데이터를 수동으로 삭제해야 합니다.
    • 삭제(Delete): PVC가 삭제될 때 대응되는 PV도 같이 삭제됩니다.
    • 재사용(Recycle): PVC가 삭제될 때 대응하는 PV의 상태를 bound -> pending상태로 바꾸며 다른 PVC의 연결요청을 기다립니다.

전 포스팅에서 진행한 실습의 경우는 직접 관리자가 PV를 생성하고 PVC에 별도의 storageClass를 정의하지 않고 사용하였기 때문에 정적 프로비저닝이라고 할 수 있겠습니다.


storageClass

동적 프로비저닝은 관리자 개입없이 PV를 생성합니다. 이는 StorageClass를 생성하는 것으로 사용할 수 있습니다.
StorageClass는 관리자가 제공하는 스토리지의 "클래스"를 설명하는 방법을 제공합니다. 다양한 클래스는 서비스 품질 수준, 백업 정책 또는 클러스터 관리자가 결정한 임의 정책에 매핑될 수 있습니다.


storageClass 리소스

  • provisioner:
  • parameters:
  • reclaimPolicy:
  • volumeBindingMode
  1. provisioner : 스토리지 볼륨을 프로비저닝하는 플러그인 선택
  2. parameters : 해당 스토리지 시스템의 특정 속성 명세
  3. recliamPolicy : PVC를 삭제했을 경우 PV를 어떻게 회수할 것인지 명세합니다. 기본 값은 delete(삭제) 입니다.
  4. volumeBindingMode: 볼륨 바인딩 및 동적 프로비저닝이 발생해야하는 시기를 제어합니다. 기본 값은 immediate(즉시)입니다.
    • 클러스터의 모든 노드에서 전역적으로 액세스할 수 없는 스토리지의 백엔드의 경우 PV에 대한 정보 없이 binding될 수 있게 되어 정상적으로 POD 생성이 이루어지지 않을 수 있습니다.
      따라서 WaitForFirstConsumer를 지정하여 PVC를 사용하는 pod가 생성될 때까지 PV의 바인딩을 지연하는 모드를 사용합니다.

provisioner

provisioner 종류

PV를 생성할 스토리지 종류. 클라우드 벤더사에서 지원하는 프로비저너들도 존재.
cloud 환경에서는 자원을 선점할 필요가 없습니다. 필요할 때 자원을 바로 할당할 수 있기 때문입니다. 보통 운영환경에서는 storage class의 성능을 최대로 높게 하고, 개발환경에서는 storage class의 성능을 느리지만 안전한 volume에 저장하도록 구성합니다.

네트워크 볼륨

쿠버네티스에서는 별도의 플러그인을 설치하지 않아도 다양한 종류의 네트워크 볼륨을 포드에 마운트할 수 있습니다. 온프레미스 환경에서도 구축할 수 있는 NFS, iSCSI, GlusterFS, Ceph와 같은 네트워크 볼륨뿐만 아니라 AWS의 EBS, GCP의 gcePersistentDisk와 같은 클라우드 플랫폼을 포드에 마운트할 수도 있습니다.


GCP GKE를 통한 실습 진행

쿠버네티스에서는 다양한 프로비저너들을 제공하지만, 온프레미스 환경에서는 내장 프로비저너가 존재하지 않습니다. 따라서 클라우드환경에서 제공해주는 프로비저너를 사용해보려고 합니다.
GCE - GKE 연결해서 해보기

  • GCE PD(Persistent Disk)

pod와 PVC, storageClass를 생성해서 할당이 잘 되는지 확인해 보겠습니다.

StorageClass 생성

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: storage-class
provisioner: kubernetes.io/gce-pd # 프로비저닝에 사용하는 플러그인
parameters:
  type: pd-ssd # 프로비저너에 전달될 매개변수

PVC 생성

예시로 사용할 PVC파일을 만들겠습니다.

# mongodb-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mongodb-pvc # 클레임 사용 때 필요
spec:
  resources:
    requests:
      storage: 1Gi # 요청하는 스토리지 양
  accessModes:
    - ReadWriteOnce # 단일 클라이언트에 읽기 쓰기 지원
  storageClassName: storage-class # 동적 프로비저닝에서 사용

이전 포스팅과는 다르게, PVC를 생성하자마자 bound가 된 것을 알 수 있습니다. PV가 없는데도 말이죠. 따라서 클라우드 벤더에서 제공하는 프로바이저가 존재하기 때문에 bound 상태가 된 것을 알 수 있었습니다.

POD 생성

#mongo-pvc-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: mongodb
spec:
  containers:
  - image: mongo
    name: mongodb
    volumeMounts:
    - name: mongodb-data # Pod가 참조할 볼륨이름. volumes.name과 같아야 함
      mountPath: /data/db # POD의 /data/db의 데이터가 볼륨에 저장됨! 
    ports:
    - containerPort: 27017
      protocol: TCP
  volumes:
  - name: mongodb-data # PVC가 프로바이저로부터 할당해놓은 볼륨 이름
    persistentVolumeClaim:
      claimName: mongodb-pvc  # PVC의 이름

pod에 접속해서 잘 적용되는지 확인해보겠습니다.


mongodb 데이터베이스에 도큐먼트 추가해 할당된 PV에 데이터 쓰기

파드를 생성해 컨테이너가 시작됐으므로 컨테이너 내부에 MongoDB 셸을 실행해 데이터 스토리지에 데이터를 쓰는 데 사용할 수 있다.

$ kubectl exec mongodb -c mongodb -i -t -- bash -il
$ mongosh

데이터를 불러와서 확인 후, pod를 지우고 다시 실행 시켜보겠습니다.

동적 프로비저닝 동작 순서

gcp에서 제공하는 예시

GCP-CSI사용법

GCE(Google Compute Engine)에서 GKE(Google Kubernetes Engine)을 연결해서 pod, service, pvc, storageclass까지 생성해보았습니다. 결과는 아래와 같습니다.


# pd-example-class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: pd-example
provisioner: pd.csi.storage.gke.io
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
parameters:
  type: pd-balanced
#pvc-example.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: podpvc
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: pd-example
  resources:
    requests:
      storage: 6Gi
# web-server.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web-server
  labels:
    app: nginx
spec:
  containers:
   - name: web-server
     image: nginx
     port:
     - containerPort: 80
     volumeMounts:
       - mountPath: /usr/share/nginx/html
         name: mypvc
  volumes:
   - name: mypvc
     persistentVolumeClaim:
       claimName: podpvc
       readOnly: false

expose 명령어를 통해 pod를 loadbalancer타입으로 service를 생성합니다.
$ kubectl expose pod web-server --type=LoadBalancer --port=80 --target-port=80 --selector=app=nginx --dry-run=client -o yaml

여기서 배운점: --selector={라벨 키}={라벨 값}

배포 결과

어째서 nginx index.html인 기본페이지가 아니라 403에러가 났을까요?
그 이유는 /usr/share/nginx/html안에 index.html이 존재하는데, GCP의 ssd-pd로 마운트가 된 상태이기 때문에 비워졌습니다.
따라서 이 안에 index.html을 새로 만들어서 넣어보겠습니다.

index.html 변경 후 결과 확인

pod에 먼저 접근합니다.

$ kubectl exec -it  web-server -c web-server -- bash
$ cd /usr/share/nginx/html
$ vi index.html

html문서를 간단하게 바꿔보고, pod삭제 후 다시 생성해도 파일이 불러와지는지 확인하겠습니다.

pod를 지우고 재생성 하겠습니다.

$ kubectl delete -f web-server.yaml
$ kubectl create -f web-server.yaml

그리고 다시 접속해보면..

그대로 존재하고 파드 안에 들어가서 확인해보겠습니다.


PVC 지워보기

위에서 봤듯이, PV&PVC의 라이프사이클 중, 재회수(Reclaim)의 정책 4가지 중 기본 값은 Delete입니다. 위에서 storageClass정의할 때 Recalim에 대한 부분이 없었죠? 그러면 delete로 설정이 됩니다.
삭제(Delete): PVC가 삭제될 때 대응되는 PV도 같이 삭제됩니다.

그러면 PVC를 지우면 pod의 존재했던 PV의 데이터도 사라지는 건가요? 한 번 진행해보겠습니다.
지금 생각하는 결과 값은 임의로 생성했던 index.html이 없어지고, 403에러가 떠야겠죠.
왜냐하면, PV도 같이 사라지기 때문에 새로운 PV가 생성이 될 것입니다.

volume이름이 바뀌었네요. pod로 접속해서 확인해보겠습니다.

$ kubectl exec -it web-server -c web-server -- bash
$ cat /usr/share/nginx/html/index.html

이 처럼 Recliam 정책에 의해 PVC가 삭제되면 PV도 같이 사라지는 것을 확인하였습니다!!


실습 중.. 에러 발생!!

PVC가 지워지지 않고 status=Terminating에만 머물러 있다..
kubectl delete pv (pv name) --grace-period=0 --force 명령어로도 삭제가 불가능.

$ kubectl edit pvc {pvc 이름}

edit창에서 Finalizer를 지워주면 삭제된다는 것!!
kubernetes - finalizers

PV, PVC말고도 다른 오브젝트도 안지워지면 finalizer 확인 할 것!

에러 수정

나중에 안 사실이지만.. Pod를 지우기 전에 PVC를 지우려고 하니 에러가 발생한 것이었습니다.. binding되어 있는 Pod를 먼저 지워주고 PVC를 지워주시면 됩니다!!!


정리

volume에서 이어져 내려와 PV, PVC, StorageClass까지 이어지는 내용에 대해 공부하였습니다.
온프레미스 환경보다 확실히 프로바이저가 존재해서 편하였고, 클라우드 플랫폼을 이용하면 관리자와 사용자 모두 편해질 수 있구나.. 이런 방법도 존재하는 구나.. 에 대해 알 수 있었습니다.

공부하면서 찾은 내용은 statefulSet이라는 리소스도 storageClass가 사용된다는 것을 알게 되어서 다음 포스팅에서는 statefulSet에 대해 다뤄보려고 합니다.

  • PV: 파드(컨테이너)는 사라지기 마련인데, 데이터를 저장하기 위한 persistent volume
  • PVC: PVC를 사용함으로 사용자가 원하는 스펙의 볼륨을 정의해서 pod에 기록함.
  • StorageClass: 관리자가 직접 PV를 생성해두고, 그것을 바인딩해주는 작업이 정적 프로비저닝. 하지만, 모든 상황에 PV를 생성하는 것은 비효율적이기 때문에 서비스 품질 수준, 백업 정책 또는 클러스터 관리자가 결정한 임의 정책등을 정의해 놓은 인터페이스. PVC의 요청에 맞춰서 storageClass의 내용을 확인 후 바인딩 여부 결정 후 PV 자체 생성
profile
server, kubernetes에 관심이 많이 있습니다

0개의 댓글