쿠버네티스(k8s) Persistent Storage란?

Hoonkii·2022년 9월 5일
1

사내 Celery 도입을 위해서 GKE(Google Kubernetes Engine)에 RabbitMQ를 설치해야 했다. GKE에 RabbitMQ RabbitMQ를 설치하는 도중 Pod이 계속 Pending State에 머물러있길래 왜 그런지 살펴보던 중 Persistent Volume 및 Persistent Volume Claim과 관련된 이슈라는 것을 깨달았다.

오늘은 k8s에서 데이터를 영구적으로 저장하는 메커니즘인 Persistent Storage에 관한 내용을 다룰 것이다. 스토리지 관리는 K8s 클러스터 내에 있는 컴퓨트 노드(인스턴스) 관리와는 별개의 문제이다. 외부 별도의 스토리지 시스템을 이용해 데이터를 저장할 수도 있고 클러스터 내 노드의 자원을 사용할 수도 있다. k8s에서는 Persistent Storage를 통해서 클러스터 개발자 및 관리자에게 스토리지 사용 방법 및 스토리지 제공 방법에 대한 추상화된 API를 제공한다.

주요 오브젝트

Persistent Volume(PV)

PV는 관리자가 프로비저닝하거나, Storage class를 사용해서 동적으로 프로비저닝한 클러스터의 스토리지이다. 우리가 Pod에 노드의 CPU나 Memory와 같은 클러스터 리소스를 요청하는 것처럼 PV도 클러스터 리소스의 일종이다. 일반적인 Volume은 Pod과 동일한 라이프사이클을 가지지만 PV는 리소스를 사용하는 Pod과 별개의 라이프사이클을 가진다. 따라서 Pod이 종료되어도 PV에 기록된 데이터는 삭제되지 않고 남아있는다.

PV는 NFS, ISCSI 또는 클라우드 공급자 별 스토리지 시스템 등 스토리지 구현에 대한 세부 정보가 반드시 명시되어야한다.

Persistent Volume Claim(PVC)

PV가 클러스터 내 노드들의 CPU, Memory와 마찬가지로 클러스터 리소스라고 설명했다. PVC는 해당 리소스에 대한 요청이며 리소스에 대한 클레임 검사 역할을 한다. PVC를 명시하면 쿠버네티스는 적정한 크기와 접근 모드의 PV를 찾고 PVC를 PV에 할당한다.

PV, PVC 라이프사이클

PV와 PVC 간의 상호 작용은 다음 라이프사이클을 따른다. 프로비저닝 -> 바인딩 -> 사용 중 -> 반환

프로비저닝

정적 프로비저닝

클러스터 관리자가 관련 스토리지 기술을 명세해 PV를 사전에 만드는 방식이다. PVC의 storage class를 지정하지 않으면 정적으로 만든 PV를 사용할 수 있다. 보통 컴퓨팅 리소스가 한정된 온 프레미스 환경에서 활용한다.

yaml 예시를 살펴보자.
먼저 PV 생성 예시이다.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mongodb-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  gcePersistentDisk:
    pdName: mongodb
    fsType: ext4

capacity를 통해 용량을 명시하고, accessModes를 통해 스토리지 접근 방법을 정의한다. 그리고 실제 스토리지 유형을 명시해야 하는데, 예제에서는 gcePersistentDisk이다.

PV를 생성했으면 개발자는 정적으로 생성된 PV 리소스를 사용하겠다는 PVC를 생성한다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mongodb-pvc
spec:
  resources:
    requests:
      storage: 1Gi
  accessModes:
    - ReadWriteOnce
  storageClassName: ''

예제에서 storageClassName을 ‘’로 지정한 것에 유의하자. 이 설정의 뜻은 미리 생성한 PV들 (정적 프로비저닝 한) 안에서 가능한 PV를 바인딩하겠다는 것이다.

Pod 볼륨에 PVC를 참조함으로써 pod에서 PV를 사용할 수 있다.

apiVersion: v1
kind: Pod
metadata:
  name: mongodb
spec:
  containers:
    - image: mongo
      name: mongodb
      volumeMounts:
        - name: mongodb-data
          mountPath: /data/db
      ports:
        - containerPort: 27017
          protocol: TCP
  volumes:
    - name: mongodb-data
      persistentVolumeClaim:
        claimName: mongodb-pvc

volumes에 persistentVolumeClaim: claimName에 PVC 이름을 지정하면 된다.

PVC를 먼저 소개하긴 했으나, 사실 PVC를 활용하지 않고 Pod에서 PV를 직접 참조할수도 있다.

apiVersion: v1
kind: Pod
metadata:
  name: mongodb
spec:
  volumes:
  - name: mongodb-data
    # 볼륨 유형
    gcePersistentDisk:
      pdName: mongodb # 쉘에서 사전에 Persistent Disk 생성 필요
      fsType: ext4
  containers:
    - image: mongo
      name: mongodb
      volumeMounts:
        - name: mongodb-data
          mountPath: /data/db
        ports:
          - containerPort: 27017
            protocol: TCP

위 예제에서 보면 바로 볼륨에서 gcePersistentDisk를 참조하고 있다. 이 때 shell에서 persistent disk를 미리 생성해야 한다.

gcloud compute disks create --size=1GiB --zone=europe-west1-b mongodb

PVC를 활용하면 PV의 세부 구현 정보 등을 몰라도 내가 원하는 자원만 명세하면 쿠버네티스가 알아서 자원을 할당해주기 때문에 개발자 입장에서 기반 스토리지 기술(NFS or ..) 을 몰라도 Persistent Storage를 사용할 수 있다는 장점이 있다. 그래서 권장 설정은 PV직접 참조가아닌 PVC를 통한 참조이다.

동적 프로비저닝

PV, PVC를 활용하면 개발자가 내부 스토리지 기술을 몰라도 Persistent Storage를 사용할 수 있다는 장점이 있다. 그러나 정적 프로비저닝의 경우 관리자가 실제 스토리지를 미리 PV로 다 만들어놓아야 한다는 관리 상 귀찮음이 있다.

K8s에서는 PV의 동적 프로비저닝을 통해 이 작업을 자동으로 수행할 수 있게 한다. 클러스터 관리자는 PV를 생성하는 대신에, PV 프로비저너를 배포하고 사용자가 선택 가능한 하나 이상의 storage class 오브젝트로 정의할 수 있다.

사용자는 PVC에서 PV가 아닌 storage class를 참조하면 프로비저너가 알아서 PV를 프로비저닝 해준다.

GKE에서는 프로비저너를 포함해서 준다.(GKE를 비롯한 클라우드 제공 클러스터 들은 다 프로비저너를 포함해서 준다. ) 사용할 수 있는 스토리지 클래스를 조회해보면 나온다.

yaml 예시를 살펴보자.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-ssd
  zone: europe-west1-b

GKE의 경우 기본 storage class를 제공하지만, storage class를 따로 정의하고 싶다면 위와 같이 작성하면 된다.

PVC는 다음과 같이 작성하면 된다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mongodb-pvc
spec:
  resources:
    requests:
      storage: 100Mi
  accessModes:
    - ReadWriteOnce
  storageClassName: fast

정적 프로비저닝에서와 다르게 storageClassName 항목에 생성한 storage class의 이름을 명시한다.

이렇게 되면 storage class에 참조한 프로비저너가 알아서 PV를 생성해주고, PVC와 연결도 해준다.

클라우드 기반 클러스터 환경에서 정적 프로비저닝을 사용하면 클러스터 관리자와 개발자 둘다 공수가 줄어 행복해진다.

바인딩

PV와 PVC가 연결되는 동작을 바인딩이라고 한다. 정적 프로비저닝의 경우 PVC를 배포하면 쿠버네티스가 가능한 PV안에서 PVC를 바인딩해준다. 동적 프로비저닝의 경우는 Storage Class의 Provisioner가 PV를 동적으로 생성하고 PVC와 바인딩해준다.

사용 중

파드는 클레임을 볼륨으로 사용하고, 클러스터는 클레임을 검사하여 바인딩된 볼륨을 찾고 해당 볼륨을 파드에 마운트 한다. 일단 클레임이 바인딩되면 PV는 사용자가 필요로 하는 한 사용자에게 속하게 된다.

반환

볼륨을 다 사용하고나면, 리소스를 반환할 수 있는 API를 사용하여 PVC 오브젝트를 삭제할 수 있다. PVC의 반환 정책은 볼륨에서 클레임을 해제한 후 볼륨에 수행할 작업을 클러스터에 알려준다.

  • Retain

리소스를 수동으로 반환할 수 있게 하는 정책이다. PVC가 삭제되어도 PV는 여전히 존재하며, 따라서 다른 요청에 대해서는 사용이 불가능하다. 따라서 관리자가 수동으로 볼륨을 반환해야 한다.

  • Delete

PV와 외부 인프라와 관련된 스토리지 자산을 모두 삭제한다. 동적으로 프로비저닝 된 볼륨은 Storage Class의 반환 정책을 상속한다.

profile
개발 공부 내용 정리

0개의 댓글