Chapter 9

퍼시스턴트 볼륨

  • 9.1 hostPath와 emptyDir
  • 9.2 퍼시스턴트 볼륨과 퍼시스턴트 볼륨 클레임
  • 9.3 StorageClass와 Dynamic Provisioning

파드는 일시적이야. 죽으면 데이터가 사라지는데, 데이터베이스 같은 건 당연히 데이터가 보존돼야 하잖아. 쿠버네티스는 이를 위해 다양한 볼륨 타입과 퍼시스턴트 볼륨 시스템을 제공해.

가장 기본적인 볼륨 타입 두 가지부터 보자. emptyDir은 파드가 생성될 때 빈 디렉터리가 만들어지고, 파드가 삭제되면 같이 사라져. 같은 파드 안의 여러 컨테이너가 데이터를 공유할 때 쓰는 거야:

spec:
  containers:
    - name: app
      image: my-app
      volumeMounts:
        - name: shared-data
          mountPath: /data
    - name: sidecar
      image: log-collector
      volumeMounts:
        - name: shared-data
          mountPath: /logs
  volumes:
    - name: shared-data
      emptyDir: {}

app 컨테이너가 /data에 쓴 파일을 sidecar 컨테이너가 /logs에서 읽을 수 있어. 하지만 파드가 삭제되면 데이터도 사라지니까 영속성은 없지. 임시 파일이나 캐시 용도로 적합해. emptyDirmedium: Memory를 설정하면 tmpfs(메모리 기반)를 사용할 수 있는데, 디스크보다 빠르지만 노드 메모리를 소비해.

hostPath는 노드(호스트)의 파일시스템 경로를 파드에 마운트하는 거야:

volumes:
  - name: host-volume
    hostPath:
      path: /var/log
      type: Directory

노드의 /var/log를 파드 안에서 접근할 수 있어. 파드가 삭제돼도 노드에 데이터가 남으니까 어느 정도 영속성이 있지만, 파드가 다른 노드에 스케줄링되면 이전 노드의 데이터에 접근할 수 없다는 치명적인 문제가 있어. hostPath는 노드의 시스템 파일에 접근해야 하는 특수한 경우(모니터링 에이전트 등)에만 쓰고, 일반적인 데이터 저장에는 쓰지 않는 게 좋아. 보안 위험도 있거든 — 호스트 파일시스템에 직접 접근하는 거니까.

실제 프로덕션에서 데이터를 저장하려면 **PV(PersistentVolume)**와 **PVC(PersistentVolumeClaim)**를 사용해야 해. PV는 클러스터 관리자가 만들어둔 실제 스토리지 볼륨이야. 노드에 독립적이고, 파드 라이프사이클과 무관하게 존재하지. AWS EBS, GCE Persistent Disk, NFS 등 다양한 백엔드를 지원해. PVC는 사용자(개발자)가 "이만큼의 스토리지가 필요해"라고 요청하는 거야. 쿠버네티스가 조건에 맞는 PV를 찾아서 바인딩해줘.

이렇게 분리하는 이유는 관심사의 분리 때문이야. 관리자는 스토리지를 프로비저닝하고, 개발자는 필요한 용량만 요청하면 돼. 개발자가 실제 스토리지 인프라를 알 필요가 없지.

# PV 생성 (관리자)
apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /mnt/data
# PVC 생성 (개발자)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
# 파드에서 PVC 사용
spec:
  containers:
    - name: app
      volumeMounts:
        - name: data
          mountPath: /var/data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: my-pvc

accessModes는 세 가지야:

  • ReadWriteOnce (RWO): 하나의 노드에서만 읽기/쓰기 가능
  • ReadOnlyMany (ROX): 여러 노드에서 읽기 가능
  • ReadWriteMany (RWX): 여러 노드에서 읽기/쓰기 가능 (NFS 같은 공유 스토리지 필요)

Reclaim Policy도 알아야 해:

  • Retain: PVC가 삭제돼도 PV와 데이터를 보존해. 수동으로 정리해야 하지.
  • Delete: PVC가 삭제되면 PV와 실제 스토리지도 삭제돼. 클라우드 환경에서 주의해야 해.
  • Recycle: 데이터를 지우고 PV를 재사용하는 건데, 현재는 deprecated야.

PV를 미리 만들어두는 방식은 관리자가 수동으로 스토리지를 프로비저닝해야 하니까 번거롭잖아. StorageClass를 사용하면 PVC가 생성될 때 PV를 자동으로(동적으로) 프로비저닝할 수 있어:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp3
  fsType: ext4
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer

PVC에서 StorageClass를 지정하면:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 20Gi

이 PVC가 생성되면 쿠버네티스가 StorageClass의 provisioner를 통해 자동으로 20Gi짜리 AWS EBS gp3 볼륨을 만들고, PV를 생성해서 바인딩해줘. 관리자가 PV를 미리 만들 필요가 없지.

volumeBindingMode는 두 가지야:

  • Immediate: PVC 생성 즉시 PV를 프로비저닝해. 파드가 아직 스케줄링되지 않은 상태에서 볼륨이 만들어질 수 있어서, 파드와 볼륨이 다른 가용 영역(AZ)에 생기는 문제가 발생할 수 있어.
  • WaitForFirstConsumer: 파드가 스케줄링될 때까지 PV 프로비저닝을 지연해. 파드와 같은 AZ에 볼륨이 생기니까 이 옵션이 더 안전하지.

대부분의 클라우드 환경에는 기본 StorageClass가 설정되어 있어. GKE에서는 standard, EKS에서는 gp2 같은 게 기본으로 들어 있어서, storageClassName을 생략하면 기본 StorageClass가 사용돼.


정리

9장 읽고 기억할 거 세 가지:

  1. emptyDir은 파드와 함께 사라지고, hostPath는 노드에 종속된다. 둘 다 프로덕션 데이터 저장에는 부적합.
  2. PV/PVC는 스토리지와 사용을 분리하는 추상화다. 관리자는 PV를, 개발자는 PVC를 관리하는 관심사의 분리.
  3. StorageClass + Dynamic Provisioning으로 PV 생성을 자동화한다. PVC만 만들면 스토리지가 자동 프로비저닝되니까 운영 부담이 크게 줄어든다.