[Kubernetes] Volume(PV, PVC)

PersistentVolume(PV), PersistentVolumeClaim(PVC)

상태가 있는 애플리케이션(Stateful Application)의 데이터 문제를 해결하기 위해 Kubernetes는 PersistentVolume(PV)와 PersistentVolumeClaim(PVC)를 제공한다. 이를 활용하면 파드(Pod)가 삭제되거나 노드가 변경되어도 데이터는 지속적으로 유지될 수 있다. 

 

파드 데이터 영속성의 필요성

상태를 가지는 애플리케이션, 예를 들어 MySQL 같은 데이터베이스는 데이터를 저장해야 하며, 파드가 종료되거나 재시작되어도 데이터는 유지되어야 한다. 하지만 기본적으로 Kubernetes 파드는 다음과 같은 문제를 가진다. 

  • 비영속적 데이터: 디플로이먼트나 파드가 삭제되면 내부의 모든 데이터도 함께 삭제.
  • 노드 종속성: 특정 노드에만 데이터를 저장하면, 파드가 다른 노드로 이동했을 때 데이터를 접근할 수 없음.

영속적 데이터 저장을 위한 방법

이를 해결하기 위해 퍼시스턴트 볼륨(PersistentVolume, PV)을 사용한다. PV는 다음과 같은 역할을 한다.

  • 클러스터 내 노드 간 네트워크 스토리지를 통해 데이터를 공유.
  • 파드가 이동해도 데이터에 지속적으로 접근 가능.

Kubernetes의 PV는 여러 스토리지 백엔드를 지원하며, 주로 사용되는 백엔드는 다음과 같다. 

  • NFS(Network File System): 간단히 네트워크 파일 공유 가능.
  • AWS EBS(Elastic Block Store): AWS 클라우드 환경에서 블록 스토리지 제공.
  • Ceph: 고성능 분산 스토리지.
  • GlusterFS: 클러스터 환경에서 분산 파일 시스템.

임시 볼륨 기법 emptyDir 볼륨

Pod 생성 시 Podspec에 의해 Pod 내부에 존재하는 Volume 생성을 의미한다. 임시 데이터를 저장하는 데 사용되는 비어있는 디렉터리 제공방식으로 동일 Pod 내의 모든 컨테이너의 접근이 가능하고 내부 데이터 공유를 위해 사용한다. 그래서 Pod와 Lifecycle이 같다. emptyDir Volume은 Pod를 실행하는 Node 환경에 따라 성능이 변화한다. 

 

Multi container Pod에 emptyDir 활용 

apiVersion: v1
kind: Pod
metadata:
  name: temp-pod1
spec:
  volumes:
    - name: temp-vol
      emptyDir: {} # emptyDir 볼륨
  containers:
    - name: temp-container1
      image: ubuntu:14.04
      volumeMounts:
        - name: temp-vol
          mountPath: /mount1
    - name: temp-container2
      image: ubuntu:14.04
      volumeMounts:
        - name: temp-vol
          mountPath: /mount2

파드 생성 후 각 컨테이너 볼륨 연동 테스트 

kubectl apply -f temp-pod.yaml
kubectl exec -it temp-pod1 -c temp-container1 -- sh -c "echo 'Hello from container1' > /mount1/testfile"
kubectl exec -it temp-pod1 -c temp-container2 -- sh -c "cat /mount2/testfile"
Hello from container1

그 외에 다음과 같은 방법으로 emptyDir를 활용할 수 있다.

  • 사이드카 컨테이너가 깃허브 소스코드를 주기적으로 pull 받아 emptyDir을 통해 애플리케이션 컨테이너에 공유. 이를 통해 애플리케이션 컨테이너는 실시간으로 최신 소스코드를 적용 가능.
  • Tomcat의 로그 데이터를 Logstash가 수집하고 처리하여 Elasticsearch로 전송하는 로그 관리 파이프라인을 구성
  • 별도의 컨테이너를 추가하여 설정 파일을 동적으로 갱신. emptyDir을 통해 변경된 설정 파일을 애플리케이션 컨테이너에 실시간 공유

영구 볼륨 기법 hostPath 볼륨

hostPath 볼륨은 Kubernetes에서 노드의 로컬 디렉토리를 Pod와 공유하는 볼륨 타입이다. 이는 Docker의 -v 옵션과 유사하며, Pod의 데이터를 보존할 수 있는 간단한 방법을 제공한다. 

 

hostPath를 volumes 항목에 정의하고, 이를 Pod의 컨테이너에 마운트한다. 

apiVersion: v1
kind: Pod
metadata:
  name: hostpath-pod
spec:
  volumes:
  - name: hostpath-volume
    hostPath:
      path: /tmp  # 호스트 디렉토리
  containers:
  - name: app-container
    image: busybox
    volumeMounts:
    - name: hostpath-volume
      mountPath: /etc/data  # 컨테이너 내부 경로

hostPath 볼륨은 특정 노드의 디렉토리를 마운트하여 손쉽게 데이터를 공유할 수 있는 간단한 방법을 제공한다. 이는 특히 모든 워커 노드에 배치되어야 하는 모니터링 툴(CAdvisor 등)을 배포할 때 유용하게 사용할 수 있다. 하지만 hostPath 볼륨을 사용할 때는 몇 가지 제한 사항과 문제점이 존재한다. 우선, hostPath는 노드에 종속적이기 때문에 Pod가 장애로 다른 노드로 스케줄링될 경우, 이전 노드에 저장된 데이터를 사용할 수 없다. 또한, 특정 노드에 의존하기 때문에 클러스터 확장성에 부정적인 영향을 미치고, 노드의 로컬 파일 시스템에 접근하는 방식이 보안 리스크를 증가시킬 수 있다. 이런 문제를 해결하기 위해 hostPath를 사용할 경우, Pod가 특정 노드에서만 실행되도록 노드 스케줄링을 설정해야 하는 번거로움이 있다. 

따라서 hostPath는 주로 단기적인 개발 및 테스트 환경에서 간단한 데이터 공유가 필요할 때 적합하며, 노드 로컬 데이터를 수집해야 하는 모니터링 툴을 배포할 때 유용하다. 그러나 장기적으로 데이터를 보존하고 확장성을 고려해야 하는 경우에는 Persistent Volume (PV) 및 Persistent Volume Claim (PVC)를 사용하는 것이 더 올바른 솔루션이다. PV와 PVC는 클라우드 스토리지나 네트워크 스토리지(NFS 등)를 기반으로 하여 노드 독립적으로 데이터를 관리할 수 있어 확장성과 유연성을 제공한다. 

Kubernetes Network Volume

쿠버네티스에서는 다양한 종류의 네트워크 볼륨을 파드에 마운트할 수 있으며, 별도의 플러그인을 설치하지 않아도 된다. 사용 가능한 네트워크 볼륨으로는 온프레미스 환경에서 구축할 수 있는 NFS, iSCSI, GlusterFS, Ceph와 같은 것들이 있다. 또한, 클라우드 플랫폼에서는 AWS의 EBS, GCP의 gcePersistentDisk와 같은 볼륨도 마운트할 수 있다. 

네트워크 볼륨은 특별히 위치가 정해져 있지 않으며, 네트워크를 통해 접근할 수 있다면 쿠버네티스 클러스터 내부와 외부 어디에 존재해도 무방하다. 다만, AWS의 EBS와 같이 클라우드에 종속적인 볼륨을 사용하려면 해당 클라우드 플랫폼에 맞는 설정이 쿠버네티스 클러스터 생성 시 필요하다. 

NFS 볼륨 이용하기 

NFS 서버용 Service와 Deployment

먼저 NFS 서버를 Kubernetes에 배포한다. 

apiVersion: v1
kind: Service
metadata:
  name: nfs-service
spec:
  selector:
    app: nfs
  ports:
    - protocol: TCP
      port: 2049
  clusterIP: None  # Headless Service로 설정
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-server
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs
  template:
    metadata:
      labels:
        app: nfs
    spec:
      containers:
        - name: nfs
          image: itsthenetwork/nfs-server-alpine
          args:
            - "/exports"
          ports:
            - name: nfs
              containerPort: 2049
          volumeMounts:
            - name: nfs-data
              mountPath: /exports
      volumes:
        - name: nfs-data
          emptyDir: {}  # 데이터를 메모리에 임시 저장

NFS 클라이언트 구성 

NFS 서버에 데이터를 저장할 파드(NFS 클라이언트)를 생성한다. 

apiVersion: v1
kind: Pod
metadata:
  name: nfs-client
spec:
  containers:
    - name: client
      image: busybox
      command: ["/bin/sh", "-c", "while true; do sleep 30; done;"]
      volumeMounts:
        - name: nfs-volume
          mountPath: /mnt
  volumes:
    - name: nfs-volume
      nfs:
        server: {NFS_SERVICE_IP}  # NFS 서버의 IP
        path: /

ClusterIP가 필요한 이유

  • NFS 마운트 과정은 컨테이너 내부가 아닌 워커 노드에서 처리된다. 
    • NFS 볼륨은 kubelet이 워커 노드에서 마운트한 후 파드 컨테이너에 바인드 마운트된다. 
    • 이 과정에서 kubelet은 Kubernetes의 DNS를 사용하지 않으므로, nfs-service와 같은 서비스의 DNS 이름으로 NFS 서버에 접근할 수 없다. 
  • 따라서, NFS 서비스의 Cluster IP를 직접 지정하여 NFS 서버에 연결해야 한다. 

NFS 서버와 별개로, NFS 클라이언트를 통해 마운트를 시도하는 주체는 kubelet이다. 파드가 실행될 때, kubelet이 워커 노드의 OS에서 NFS 서버로 네트워크 연결을 만들어 마운트를 수행한다. 왜냐면, 컨테이너 내부는 기본적으로 네트워크 스토리지 같은 시스템 자원을 직접 마운트할 권한이 없기 때문이다. 그래서 kubelet이 노드에서 먼저 NFS를 마운트하고, 그 결과를 파드의 mountPath 로 바인드 마운트하는것이다. 

헤드리스 서비스 (ClusterIP: None)

  • nfs-service의 ClusterIP를 None으로 설정하면 헤드리스 서비스가 생성된다. 
    • 헤드리스 서비스는 Kubernetes DNS에서 해당 서비스 이름에 대해 Pod IP 리스트를 반환한다.
    • 이를 통해 클라이언트는 NFS 서버 파드의 실제 IP를 직접 사용할 수 있다.

헤드리스 서비스 예시 

일반적인 서비스의 DNS 동작

  • Kubernetes에서 ClusterIP가 설정된 일반 서비스는 서비스 이름을 DNS로 조회하면 단일 IP 주소(서비스의 ClusterIP)를 반환한다. 
  • 이 단일 IP 주소는 서비스가 관리하는 여러 파드로의 트래픽을 라운드로빈 방식으로 분배한다. 
  1. 서비스 이름: my-service
  2. DNS 조회 결과: 10.96.0.1 (서비스의 ClusterIP)
  3. 클라이언트는 10.96.0.1로 요청하고, 서비스가 적절한 파드로 트래픽을 분배한다. 

헤드리스 서비스의 DNS 동작 

  • ClusterIP가 None으로 설정된 헤드리스 서비스는 단일 ClusterIP를 생성하지 않는다. 
  • 대신, DNS 조회 결과로 해당 서비스와 연결된 모든 파드의 IP 리스트를 반환한다. 
  1. 서비스 이름: my-headless-service
  2. 연결된 파드:
    • 파드 A: 192.168.1.10
    • 파드 B: 192.168.1.11
    • 파드 C: 192.168.1.12
  3. DNS 조회 결과
192.168.1.10 192.168.1.11 192.168.1.12

클라이언트는 이 리스트 중 하나를 선택해 직접 연결한다. 

NFS 서버의 Cluster IP 설정 및 적용

ClusterIP: None 설정으로 인해, NFS 서버의 Cluster IP를 얻어야 클라이언트가 서버에 연결 가능하다. 

NFS 서버 Cluster IP 설정 및 적용

# NFS 서버 Cluster IP 가져오기
export NFS_CLUSTER_IP=$(kubectl get svc nfs-service -o jsonpath='{.spec.clusterIP}')

# 클라이언트 YAML에 서버 IP 적용
cat nfs-client.yaml | sed "s/{NFS_SERVICE_IP}/$NFS_CLUSTER_IP/g" | kubectl apply -f -

NFS 구축시 고려사항

  • NFS 서버의 안정성
    • 단일 NFS 서버는 SPOF(단일 장애점)이 될 수 있으므로, 백업이나 HA(고가용성) 구성을 고려해야 한다. 
  • NFS 클라이언트 패키지 설치
    • NFS 볼륨을 사용하는 워커 노드에 NFS 클라이언트 패키지(nfs-common 등)가 설치되어 있어야 한다. 
# 워커 노드에서 NFS 클라이언트 패키지 설치 (필요 시)
sudo apt-get install -y nfs-common

PV와 PVC의 흐름

  1. PV를 미리 생성: 여러 종류의 네트워크 볼륨을 활용해 Persistent Volume(PV)를 미리 클러스터에 생성한다. 이 PV는 물리적인 저장소의 정보를 포함하고 있다. 
  2. PVC를 생성: 사용자는 Persistent Volume Claim(PVC)을 생성해서, 필요한 볼륨 크기와 접근 방식(읽기/쓰기 모드 등)을 명시한다. PVC는 어떤 저장소를 사용할지 명시하지 않고, 단순히 요구 사항만 정의하는 역할을 한다. 
  3. PV와 PVC 바인딩: 쿠버네티스는 PVC의 요구 사항에 맞는 PV를 찾아서 자동으로 바인딩한다. 이후, 바인딩된 PV는 파드에 마운트되어, 파드가 데이터를 저장하거나 읽을 수 있다 .

PV 예시

apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /mnt/nfs
    server: nfs-server.example.com

PVC 예시 

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

PVC 사용이유 

  1. 저장소 세부사항 추상화: 사용자는 디플로이먼트나 파드의 YAML 파일에서 저장소의 상세한 스펙을 명시할 필요가 없다. 단지 PVC만 명시하면 되고, 그에 맞는 PV가 자동으로 할당돼기 때문이다. 사용자는 저장소의 종류나 세부사항에 대해 신경 쓸 필요 없이, 저장소 요구사항만 정의하면 된다. 
  2. 유연한 스토리지 관리: PVC는 스토리지 백엔드와 독립적이기 때문에, 사용자는 PVC를 통해 원하는 스토리지 요구사항만 정의하고, 어떤 저장소(NFS, EBS 등)가 할당될지는 쿠버네티스가 처리한다. 
  3. 자동화된 스토리지 프로비저닝: PVC는 클러스터에서 사용할 수 있는 동적 프로비저닝을 지원한다. 만약 사용자가 원하는 PVC가 이미 존재하지 않으면, 쿠버네티스는 PVC의 요구사항을 만족하는 PV를 자동으로 생성할 수 있다.  

AWS EBS 볼륨 사용

EBS 볼륨 생성

먼저 AWS CLI를 사용하여 EBS 볼륨을 생성해야 한다. aws ec2 create-volume 명령어를 사용해서 EBS 볼륨을 생성할 수 있다.

aws ec2 create-volume \
    --size 10 \
    --volume-type gp2 \
    --availability-zone us-west-2a
    
 # 반환된 VolumeID
 {
    "VolumeId": "vol-0abcd1234efgh5678",
    "Size": 10,
    "AvailabilityZone": "us-west-2a",
    "State": "creating",
    ...
}

Persistent Volume (PV) 정의

AWS EBS 볼륨을 Kubernetes에서 사용할 수 있게 하기 위해, PV 리소스를 awsElasticBlockStore를 사용하여 정의할 수 있다. 

pv-ebs.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: ebs-pv
spec:
  capacity:
    storage: 10Gi  # EBS 볼륨 크기
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: ebs-sc
  awsElasticBlockStore:
    volumeID: vol-0abcd1234efgh5678  # EBS 볼륨의 VolumeId
    fsType: ext4
    partition: 0
  • capacity: EBS 볼륨의 크기이다. size로 지정한 값과 동일해야 한다.
  • volumeID: AWS에서 생성한 EBS 볼륨의 VolumeId를 입력해야 한다..
  • fsType: EBS 볼륨에 사용할 파일 시스템 유형
  • partition: 기본값은 0이야. 대부분의 경우 0으로 두면 됀다. 

Persistent Volume Claim (PVC) 정의

# pvc-ebs.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi  # PVC 크기, PV와 동일해야 함
  storageClassName: ebs-sc
  
  --------------------------------------------
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: ebs-pod
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - mountPath: /usr/share/nginx/html
      name: ebs-volume
  volumes:
  - name: ebs-volume
    persistentVolumeClaim:
      claimName: ebs-pvc
  • accessModes: ReadWriteOnce로 설정해서 파드가 EBS 볼륨을 읽고 쓸 수 있도록 한다.
  • resources.requests.storage: PVC 크기도 PV 크기와 맞아야 한다.
  • storageClassName: 위에서 설정한 ebs-sc와 일치해야 한다.
  • volumes: persistentVolumeClaim.claimName을 통해 PVC 이름을 지정하고, volumeMounts 항목에서 실제 컨테이너 내의 mountPath를 설정해야한다. 

AWS 에서 PV, PVC 사용 흐름도 

EBS 볼륨 생성: aws ec2 create-volume 명령어로 EBS 볼륨을 생성한다.

Persistent Volume(PV) 정의: awsElasticBlockStore를 사용하여 EBS 볼륨을 Kubernetes에서 사용할 수 있도록 정의한다.

Persistent Volume Claim(PVC) 정의: PVC를 통해 EBS 볼륨을 요청하고, 이를 파드에서 사용할 수 있도록 한다.

파드에서 EBS 사용: 파드의 volumeMounts 항목에서 PVC를 마운트하여 EBS 볼륨을 사용할 수 있게 한다. 

PVC 조건

PVC가 요청한 조건에 맞는 PV를 선택하는 과정에서 중요한 점은 조건 일치이다. PVC에서 정의한 요구 사항을 만족하는 PV가 있어야만 그 PV가 바인딩된다. 하지만 이때 중요한 점은, accessModes나 용량 같은 속성들이 메타데이터에 불과하며, 실제로 해당 속성들이 볼륨의 동작을 강제하지 않는다는 점이다. 예를 들어, AWS EBS를 사용하는 경우, accessModes를 ReadWriteMany로 설정할 수 있지만, 실제로 EBS는 ReadWriteOnce만 지원하므로, 이런 설정은 해당 볼륨을 선택하는 기준에만 영향을 미친다.

  1. 용량 (Capacity)
    PVC가 요청한 용량은 해당 PV가 제공하는 실제 용량과 일치해야만 바인딩된다. 그러나 capacity.storage 항목을 설정한다고 해서 실제로 해당 크기의 디스크 파티션이 생성되지는 않는다. 예를 들어, 로컬 볼륨이나 hostPath 같은 경우 크기를 설정한다고 해서 실제로 디스크 공간이 할당되지 않으므로, 용량은 설정된 값만큼의 추상적인 메타데이터로 취급된다.
  2. 접근 모드 (Access Modes)
    accessModes는 해당 볼륨이 어떤 방식으로 접근할 수 있는지 나타내는 설정이지만, 이 설정이 실제로 해당 볼륨의 접근 방식을 강제하지는 않는다. 예를 들어, ReadWriteMany로 설정한 PVC는 PV가 ReadWriteOnce를 지원하는 경우에도 바인딩될 수 있다. 이 설정은 주로 어떤 종류의 볼륨이 필요할지를 선택하는 기준으로 사용된다.
  3. 스토리지 클래스 (StorageClass)
    스토리지 클래스는 볼륨의 속성, 성능 수준 등을 정의하는 데 사용된다. storageClassName을 통해 특정 스토리지 클래스를 요청하면, 해당 클래스를 가진 PV만 선택되어 바인딩된다. 만약 스토리지 클래스가 정의되지 않으면, 기본 스토리지 클래스가 사용된다.
  4. 라벨 (Labels)
    PVC는 라벨 셀렉터를 사용해 PV를 더 세밀하게 선택할 수 있다. 라벨을 이용하면 특정 환경에 맞는 PV를 선택하는 데 유용하다. 예를 들어, environment: production이라는 라벨을 지정하면, 해당 라벨을 가진 PV가 PVC와 바인딩된다.

결국, accessModes나 용량 같은 설정들은 볼륨이 실제로 어떻게 동작하는지와는 관련이 없으며, 주로 PV 선택에 필요한 메타데이터 역할을 한다. 따라서 PVC가 요구하는 조건을 만족하는 PV가 선택되기 위해서는, 이러한 설정들이 조건에 맞는지 확인하는 것 외에도, 스토리지 클래스와 라벨을 이용한 세밀한 선택이 중요하다.

 

Persistent Volume (PV) 예시

apiVersion: v1
kind: PersistentVolume
metadata:
  name: ebs-pv
  labels:
    type: ebs
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: standard
  awsElasticBlockStore:
    volumeID: vol-0abcd1234efgh5678
    fsType: ext4
  • 이 PV는 awsElasticBlockStore를 사용하여 EBS 볼륨을 나타냄.
  • accessModes는 ReadWriteOnce로 설정되어 있어 하나의 파드에서만 읽고 쓸 수 있음.
  • storageClassName은 standard로 설정됨, 이는 기본 스토리지 클래스를 사용하도록 설정된 것.
  • capacity는 10Gi로 설정되어 있음.

Persistent Volume Claim (PVC) 예시

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: standard
  • PVC는 accessModes를 ReadWriteOnce로 설정하고, resources.requests.storage는 10Gi로 설정됨.
  • storageClassName도 standard로 설정되어, PV에서 storageClassName: standard와 일치하는 PV를 요청함.

조건 일치로 바인딩 

  • 이 예시에서는 ebs-pv와 ebs-pvc가 완전히 일치하는 조건을 가짐.
    • accessModes: ReadWriteOnce
    • storageClassName: standard
    • storage: 10Gi

따라서, PVC는 ebs-pv와 바인딩된다.

PV의 라이프 사이클

PV는 Kubernetes 클러스터에서 클러스터 관리자에 의해 미리 생성되거나 동적으로 프로비저닝될 수 있다. PV의 라이프 사이클은 대체로 아래와 같은 단계로 진행된다:

  • 생성
    • 관리자가 PV를 정의하여 클러스터에 생성하거나, PVC가 요구하는 스토리지 요구사항에 맞춰 자동으로 생성될 수 있다.
  • Binding
    • PVC가 생성되면 Kubernetes는 요청된 스토리지 요구사항(용량, 접근 모드 등)에 맞는 PV를 선택하고, 해당 PVC와 바인딩된다.
  • 사용
    • PV가 PVC와 연결되면, 해당 PV는 파드에 마운트되어 실제로 사용된다. 사용 중인 PV는 상태가 Bound로 표시된다.
  • 삭제
    • 파드가 삭제되거나 PVC가 삭제되면, 해당 PV는 더 이상 사용되지 않으며, PV의 상태는 Released로 변경된다.
    • 이때, Reclaim Policy에 따라 PV가 처리되는 방식이 결정된다.

Reclaim Policy

Reclaim Policy는 PV가 더 이상 사용되지 않거나 삭제될 때 어떻게 처리할지를 정의한다. Kubernetes에서 제공하는 기본적인 Reclaim Policy는 세 가지로 나뉜다

  • Retain
    • PV가 삭제되어도 실제 스토리지(예: EBS 볼륨, NFS 볼륨)는 삭제되지 않고 그대로 유지된다.
    • 관리자가 수동으로 PV를 정리하거나 다시 사용할 수 있도록 한다.
    • 사용자가 Retain 정책을 선택하면, PV를 삭제하는 대신 수동으로 클린업 작업을 해야 한다.
  • Delete
    • PV가 더 이상 사용되지 않으면, 그에 해당하는 스토리지 자원도 자동으로 삭제된다.
    • 예를 들어, AWS EBS 볼륨이 있는 경우, 해당 볼륨이 자동으로 삭제된다.
  • Recycle (현재는 deprecated)
    • PV가 삭제되면, 자동으로 스토리지 내용이 삭제되고 다시 사용할 수 있도록 초기화된다.
    • 예전에 많이 사용됐지만, 현재는 Recycle 정책은 더 이상 권장되지 않으며, 대부분의 경우 Retain이나 Delete가 사용된다.

Reclaim Policy: Retain

apiVersion: v1
kind: PersistentVolume
metadata:
  name: ebs-pv
spec:
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain  # Reclaim Policy를 Retain으로 설정
  storageClassName: ebs-storage
  awsElasticBlockStore:
    volumeID: vol-0abcd1234efgh5678
    fsType: ext4
  • 위 예시에서 persistentVolumeReclaimPolicy: Retain으로 설정하면, PV가 삭제되더라도 EBS 볼륨은 그대로 남아 있게 된다. 관리자가 수동으로 해당 EBS 볼륨을 삭제하거나 다시 사용할 수 있다.

Reclaim Policy: Delete

apiVersion: v1
kind: PersistentVolume
metadata:
  name: ebs-pv-delete
spec:
  capacity:
    storage: 20Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: ebs-storage
  awsElasticBlockStore:
    volumeID: vol-0abcd1234efgh5678
    fsType: ext4
  • Delete 정책으로 설정된 PV는 PVC가 삭제될 때 PV와 EBS 볼륨이 모두 삭제된다. 

Reclaim Policy는 데이터의 지속성이나 관리 방식을 결정하는 중요한 요소다. 예를 들어, Delete 정책을 사용하면 자동으로 저장소 자원을 정리할 수 있지만, Retain 정책은 데이터를 보존하여 수동으로 관리하고 싶은 경우 유용하다.

  • Retain: 테스트 환경이나 중요한 데이터가 포함된 볼륨에서, 삭제 후 데이터를 보존하고 싶을 때.
  • Delete: 개발 환경처럼 데이터를 보존할 필요가 없는 경우, 사용 후 자동으로 정리되도록 설정.

이렇게 Reclaim Policy를 통해 PV가 삭제될 때의 처리를 세밀하게 제어할 수 있다.

동적 프로비저닝 (Dynamic Provisioning)

동적 프로비저닝은 쿠버네티스에서 PVC(PersistentVolumeClaim)가 요구하는 스토리지가 없을 때 자동으로 PV(PersistentVolume)와 외부 스토리지를 생성하는 기능이다. 이로 인해 사용자는 스토리지를 미리 만들 필요 없이 PVC를 통해 스토리지를 요청하면, 자동으로 외부 스토리지(EBS, GCP Persistent Disk 등)가 프로비저닝되고, 해당 스토리지가 PV로 바인딩돼서 PVC와 연결된다. 

기본 스토리지 클래스 (StorageClass)

스토리지 클래스는 PVC가 요청하는 스토리지를 정의하는 쿠버네티스 리소스이다. 동적 프로비저닝을 사용하려면 PVC에 storageClassName을 명시해서 스토리지 클래스를 참조해야 한다. 만약 명시하지 않으면 기본 스토리지 클래스가 사용된다. 기본 스토리지 클래스를 사용하려면 PVC에서 storageClassName: ""으로 설정하면 돼요.

동적 프로비저닝 예시

스토리지 클래스 정의 (예: SSD) 먼저, ssd라는 이름의 스토리지 클래스를 정의하여 SSD 스토리지를 생성하도록 설정할 수 있다. 

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ssd
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
reclaimPolicy: Delete  # 기본적으로 Delete로 설정됩니다.

PVC 정의(스토리지 클래스를 정의할때)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: ssd  # ssd 스토리지 클래스를 사용

이 PVC가 생성되면, Kubernetes는 ssd 스토리지 클래스를 참조하여 자동으로 gp2 타입의 EBS 볼륨을 생성하고, PVC와 바인딩한다. 

 

PVC 정의(기본 스토리지 클래스를 사용하는 경우)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: ""  # 기본 스토리지 클래스를 사용
  • 위 예시에서 storageClassName: ""을 설정하면 기본 스토리지 클래스를 사용하여 동적 프로비저닝을 수행한다. 

동적 프로비저닝 시 리클레임 정책

동적 프로비저닝으로 생성된 PV는 기본적으로 Delete 리클레임 정책을 사용한다. 그래서 PVC가 삭제되면 관련된 PV와 외부 스토리지(EBS 등)도 함께 삭제된다. AWS나 GCP 같은 클라우드 환경에서는 별도의 설정 없이 스토리지 클래스를 정의하고 PVC를 생성하면 자동으로 외부 스토리지가 프로비저닝된다. 

기본 스토리지 클래스를 설정하려면 is-default-class: "true"를 사용해서 기본 클래스를 지정할 수 있다. 

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: generic
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"  # 기본 스토리지 클래스로 설정
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2

이 설정을 통해 generic 스토리지 클래스가 기본값으로 설정되고, PVC에 storageClassName을 지정하지 않으면 자동으로 이 클래스가 사용된다. 

  • PV 라이프 사이클은 Available → Bound → Released로 진행되며, 리클레임 정책에 따라 데이터를 어떻게 처리할지 정의할 수 있다. 
  • Reclaim Policy는 Retain, Delete, Recycle로 설정할 수 있으며, 각 정책에 따라 PV와 데이터를 어떻게 처리할지를 결정한다.
  • 동적 프로비저닝을 사용하면 PVC가 생성될 때 적절한 외부 스토리지가 자동으로 생성되어, 수동으로 PV를 관리할 필요가 없다.