StorageClass

개요

스토리지 클래스는 관리자가 제공할 스토리지 분류(class)가 뭐가 있는지 보여주는 하나의 방법이다.
관리자는 클래스마다 서비스 품질, 백업 정책 등 임의의 정책을 지정해놓을 수 있다.
쿠버네티스는 각 클래스가 무얼 대표하는지를 상관하지 않으며, 관리자가 알아서 할 부분이다.
다른 시스템 디자인에서는 흔히 프로필(profile)이라고 불린다고 한다.

동적 프로비저닝(Dynamic Provisioning)

동적 프로비저닝은 PVC에 맞게 자동으로 PV를 생성하는 기술을 말한다.[1]
원래 보통의 스토리지 자원 제공 과정은 아래의 순서를 따른다.

  1. 관리자가 원하는 만큼 PV를 만든다.
  2. 사용자가 PVC로 자원을 요청한다.

그러나 동적 프로비저닝을 통해서, 2번 과정만 있으면 PV가 알아서 만들어지게 할 수 있다!
그래서 관리자는 클러스터에서 발생하는 요구에 대한 파악과 분석을 하지 않고도 편하게 스토리지 자원을 제공할 수 있게 된다.

이 개념을 이 문서에서 다루는 이유는 스토리지 클래스를 세팅함으로써 동적 프로비저닝이 가능해지기 때문이다..
조금 더 구체적으로, 스토리지 클래스에 프로비저너(자원 제공자)를 명시함으로써 동적 프로비저닝이 가능해진다.
관리자가 다양한 설정으로 각종 스토리지 클래스를 만들면, 사용자는 스토리지가 어떻게 프로비저닝되는지에 대한 복잡한 설정을 알 필요 없이 다양한 스토리지 옵션을 가지게 될 것이다.
사용자는 단순히 PVC 스펙에 사용하고 싶은 .spec.storageClassName만 지정해주면 된다!

기본 스토리지 클래스

어노테이션에 storageclass.kubernetes.io/is-default-class 를 달아서 기본 스토리지 클래스를 설정할 수 있다.
기본 스토리지 클래스는 사용자가 PVC에 스토리지 클래스를 지정하지 않았을 때 기본으로 사용될 스토리지 클래스를 말한다.

단순한 어노테이션이라 여러 개를 기본으로 설정할 수도 있을 것이다.
이럴 경우에는 가장 최근에 세팅한 것이 기본 스토리지 클래스가 된다.
어차피 하나만 기본으로 쓰일 텐데 이렇게 어노테이션 방식을 통해 중복을 허용한 이유는, 기본 스토리지 클래스를 서비스 중단 없이 변경할 수 있게 하기 위함이다.
관리 입장에서는 당연히 현재 어떤 놈이 기본 스토리지 클래스로 설정된지 빠르게 확인하기 어렵게 될 것이긴 하다..
그러니 기본 스토리지 클래스를 바꿀 때는 이전 놈의 어노테이션을 제거해서, 가급적으로 하나로만 유지되도록 하길 권장한다.

그래서 나는 그렇게 좋은 방식이라는 생각은 잘 들지 않는다.
차라리 나는 클러스터를 구성하는 시점에 아래에서 볼 [[#local]] 스토리지 클래스가 자동 생성되어 기본으로 지정되게 하는 게 좋지 않을까 싶다.
네임스페이스 별로 기본 스토리지 클래스를 지정할 방법은 없는가?

pvc에서 명시 안하면 기본 스클이 사용된다.
기본 스클이 없는 클러스터에선 pvc에 아예 세팅이 안 될 것이다.

양식 작성법

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: low-latency
  annotations:
    storageclass.kubernetes.io/is-default-class: "false"
provisioner: csi-driver.example-vendor.example
reclaimPolicy: Retain # 기본값은 Delete
allowVolumeExpansion: true
mountOptions:
  - discard # this might enable UNMAP / TRIM at the block storage layer
volumeBindingMode: WaitForFirstConsumer
parameters:
  guaranteedReadWriteLatency: "true" # 프로바이더마다 다를 것이다.

여러 필드가 보이는데, provisioner, parameters, recliamPolicy 필드가 PVC에 대해 동적으로 프로비저닝될 때 사용된다.
이게 있으면, 스토리지 클래스를 명시하지 않은 PVC에 자동으로 해당 스토리지 클래스가 설정된다.

동적 프로비저닝과 관련된 필드를 먼저 모아보겠다.

provisioner

프로비저너는 PV를 프로비저닝할 볼륨 플러그인을 명시하는 필드로, 반드시 있어야 한다.

내장된 프로비저너는 kubernetes.io가 붙어있으며, 이것들을 사용하는 데에는 아무런 제한이 없다.
외부 프로비저너는 자신의 코드가 어디에서 동작하는지, 어떻게 프로비저너가 적재되는지, 어떻게 동작할지, 그리고 어떻게 설정을 할지까지 설정할 수 있다.

reclaimPolicy

여기에 있는 reclaimPolicy는 동적으로 프로비저닝될 때 생기는 PV의 설정을 지정한다.
그래서 PV와 마찬가지로 Delete, Retain으로 지정할 수 있다.
기본값은 Delete로 되어있다.
생각해보면 동적 프로비저닝을 위해서는 기본적으로 삭제되는 게 편리할 것 같긴 하다.

mountOptions

동적 프로비저닝되는 PV mountOptions 필드를 채우는 필드이다.
계속 말하지만, 검증 과정이 없기 때문에 잘못 설정되면 마운팅 시점에 실패할 수 있다.

parameters

동적 프로비저닝되는 볼륨에 대한 각종 설정을 지정하는 필드이다.
동적 프로비저닝이 호출되는 시점에 해당 인자들이 사용된다.
당연히 프로비저너마다 설정하는 방법이 다를 것이다.
최대 512개 지정될 수 있으며, 256 키비바이트만큼의 값을 가질 수 있다고 한다.

volumeBindingMode

PV 라이프사이클 binding단계에서 일어날 동작을 설정하는 필드이다.
즉, 정적 바인딩이나 동적 프로비저닝 시의 동작을 제어하며, 다음의 값이 가능하다.

웬만한 CSI 볼륨들은 전부 동적 프로비저닝이든, 정적 바인딩이든 WaitForFirstConsumer를 지원한다.
local PV도 이를 지원하는데, 다만 local PV 자체가 동적 프로비저닝을 지원하지 않아 그때만 안 된다.

주의할 것은 WaitForFirstConsumer는 스케줄링 조건을 고려한다는 것이다.
그래서 파드에 .spec.nodeName 필드로 노드를 지정하면 스케줄러를 우회하게 되기에 제대로 동작하지 않게 된다.
그러니 노드 이름을 사용하고 싶다면 .spec.nodeSelector에서 kubernetes.io/hostname키를 매칭하자.

allowedTopologies

위에서 volumeBindingModes: WaitForFirstConsumer를 설정했다면 별도로 프로비저닝에 대한 토폴로지를 설정할 필요가 없다.
그럼에도 토폴로지를 지정하고 싶다면 이 필드를 사용하면 된다.
위처럼 파드의 위치에 같이 가게 할 수는 있는데, 그럼에도 토폴로지를 지정하고 싶을 수도 있다.

allowedTopologies:
- matchLabelExpressions:
  - key: topology.kubernetes.io/zone
    values:
    - us-central-1a
    - us-central-1b

그럴 때 사용해주면 된다.

allowVolumeExpansion

PV 확장과 관련된 필드로, PVC에서 더 많은 양을 요청할 때 이를 동적으로 확장할 지 선택할 수 있다.
이것도 계속 말하지만, 이걸 정말 지원하는 플러그인인지는 꼭 확인해보자.

예시

nfs

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: example-nfs
provisioner: example.com/external-nfs
parameters:
  server: nfs-server.example.com
  path: /share
  readOnly: "false"

NFS가 내장된 볼륨이 있다고는 하나, 프로비저너가 있는 건 아니라 기본적으로 동적 프로비저닝을 하고 싶다면 외장 프로비저너를 따로 세팅을 해야만 한다.
결국 CSI 플러그인 쓰듯이 설치를 해야 하는 거다..

local

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner # 이 스토리지 클래스가 동적 프로비저닝이 불가능하다는 걸 명시하는 값이다.
volumeBindingMode: WaitForFirstConsumer

동적 프로비저닝은 안 되지만, 그럼에도 정적 바인딩은 할 수 있기에, local 역시 스토리지 클래스로서 생성할 수 있다.

관련 문서

이름 noteType created
StorageClass knowledge 2025-01-12
E-NFS 볼륨, 스토리지 클래스 설정 topic/explain 2024-10-17
T-vagrant 쿠버 버전 업그레이드 topic/temp 2025-01-14

참고


  1. https://kubernetes.io/docs/concepts/storage/dynamic-provisioning/ ↩︎