Kubernetes를 사용하다 보면 애플리케이션에서 데이터를 저장하기 위해 스토리지를 사용하는 일이 필수적으로 발생합니다. 이를 위해 Kubernetes는 PersistentVolume (PV), PersistentVolumeClaim (PVC), 그리고 StorageClass라는 개념을 도입했습니다. 이 포스트에서는 각 개념을 상세히 정리하고, 이들이 어떻게 상호작용하는지, 어떤 상황에서 각각을 사용하는지를 설명하겠습니다.
📦 1. Persistent Volume (PV)란?
**PersistentVolume(PV)**는 클러스터 관리자가 미리 구성한 스토리지 리소스입니다. 이는 쿠버네티스 클러스터의 일부 리소스로 존재하며, 사용자에게 제공되는 스토리지와는 독립적인 객체입니다.
🔹 특징
- PV는 NFS, iSCSI, AWS EBS, GCE Persistent Disk 등 다양한 스토리지 백엔드를 지원합니다.
- Pod에 종속되지 않고 독립적으로 존재합니다.
- 수동(manual) 또는 동적(dynamic)으로 생성할 수 있습니다.
🔹 예시
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-example
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /mnt/data
🧾 2. Persistent Volume Claim (PVC)란?
**PersistentVolumeClaim(PVC)**는 사용자가 필요한 스토리지를 요청하는 객체입니다. 일종의 스토리지 요청서로 이해할 수 있습니다.
🔹 특징
- 원하는 용량(storage)과 접근 방식(accessMode)을 지정하여 요청합니다.
- PVC가 생성되면 Kubernetes는 조건에 맞는 PV를 바인딩하거나, StorageClass를 통해 자동으로 PV를 생성합니다.
🔹 예시
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-example
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
🏷️ 3. StorageClass란?
StorageClass는 동적 프로비저닝(dynamic provisioning)을 위해 사용됩니다. 사용자가 PVC를 생성할 때 storageClassName을 명시하면, 해당 StorageClass에 정의된 방식으로 PV가 자동으로 생성됩니다.
🔹 주요 요소
- provisioner: 실제 볼륨을 생성하는 드라이버 예: kubernetes.io/aws-ebs, kubernetes.io/gce-pd 등
- parameters: 해당 프로비저너에 전달되는 설정값들
🔹 예시
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-storage
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
PVC 예시:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-fast
spec:
storageClassName: fast-storage
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
🔄 이들의 관계
- 관리자가 PV를 수동 생성하거나, StorageClass를 통해 자동 생성되도록 설정
- 사용자는 PVC를 통해 필요한 스토리지를 요청
- Kubernetes는 조건에 맞는 PV를 PVC에 바인딩
- Pod는 PVC를 volumeMount로 사용하여 실제 스토리지에 접근
⚠️ 주의할 점
- AccessModes에 주의: ReadWriteOnce(RWO), ReadOnlyMany(ROX), ReadWriteMany(RWX) 중 어떤 접근 방식이 필요한지 명확히 해야 함
- PVC가 요청한 용량보다 작은 PV는 바인딩되지 않음
- StorageClass는 기본값이 존재할 수 있으며, 이를 지정하지 않으면 default StorageClass가 사용됨
Pod에서 PVC 마운트하는 실전 예제
PVC는 단독으로는 의미가 없고, Pod가 해당 PVC를 마운트하여 실제 애플리케이션에서 사용해야 의미가 있습니다.
📁 예시: NGINX에서 PVC 마운트하기
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: web-content
volumes:
- name: web-content
persistentVolumeClaim:
claimName: pvc-example
✅ 주요 포인트
- volumeMounts.mountPath: 컨테이너 내부에 마운트될 경로
- volumes.persistentVolumeClaim.claimName: 앞서 생성한 PVC 이름
이 설정을 통해 애플리케이션 재시작 시에도 데이터가 보존됩니다.
동적 vs 정적 프로비저닝 실습
🧱 정적 프로비저닝
- 관리자가 직접 PV 생성
- 사용자가 PVC로 요청
- 조건이 맞으면 바인딩
장점: 세부 설정 제어 가능
단점: 자동화가 어렵고 오퍼레이션 부담
⚙️ 동적 프로비저닝
- 사용자가 PVC 생성하면서 storageClassName 지정
- Kubernetes가 PV를 자동 생성
장점: 자동화에 적합, 클라우드 환경과 잘 어울림
단점: 프로비저너 설정이 필요, 내부 스토리지에는 부적합할 수 있음
📘 실습 비교
항목 정적 프로비저닝 동적 프로비저닝
PV 생성 | 수동 (kubectl apply) | 자동 |
StorageClass 필요 | ❌ | ✅ |
클라우드 환경 적합 | △ | ◎ |
온프레미스 적합 | ◎ | △ |
⚡ 3. StorageClass 별 성능 비교 및 테스트
💡 목적
어떤 StorageClass가 애플리케이션의 성능에 가장 적합한지 파악합니다.
🧪 테스트 조건
- AWS EBS 기준 (gp2, gp3, io1 비교)
- fio 툴을 사용한 read/write throughput 측정
- 블록 사이즈: 4KB / 1MB
- 작업량: 1GB
📊 결과 예시
StorageClass IOPS (4KB, read) IOPS (4KB, write) MB/s (1MB, seq read) MB/s (1MB, seq write)
gp2 | 3000 | 2800 | 120 | 110 |
gp3 | 5000 | 5000 | 180 | 170 |
io1 (provisioned 10000) | 9500 | 9200 | 230 | 225 |
📝 결론
- gp3는 비용 대비 성능이 뛰어나 대부분의 워크로드에 적합
- io1/io2는 고성능 DB 등에 유리하나 비용이 큼
- 성능이 중요한 워크로드는 반드시 사전 테스트 권장
🎯 정리 및 팁
- Pod에 PVC 마운트 시, readOnly: true/false 옵션도 조정 가능
- StorageClass 성능은 클라우드 벤더/리전/환경에 따라 다를 수 있음
- 테스트 자동화를 위한 Job 배포도 고려해보자 (fio Pod 실행 등)
🔚 마무리
PV, PVC, StorageClass는 Kubernetes에서 영속 스토리지를 다루기 위한 핵심 개념입니다. 이들을 잘 이해하고 구성하면 Stateful Application 운영이 훨씬 수월해집니다.
'DevOps > Kubernates' 카테고리의 다른 글
[k8s] Kubernetes 서비스 타입, Headless Service? (6) | 2025.07.11 |
---|---|
[k8s] API Groups 란? (0) | 2025.03.26 |
[k8s] Local Kubernetes Distribution (1) | 2025.01.25 |
[CKA] Certified Kubernetes Administrator (신청 방법, 꿀팁) (0) | 2025.01.05 |
[Kubernetes] Failed to pull image “no matching manifest for linux/arm64/v8 in the manifest list entries (0) | 2024.03.31 |
댓글