Kubernetes

Kubernetes 기초 - Storage(2)

사실 나도 모름 2024. 1. 20. 02:35
  1. Volumes
  2. Persistent Volumes(PV)               ←  오늘 볼 내용
  3. Projected Volumes
  4. Ephemeral Volumes
  5. Storage Classes

2. Persistent Volumes(PV)

https://kubernetes.io/docs/concepts/storage/persistent-volumes/

 

Persistent Volumes

This document describes persistent volumes in Kubernetes. Familiarity with volumes, StorageClasses and VolumeAttributesClasses is suggested. Introduction Managing storage is a distinct problem from managing compute instances. The PersistentVolume subsystem

kubernetes.io

 

 

Persistent Volumes은 이름과 같이 영구 볼륨이라고 불린다.

AWS서비스를 이용해본 사람이라면 EBS(Elastic Block Storage)와 동일한 개념이라고 생각하면 쉽게 이해가 될 것이다.

쿠버네티스에서는 PV를 생성하고 PVC(Persistent Volumes Claim)을 생성하여 PV의 연결점을 생성하여 컨테이너에 마운트하는 방식으로 동작한다.

이러한 PV는 볼륨 내부의 데이터가 파드가 종료되더라도 유지되는 특성을 가진다.

 

PV에서 사용되는 옵션들에 대해 먼저 보자.

 

PV 옵션

persistentVolumeReclaimPolicy

  • Retain : PV가 해제되어도 PV가 그대로 보존된다. 데이터를 영구적으로 보존해야하는 경우 사용되며 수동으로 PV를 재사용하려면 관리자가 해당 PV를 수동으로 삭제해야 한다.
  • Delete : PV가 해제되면 PV와 연결된 스토리지 자원(AWS EBS 등)가 삭제된다. 새로운 PVC가 해당 PV를 요청하면, 시스템은 새로운 스토리지를 할당하여 새 PV를 생성한다.
  • Recycle(Deprecated) : 더 이상 사용되지 않는다. 쿠버네티스 공식 문서에 의하면 동적 프로비저닝을 대신 사용하는 것을 권장한다. PV가 해제되면 PV 내 데이터는 모두 삭제되고 빈 PV 상태가 되는 것이다.

 

volumeBindingMode

  • Immediate : 즉시 바인딩이 활성화된다. PV가 생성되자마자 가장 빠른 PVC에 즉시 바인딩된다. 이 옵션을 사용하면 PV를 할당하는 데 더 높은 확률로 성공한다.
  • WaitForFirstConsumer : 첫 번째 PVC가 해당 PV를 사용할 때까지 기다린다. PV는 생성되어도 PVC와 즉시 바인딩되지 않습니다. 대신, 첫 번째 PVC가 해당 PV를 사용하려고 할 때까지 대기한다. 이 옵션은 PV를 미리 만들어 놓고, 나중에 필요한 PVC가 나타날 때까지 PV를 보존하는 데 사용된다.

 

accessMode

  • ReadWriteOnce : 하나의 노드에서 해당 볼륨이 읽기-쓰기로 마운트 될 수 있다. ReadWriteOnce 접근 모드에서도 파드가 동일 노드에서 구동되는 경우에는 복수의 파드에서 볼륨에 접근할 수 있다.
  • ReadOnlyMany : 볼륨이 다수의 노드에서 읽기 전용으로 마운트 될 수 있다.
  • ReadWriteMany : 볼륨이 다수의 노드에서 읽기-쓰기로 마운트 될 수 있다.
  • ReadWriteOncePod : 볼륨이 단일 파드에서 읽기-쓰기로 마운트될 수 있다. 전체 클러스터에서 단 하나의 파드만 해당 PVC를 읽거나 쓸 수 있어야하는 경우 ReadWriteOncePod 접근 모드를 사용한다. 이 기능은 CSI 볼륨과 쿠버네티스 버전 1.22+ 에서만 지원된다.

 

volumeMode

기본적으로 대부분의 PV는 Filesystem 모드로 설정되어 파일 시스템을 사용하며 특별한 경우에만 Block을 사용한다.

  • Filesystem : 볼륨을 파일 시스템으로 사용하도록 지정
  • Block : 볼륨을 파일 시스템으로 사용하도록 지정

 

mountOptions

PV 또는 PVC를 마운트할 때 파일 시스템에 대한 추가 설정을 할 수 있다.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv0003
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: slow
  mountOptions:
    - hard
    - nfsvers=4.1
  nfs:
    path: /tmp
    server: 172.17.0.2
참고 :
클러스터 내에서 퍼시스턴트볼륨을 사용하려면 볼륨 유형과 관련된 헬퍼(Helper) 프로그램이 필요할 수 있다. 이 예에서 퍼시스턴트볼륨은 NFS 유형이며 NFS 파일시스템 마운트를 지원하려면 헬퍼 프로그램인 /sbin/mount.nfs가 필요하다.

다음 명령을 입력하여 nfs를 설치한다.

apt-get update
apt-get install nfs-common

 

 

퍼시스턴트 볼륨의 유형

퍼시스턴트볼륨 유형은 플러그인으로 구현된다. 쿠버네티스는 현재 다음의 플러그인을 지원한다.

  • cephfs - CephFS 볼륨
  • csi - 컨테이너 스토리지 인터페이스 (CSI)
  • fc - Fibre Channel (FC) 스토리지
  • hostPath - HostPath 볼륨 (단일 노드 테스트 전용. 다중-노드 클러스터에서 작동하지 않음. 대신 로컬 볼륨 사용 고려)
  • iscsi - iSCSI (SCSI over IP) 스토리지
  • local - 노드에 마운트된 로컬 스토리지 디바이스
  • nfs - 네트워크 파일 시스템 (NFS) 스토리지
  • rbd - Rados Block Device (RBD) 볼륨

아래의 PersistentVolume 타입은 사용 중단되었다. 이 말인 즉슨, 지원은 여전히 제공되지만 추후 쿠버네티스 릴리스에서는 삭제될 예정이라는 것이다.

  • awsElasticBlockStore - AWS Elastic Block Store (EBS) (v1.17에서 사용 중단)
  • azureDisk - Azure Disk (v1.19에서 사용 중단)
  • azureFile - Azure File (v1.21에서 사용 중단)
  • cinder - Cinder (오픈스택 블록 스토리지) (v1.18에서 사용 중단)
  • flexVolume - FlexVolume (v1.23에서 사용 중단)
  • gcePersistentDisk - GCE Persistent Disk (v1.17에서 사용 중단)
  • portworxVolume - Portworx 볼륨 (v1.25에서 사용 중단)
  • vsphereVolume - vSphere VMDK 볼륨 (v1.19에서 사용 중단)

 

 


 

Storage Class

PV를 알기 전에 간단하게 StorageClass에 대해 설명하자면 PV를 동적으로 생성하여 바인딩하는 역할을 한다.

일반적으로 클라우드 환경에서 동적으로 프로비저닝하는 경우가 대부분이지만 온프레미스 환경에서도 스토리지 클래스를 생성하여 사용하는 경우도 있다.

 

온프레미스에서 사용하는 경우

> 이 경우 스토리지 클래스가 있음에도 PV는 따로 생성해야 한다.

Storage Class PV PVC
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer















apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  storageClassName: local-storage
  local:
    path: /path/to/local/disk
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node1
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: example-pvc
spec:
  storageClassName: local-storage
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi










 

 

AWS 클라우드에서 사용하는 경우

Storage Class PVC
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
provisioner: kubernetes.io/aws-ebs
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
reclaimPolicy: Retain
parameters:
  type: gp2
  fsType: ext4
  iopsPerGB: "10"
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: example-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast
  resources:
    requests:
      storage: 5Gi

 

 

 


 

Static

PV는 PVC와 StorageClass를 사용해서 동적으로 프로비저닝되도록 할 수 있지만 PV를 직접 생성하고 PVC에 volumeName 필드를 명시하면 해당 PVC를 통해 수동으로 파드에 바인드할 수 있다.

다만 이 방식으로 PV와 PVC를 생성하면 자동으로 기본 스토리지 클래스로 설정해서 생성하게 된다.

결국 모든 PV는 스토리지 클래스를 반드시 하나씩 가지는 것이다.

 

아래 yaml 파일은 수동으로 PVC를 구성하여 마운트하기 위한 방법으로 구조는 다음과 같다.

PV PVC
apiVersion: v1
kind: PersistentVolume
metadata:
  name: test-pv
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /mnt/data
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
  volumeName: test-pv    # 수동으로 설정하는 방법


 

 

파드 명세는 다음과 같다.

Pod
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - image: nginx:1.25
    name: nginx-container
    volumeMounts:
    - name: test-vol
      mountPath: /test-path
  volumes:
  - name: test-vol
    persistentVolumeClaim:
      claimName: test-pvc

 

파드 내부에 진입하여 해당 디렉토리에 test.txt 파일 생성
node2 호스트 VM의 파일시스템을 경로로 사용했기에 /mnt/data/ 경로에 test.txt가 존재한다.

 

 

파드 내부에 진입한 후 바인딩한 PV내부에 test.txt라는 이름의 파일을 생성했다.

이 PV는 영구 볼륨이기에 파드가 죽더라도 데이터가 보존된다.

 

위 예시에서는 수동으로 구성하였지만 보통 PV는 클라우드 환경에서 StorageClass를 사용하여 동적으로 프로비저닝되도록 한다.

AWS와 GCP, AZURE와 같은 클라우드 프로바이더를 통해 서비스를 운영하는 경우 StorageClass를 사용하여 AWS EBS, GCE Persistent Disk, Azure Disk와 같은 볼륨을 동적으로 프로비저닝할 수 있다.

하지만 클라우드를 쓰지 않는 온프레미스의 경우는 동적으로 프로비저닝하는 기능은 없으며 StorageClass를 생성하더라도 PV는 따로 생성해주어야 한다.

 

 

 


 

Dynamic

동적 프로비저닝되는 모습을 보여주려면 클라우드 서비스 내에서 쿠버네티스를 실행해야 하는데 현재 내의 실습 환경은 개인 VM에 쿠버네티스를 설치하여 사용하는 것이기에 화면을 캡쳐하여 보여줄 수는 없다.

그래도 코드의 설명을 통해 과정을 설명할 것이다.

서두에서 예시로 보았던 AWS 클라우드를 사용하는 사례를 보자.

Storage Class PVC
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
provisioner: kubernetes.io/aws-ebs
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
reclaimPolicy: Retain
parameters:
  type: gp2
  fsType: ext4
  iopsPerGB: "10"
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: example-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast
  resources:
    requests:
      storage: 5Gi

 

위 내용을 보면 PV는 없고 PVC와 StorageClass만 존재한다.

StorageClass를 확인하면 provisioner를 볼 수 있는데 이 필드를 통해 어떤 클라우드 프로바이더를 이용하는지 명시할 수 있다.

parameters에는 AWS EBS 볼륨을 생성하는데 필요한 상세 설정이 담겨있다.

 

PVC는 storageClassName을 통해 StorageClass의 이름을 명시하면 StorageClass의 parameters에서 명시한 설정대로 EBS 볼륨을 생성한다.

StorageClass와 PVC에는 모두 사용할 볼륨 리소스의 양을 기재할 수 있는데 둘 중 더 큰 값을 사용하여 볼륨을 생성한다.

 

 

 


 

 

원시 블럭 볼륨을 사용한 PV

원시 블럭 즉 순수 디스크를 직접 PV로 활용하겠다는 의미다.

PV PVC Pod
apiVersion: v1
kind: PersistentVolume
metadata:
  name: block-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  volumeMode: Block
  persistentVolumeReclaimPolicy: Retain
  fc:
    targetWWNs: ["50060e801049cfd1"]
    lun: 0
    readOnly: false


apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: block-pvc
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Block
  resources:
    requests:
      storage: 10Gi






apiVersion: v1
kind: Pod
metadata:
  name: pod-with-block-volume
spec:
  containers:
    - name: fc-container
      image: fedora:26
      command: ["/bin/sh", "-c"]
      args: [ "tail -f /dev/null" ]
      volumeDevices:
        - name: data
          devicePath: /dev/xvda
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: block-pvc

 

 

 


 

 

알아두면 좋은 내용

Finalizers

사용중인 스토리지 오브젝트를 보호목적으로 존재한다.

PV에 저장되는 데이터의 손실을 막기위해 PV는 다른 PVC를 통해 바인드되어있는 경우 삭제되지 않는다.

삭제를 하더라도 Terminating 상태에 머무르며 PVC가 없어질 때까지 기다린다.

상세 정보를 보면 Finalizers에 kubernetes.io/pv-protection라는 값이 있는데 이 값이 존재하는 한 PV는 삭제되지 않는다.

kubernetes.io/pv-protection

 

 

상세 내역에 test-pvc라는 PVC가 연결되어있는 것을 볼 수 있는데 이것이 제거되지 않는 요인이다.

PVC만 제거하면 PV는 바로 제거된다.

 

PVC에도 동일한 필드가 있다.

PVC의 경우는 컨테이너가 해당 볼륨을 사용중일 때는 지운다고 한들 지워지지 않는다.

파드가 제거되고 더이상 바인딩된 상태가 아닐 때 PVC는 완전히 제거된다.

kubernetes.io/pv-protection

 

 

 

데이터 소스를 사용하여 PV를 생성하는 내용과 네임스페이스 간 볼륨 데이터 소스를 사용하도록 설정할 수도 있다.

이 부분은 외부 구성 요소를 설치하여 사용하는 부분이므로 여기서는 다루지는 않을 것이다.

궁금하다면 공식 문서를 통해 직접 확인하길 바란다.

'Kubernetes' 카테고리의 다른 글

Kubernetes 기초 - Storage(4)  (0) 2024.01.22
Kubernetes 기초 - Storage(3)  (0) 2024.01.22
Kubernetes 기초 - Storage(1)  (0) 2024.01.12
Kubernetes 기초 - Scheduling(6)  (0) 2024.01.10
Kubernetes 기초 - Scheduling(5)  (0) 2024.01.09