카테고리 없음

쿠버네티스 스토리지 — PV/PVC/StorageClass, OpenEBS

algml0703 2026. 5. 31. 22:24
반응형
파드를 재시작했더니 데이터가 다 날아가 있다. 컨테이너 데이터는 기본적으로 임시 디스크에 있어 파드가 사라지면 같이 사라지기 때문이다. 영속적인 데이터를 가지기 위해서 PV·PVC·StorageClass에 대한 설정이 필요하다.

세 가지 핵심 — PV, PVC, StorageClass

스토리지는 세 리소스가 협업한다. 

  • PV (PersistentVolume) — 실제 데이터가 저장되는 공간. AWS EBS, 로컬 디스크 같은 진짜 스토리지 인프라. 파드 생명주기와 독립적이라 파드가 죽어도 데이터는 남는다. 
  • PVC (PersistentVolumeClaim) — 스토리지 요청서. "1Gi짜리 RWO 볼륨 주세요"라는 주문서. 
  • StorageClass — 어떤 방식으로 볼륨을 만들지 정의한 규칙. 운영 환경에선 이걸로 동적 할당을 한다. 

사용자는 PVC로 요청하고, StorageClass 규칙에 따라 PV가 자동으로 만들어져(동적 프로비저닝) PVC에 바인딩된다. k3s를 설치하면 local-path StorageClass가 기본으로 생성돼 있다.

동적 프로비저닝의 흐름

가장 주의해야할 점은 PVC를 만들었다고 바로 PV가 생기는 게 아니다. PVC를 사용하는 파드가 떠야 비로소 PV가 만들어지고 바인딩된다(StorageClass의 WaitForFirstConsumer 모드인 경우). 그래서 PVC만 만들면 처음엔 Pending 상태로 보인다.

  1. StorageClass 정의(또는 기본 제공)
  2. PVC(요청서) 생성 → 아직 Pending
  3. PVC를 마운트하는 파드 생성 → 이때 PV 생성·바인딩 → Bound
  4. 파드가 삭제돼도 PV는 남음. reclaimPolicy에 따라 PVC 삭제 시 함께 삭제(Delete)할지 유지(Retain)할지 결정

local-path의 경우 local-path-provisioner 파드가 API 서버를 감시하다가, 자기가 관리하는 StorageClass를 요청하는 PVC가 생기면 PV를 만들어 관리한다.

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

reclaimPolicy와 volumeBindingMode

설정 의미
Delete PVC가 삭제되면 PV와 실제 스토리지까지 자동 삭제
Retain PVC가 삭제돼도 PV·데이터 유지. 수동으로 정리해야 함
Immediate PVC 생성 즉시 PV 프로비저닝·바인딩 (파드 스케줄링 미고려)
WaitForFirstConsumer PVC를 쓰는 파드가 스케줄될 때 그 노드 조건을 고려해 PV 생성. 로컬 스토리지는 Pod와 PV가 같은 노드에 있어야 하므로 이 모드를 쓴다.

접근 모드 — RWO, RWX, RWOP

접근 모드는 "몇 개의 노드가 동시에, 어떻게 마운트할 수 있는가"를 정한다. 여기서 핵심은 노드 기준이라는 점이다(파드 기준이 아니다).

모드 설명
ReadWriteOnce (RWO) 하나의 노드에서만 읽기/쓰기 마운트. 같은 노드의 여러 파드는 가능. 다른 노드가 마운트 시도하면 Multi-Attach error. 블록 스토리지가 보통 RWO.
ReadWriteMany (RWX) 여러 노드에서 동시 읽기/쓰기 마운트(동시성 문제 주의). 파일 스토리지(NFS 등)가 보통 RWX.
ReadWriteOncePod (RWOP) 단 하나의 파드에서만 읽기/쓰기 마운트. Kubernetes 1.22+
볼륨 마운트가 안 될 때 의심할 것
  • 파드 정의의 볼륨 이름·마운트 경로 불일치
  • 파일시스템 권한(uid/gid)이 안 맞아 쓰기 불가 → securityContext로 조정
  • RWO인데 다른 노드가 마운트 시도 → RWX 지원 StorageClass로 변경

OpenEBS 호스트패스

OpenEBS 호스트패스는 파드가 떠 있는 호스트 노드의 특정 디렉터리를 볼륨으로 쓴다. 데이터가 그 노드에만 있으므로 다른 노드로 파드를 옮기는 게 불가능하다는 제약이 있다. 기본 저장 위치는 /var/openebs/local이다.

kubectl create ns openebs
kubectl apply -f https://openebs.github.io/charts/openebs-operator.yaml
kubectl get pods -n openebs
kubectl get storageclass     # openebs-device, openebs-hostpath 확인

데이터 영속성 검증은 간단하다. 파드가 데이터를 쓰게 한 뒤, 파드를 지우고 새 파드가 같은 PVC를 마운트했을 때 이전 데이터가 남아 있는지 보면 된다.

kubectl exec [old-pod] -- cat /data/pod-out.txt   # 데이터 확인
kubectl delete pod [old-pod]
kubectl exec [new-pod] -- cat /data/pod-out.txt   # 이전 기록이 그대로 남아 있음
삭제 순서 주의
PVC/PV를 지우려면 그걸 쓰는 파드를 먼저 지워야 한다. PVC를 삭제하면 reclaimPolicy에 따라 PV도 함께 삭제될 수 있다.

IOPS 측정 — kubestr + fio

스토리지 성능은 IOPS(초당 I/O 횟수)로 본다. 쿠버네티스 환경에선 kubestr로 특정 StorageClass에 fio 벤치마크를 돌릴 수 있다.

kubestr fio -f fio-read.fio -s openebs-hostpath

# 노드 점검(drain): 그 노드의 파드를 다 빼냄
kubectl drain k8s-node-02 --ignore-daemonsets --delete-emptydir-data
# PV 없는 파드는 다른 노드로 옮겨가지만,
# 호스트패스 PV가 있는 파드는 그 노드에 묶여 Pending이 됨
kubectl uncordon k8s-node-02   # 노드 복귀

 

쿠버네티스 실전 시리즈
  1. 쿠버네티스란 무엇인가
  2. k3s로 클러스터 구성하기
  3. 쿠버네티스 네트워킹 — Service, DNS, MetalLB, Ingress
  4. 쿠버네티스 스토리지 — PV/PVC/StorageClass, OpenEBS 
  5. Helm으로 애플리케이션 배포하기
  6. CI/CD + 모니터링 스택 구축
반응형