볼륨영구 볼륨에 이어서 영구 볼륨 클레임(PersistentVolumeClaim, PVC)에 대해서 다룬다. 각각에 대한 짧은 정리는 아래와 같다.

  • 볼륨(Volume): 호스트에 미리 준비된 사용 가능한 볼륨을 일컬음. 쿠버네티스에서 볼륨 리소스를 생성/삭제할 수 없다. 매니페스트에 볼륨을 지정하기만 할 수 있음.
  • 영구 볼륨(PersistentVolume, PV): 외부의 볼륨 시스템에 연계하여 사용하는 볼륨. 쿠버네티스에서 볼륨 리소스를 생성/삭제한다. 영구 볼륨을 생성하면 클러스터에 등록만 된다.
  • 영구 볼륨 클레임(PersistentVolumeClaim, PVC): 이미 생성된 영구 볼륨을 사용 요청하는 리소스. 파드에서 영구 볼륨을 사용하기 위해 이것을 사용한다.

 

영구 볼륨 클레임은 영구 볼륨을 요청하는 리소스이다. 영구 볼륨 클레임에서는 영구 볼륨에 대해 요구하는 용량, 레이블 등을 지정한다. 파드에서 해당 영구 볼륨 클레임을 사용하면, 스케쥴러는 현재 클러스터에 존재하는 영구 볼륨 중에서 PVC의 조건을 만족하는 가장 적절한 영구 볼륨을 할당해준다.

 

1. 영구 볼륨 클레임 설정

PVC 에는 아래와 같은 항목들을 설정할 수 있다.

항목 설명
AccessModes 읽기/쓰기 권한
- RWO(ReadWriteOnce): 한 노드만 읽고 쓰기
- RWX(ReadWriteMany): 여러 노드가 읽고 쓰기
- ROX(ReadOnlyMany): 여러 노드가 읽기만
Resources 요청할 스토리지 용량(e.g. 1Gi)
StorageClassName 사용할 스토리지 클래스
Selector(Labels) 특정 라벨이 붙은 PV 를 찾기

이 항목들은 모두 영구 볼륨에도 정의된 값이며, PVC에서 요청하는 값에 부합하는 영구 볼륨이 할당된다. 주의할 점은 용량의 경우 PVC 에서 지정한 값이 최소 용량이 된다는 것이다. 1Gi 를 요청하더라도 1Gi 이상의 가장 작은 PV 가 할당된다.

 

2. 영구 볼륨 클레임 생성

아래와 같은 매니페스트를 이용하여 PVC를 생성한다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sample-pvc-nfs
spec:
  selector:
    matchLabels:
      type: nfs
      speed: high
    matchExpressions:
      - key: env
        operator: In
        values:
          - practice
  resources:
    requests:
      storage: 300Mi
  accessModes:
    - ReadWriteOnce
  storageClassName: manual

 

PVC 를 생성하면 자동으로 적절한 영구 볼륨을 확보한다.

# PV 확인. 현재 STATUS: Available
$ kubectl get pv
NAME            CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
sample-pv-nfs   500Mi      RWO            Retain           Available           manual         <unset>                          4s

# PVC 생성
$ kubectl apply -f sample-pvc-nfs.yaml
persistentvolumeclaim/sample-pvc-nfs created

# PV 확인. STATUS: Bound 로 바뀜. default/sample-pvc-nfs 클레임이 할당됨.
$ kubectl get pv
NAME            CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                    STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
sample-pv-nfs   500Mi      RWO            Retain           Bound    default/sample-pvc-nfs   manual         <unset>                          19s

# PVC 확인. STATUS: Bound
$ kubectl get pvc
NAME             STATUS   VOLUME          CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
sample-pvc-nfs   Bound    sample-pv-nfs   500Mi      RWO            manual         <unset>                 10s

만약 조건을 만족하는 PV가 없다면 STATUS: Pending 으로 유지되며, PVC 를 describe 해보면 상세 내용을 확인할 수 있다.

 

3. 영구 볼륨 클레임 삭제

PV가 persistentVolumeReclaimPolicy: Retain 정책을 사용하고 있는 경우 PVC 가 삭제되면 바인딩 되었던 PV 는 Released 상태로 변경된다. Released 상태의 PV 는 다시 자동으로 PVC 에 할당될 수 없다.

# PVC 삭제
$ kubectl delete -f sample-pvc-nfs.yaml
persistentvolumeclaim "sample-pvc-nfs" deleted

# PV 확인. STATUS: Released
$ kubectl get pv
NAME            CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                    STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
sample-pv-nfs   500Mi      RWO            Retain           Released   default/sample-pvc-nfs   manual         <unset>                          5d15h

 

4. 파드에서 PVC 를 사용하여 PV 마운트

이제 파드 매니페스트에서 spec.volumes[].persistentVolumeClaim 항목으로 아래와 같이 미리 생성해둔 PVC 를 지정한다.

apiVersion: v1
kind: Pod
metadata:
  name: sample-pvc-pod-nfs
spec:
  containers:
    - name: nginx-container
      image: nginx:1.27
      ports:
        - containerPort: 80
          name: "http"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: nginx-pvc
  volumes:
    - name: nginx-pvc
      persistentVolumeClaim:
        claimName: sample-pvc-nfs

파드가 생성될 때 sample-pvc-nfs 라는 이름의 PVC 를 찾아 바인딩 된 PV 를 컨테이너의 "/usr/share/nginx/html" 경로로 마운트하게 된다.

이 샘플에서 sample-pvc-nfs PVC 가 바인딩한 PV 매니페스트는 아래와 같다. nfs 타입으로 master 노드의 "/srv/nfs/kubedata" 경로를 볼륨으로 사용했다.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: sample-pv-nfs
  labels: # 파드가 특정 PV를 찾을 수 있게 돕는 이름표
    type: nfs
    speed: high
    env: practice
spec:
  capacity:
    storage: 500Mi # 사용할 용량
  accessModes:
    - ReadWriteOnce
  storageClassName: manual # 수동으로 만든 PV임을 명시 (중요)
  nfs:
    server: 192.168.0.36 # 마스터 노드 IP 주소
    path: /srv/nfs/kubedata # 마스터 노드에서 만든 경로

 

이를 기반으로 실제 파드를 구동시켜보고, 파드 내 컨테이너 <-> master 노드 내 스토리지 간에 스토리지가 읽기/쓰기 공유되는지 아래 단계를 따라 확인해보자

# 파드 생성
$ kubectl apply -f sample-pvc-pod-nfs.yaml
pod/sample-pvc-pod-nfs created

# 파드가 Running 중임을 확인
$ kubectl get pods -o wide
NAME                 READY   STATUS    RESTARTS   AGE   IP            NODE       NOMINATED NODE   READINESS GATES
sample-pvc-pod-nfs   1/1     Running   0          94s   10.244.1.85   worker01   <none>           <none>

# 파드 내 컨테이너에 접속하여 볼륨 마운트 경로에 존재하는 파일이 없음 확인
$ kubectl exec -it sample-pvc-pod-nfs -- /bin/bash
root@sample-pvc-pod-nfs:/# ls /usr/share/nginx/html

# 다른 SSH 터미널 세션을 열고 master 노드의 스토리지 경로 진입
$ cd /srv/nfs/kubedata

# 샘플 파일 생성
$ cat <<EOF > index.html
<h1>Hello, PVC from storage</h1>
EOF

# 컨테이너 내에서 볼륨 마운트 경로 다시 확인
root@sample-pvc-pod-nfs:/# cat /usr/share/nginx/html/index.html
<h1>Hello, PVC from storage</h1>

# 컨테이너 내에서 파일 수정
cat <<EOF > /usr/share/nginx/html/index.html
<h1>Hello, PVC from container</h1>
EOF

# master 노드에서 스토리지 내 파일 다시 확인
$ cat index.html
<h1>Hello, PVC from container</h1>

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,