StorageClass — 동적 프로비저닝으로 볼륨을 자동 생성하는 원리
PVC를 만들 때마다 관리자가 수동으로 PV를 생성해야 한다면, 수백 개의 서비스가 있는 클러스터에서는 어떻게 관리할 수 있을까요?
Static Provisioning은 관리자가 미리 PV를 생성해 두는 방식이지만, 서비스가 많아지면 관리가 불가능해집니다. StorageClass와 동적 프로비저닝은 PVC를 생성하면 자동으로 PV가 만들어지게 해서 이 문제를 해결합니다.
StorageClass란?
StorageClass는 "어떤 스토리지를, 어떤 방식으로 생성할지"를 정의하는 오브젝트입니다. PVC가 StorageClass를 지정하면, 해당 설정에 따라 PV가 자동으로 프로비저닝됩니다.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: ebs.csi.aws.com # CSI 드라이버
parameters: # 프로비저너에 전달할 파라미터
type: gp3
iops: "3000"
throughput: "125"
reclaimPolicy: Delete # PVC 삭제 시 PV도 삭제
volumeBindingMode: WaitForFirstConsumer # Pod 스케줄 후 바인딩
allowVolumeExpansion: true # 볼륨 확장 허용
mountOptions: # 마운트 옵션
- discard
- noatime
CSI (Container Storage Interface)
CSI는 Kubernetes와 스토리지 시스템을 연결하는 표준 인터페이스입니다. 이전에는 스토리지 드라이버가 Kubernetes 코어에 포함되어 있었지만(in-tree), CSI를 통해 외부 플러그인(out-of-tree)으로 분리되었습니다.
CSI 아키텍처
PVC 생성 → API Server → CSI Controller → 스토리지 API 호출 → 볼륨 생성
↓
Pod 스케줄 → kubelet → CSI Node Plugin → 볼륨 연결(Attach) → 마운트
CSI 드라이버는 두 가지 컴포넌트로 구성됩니다.
- Controller Plugin: 볼륨 생성/삭제/스냅샷 (Deployment로 실행)
- Node Plugin: 볼륨 연결/마운트/포맷 (DaemonSet으로 실행)
주요 CSI 드라이버
| 프로비저너 | 스토리지 | 특징 |
|---|---|---|
ebs.csi.aws.com | AWS EBS | 블록 스토리지, RWO만 |
efs.csi.aws.com | AWS EFS | 파일 스토리지, RWX 지원 |
pd.csi.storage.gke.io | GCP Persistent Disk | 블록 스토리지 |
disk.csi.azure.com | Azure Disk | 블록 스토리지 |
nfs.csi.k8s.io | NFS | 파일 스토리지, RWX 지원 |
# 클러스터에 설치된 CSI 드라이버 확인
kubectl get csidrivers
클라우드별 StorageClass 예제
AWS
# 범용 SSD (gp3)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gp3
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
throughput: "125"
encrypted: "true"
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
---
# 고성능 SSD (io2)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: io2-high-perf
provisioner: ebs.csi.aws.com
parameters:
type: io2
iops: "10000"
encrypted: "true"
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
GCP
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ssd
provisioner: pd.csi.storage.gke.io
parameters:
type: pd-ssd
volumeBindingMode: WaitForFirstConsumer
NFS
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs
provisioner: nfs.csi.k8s.io
parameters:
server: nfs-server.default.svc.cluster.local
share: /exports
volumeBindingMode
PV가 언제 생성되고 바인딩되는지를 제어하는 중요한 설정입니다.
Immediate (기본값)
PVC가 생성되면 즉시 PV를 생성하고 바인딩합니다.
PVC 생성 → 즉시 PV 프로비저닝 → 바인딩
(AZ를 모름 → Pod과 다른 AZ에 생성될 수 있음!)
문제: PV가 us-east-1a에 생성되었는데 Pod이 us-east-1b에 스케줄되면 마운트가 실패합니다.
WaitForFirstConsumer (권장)
Pod이 스케줄될 때까지 PV 생성을 지연합니다.
PVC 생성 → Pending 상태 → Pod 스케줄 → Pod의 노드/AZ에서 PV 생성 → 바인딩
volumeBindingMode: WaitForFirstConsumer # 거의 항상 이것을 사용
이 설정으로 Pod과 PV의 토폴로지(AZ) 불일치 문제를 방지할 수 있습니다.
Default StorageClass
storageClassName을 지정하지 않은 PVC에 자동 적용됩니다.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
annotations:
storageclass.kubernetes.io/is-default-class: "true" # Default 설정
provisioner: ebs.csi.aws.com
parameters:
type: gp3
# Default StorageClass 확인 (default) 표시됨
kubectl get sc
# NAME PROVISIONER RECLAIM VOLUMEBINDINGMODE
# standard (default) ebs.csi.aws.com Delete WaitForFirstConsumer
# fast-ssd ebs.csi.aws.com Retain WaitForFirstConsumer
동적 프로비저닝 전체 흐름
# 1. StorageClass 정의 (한 번만)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: ebs.csi.aws.com
parameters:
type: gp3
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
---
# 2. PVC 생성 (개발자)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-ssd
resources:
requests:
storage: 20Gi
---
# 3. Pod에서 사용 (개발자)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app:1.0
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: app-data
StorageClass 설계 전략
환경에 맞는 StorageClass를 미리 정의해 두면 개발자가 용도에 따라 선택할 수 있습니다.
# 개발/테스트용 — 저비용
fast-ssd:
type: gp3
reclaimPolicy: Delete
# 프로덕션 일반용
standard-prod:
type: gp3
reclaimPolicy: Retain
encrypted: true
# 프로덕션 DB용 — 고성능
high-perf-prod:
type: io2
iops: 10000
reclaimPolicy: Retain
encrypted: true
# 공유 파일시스템 (RWX)
shared-efs:
provisioner: efs.csi.aws.com
reclaimPolicy: Retain
트러블슈팅
# PVC가 Pending인 경우
kubectl describe pvc app-data
# 가능한 원인:
# - StorageClass가 존재하지 않음
# - CSI 드라이버가 설치되지 않음
# - AZ에 사용 가능한 볼륨이 없음
# - 할당량 초과
# CSI 드라이버 Pod 상태 확인
kubectl get pods -n kube-system | grep csi
# 볼륨 이벤트 확인
kubectl get events --field-selector reason=ProvisioningFailed
정리
StorageClass는 동적 프로비저닝의 핵심으로, PVC를 생성하면 자동으로 PV가 만들어지게 합니다. CSI 드라이버가 실제 스토리지 생성을 담당하고, volumeBindingMode: WaitForFirstConsumer로 토폴로지 문제를 방지합니다. 환경별/용도별 StorageClass를 미리 설계해 두면 스토리지 관리가 크게 단순화됩니다.