PV, PVC

Created
April 16, 2022
Created by
D
DaEun Kim
Tags
Kubernetes
Property

쿠버네티스는 워커 노드 중 하나를 선택해 파드를 할당하는데, 특정 노드에서만 데이터를 보관하고 있으면 다른 노드의 파드에서 해당 데이터에 의존하는 비즈니스를 수행할 수 없다.

따라서 퍼시스턴트 볼륨(Persistent Volume)을 사용한다. 퍼시스턴트 볼륨은 워커 노드들이 네트워크 상에서 스토리지를 마운트하여 영속적으로 데이터를 저장할 수 있는 볼륨이다. 따라서 어떤 노드의 파드에 장애가 생기더라도 다른 노드에서 네트워크를 통해 볼륨에 연결하여 특정 데이터에 의존적인 비즈니스를 수행할 수 있다.

NFS(Network File System), AWS EBS(Elastic Block Store), Ceph, GlusterFS 등을 퍼시스턴트 볼륨으로 사용할 수 있다.

NFS 를 네트워크 볼륨으로 사용하기

NFS는 다른 호스트에 있는 파일 시스템의 일부를 자신의 디렉토리인 것처럼 사용하게 해주고 여러 개의 클라이언트가 동시에 마운트할 수 있다.

NFS를 사용하려면 NFS 서버와 클라이언트가 필요하다. 클라이언트 노드에서는 따로 셋업할 것은 없고 NFS 서버만 있으면 된다. (해당 실습은 PV 사용해보기 위해서 최소한으로 필요한 NFS 셋업만 할 예정.)

아래 코드는 nfs 역할을 하는 파드를 1개 생성한다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-server
spec:
  selector:
    matchLabels:
      role: nfs-server
  template:
    metadata:
      labels:
        role: nfs-server
    spec:
      containers:
        - name: nfs-server
          image: gcr.io/google_containers/volume-nfs:0.8
          ports:
            - name: nfs
              containerPort: 2049
            - name: mountd
              containerPort: 20048
            - name: rpcbind
              containerPort: 111
          securityContext:
            privileged: true

위에서 만드는 nfs 를 다른 노드들에서 접근하기 위해 clusterIP 타입의 서비스를 생성한다.

apiVersion: v1
kind: Service
metadata:
  name: nfs-service
spec:
  ports:
    - name: nfs
      port: 2049
    - name: mountd
      port: 20048
    - name: rpcbind
      port: 111
  selector:
    role: nfs-server

그리고 nfs 의 디렉토리를 컨테이너 내부에 마운트하는 파드를 생성한다.

apiVersion: v1
kind: Pod
metadata:
  name: nfs-mount-pod
spec:
  volumes:
    - name: nfs-volume
      nfs:
        path: /
        server: ${NFS_SERVICE_IP}
  containers:
    - name: nfs-mount-container
      image: busybox
      args: ["tail", "-f", "/dev/null"]
      volumeMounts:
        - name: nfs-volume
          mountPath: /mnt  # NFS 서버의 / 디렉토리를 컨테이너 내부의 /mnt 디렉토리에 마운트시킨다.

NFS_SERVICE_IP 변수는 nfs-service 의 클러스터IP 와 동일하다. nfs-service의 클러스터IP 를 얻으려면 아래와 같이 서비스의 리소스 정보를 파싱해오면 된다.

$ $ ku get svc nfs-service -o jsonpath='{.spec.clusterIP}'
10.103.254.210

trouble shooting

nfs-mount-pod 가 ContainerCreating 상태에서 멈췄을 때

$ ku describe pods nfs-mount-pod
Events:
  Type     Reason       Age               From               Message
  ----     ------       ----              ----               -------
  Normal   Scheduled    70s               default-scheduler  Successfully assigned default/nfs-mount-pod to ip-10-220-6-77
  Warning  FailedMount  6s (x8 over 70s)  kubelet            MountVolume.SetUp failed for volume "nfs-volume" : mount failed: exit status 32
Mounting command: mount
Mounting arguments: -t nfs ${NFS_SERVICE_IP}:/ /var/lib/kubelet/pods/7887d473-5d6e-4c90-9bee-260c63d3e004/volumes/kubernetes.io~nfs/nfs-volume
Output: mount: /var/lib/kubelet/pods/7887d473-5d6e-4c90-9bee-260c63d3e004/volumes/kubernetes.io~nfs/nfs-volume: bad option; for several filesystems (e.g. nfs, cifs) you might need a /sbin/mount.<type> helper program.

PV(Persistent Volume), PVC(Persistent Volume Claim)

아래 코드의 문제점은 파드를 생성하려고 하면 항상 NFS 를 사용해야 한다는 것이다.

apiVersion: v1
kind: Pod
metadata:
  name: nfs-mount-pod
spec:
  volumes:
    - name: nfs-volume
      nfs:
        path: /
        server: ${NFS_SERVICE_IP}
  containers:
    - name: nfs-mount-container
      image: busybox
      args: ["tail", "-f", "/dev/null"]
      volumeMounts:
        - name: nfs-volume
          mountPath: /mnt  # NFS 서버의 / 디렉토리를 컨테이너 내부의 /mnt 디렉토리에 마운트시킨다.

PV, PVC는 파드를 생성하는 YAML이 파드에 마운트 하려고 하는 네트워크 볼륨이 NFS 인지, AWS EBS 인지 몰라도 볼륨을 사용할 수 있도록 볼륨을 추상화한다.

쿠버네티스 클러스터를 관리하는 어드민과 애플리케이션을 배포하려는 유저가 있다고 하자.

PV, PVC 를 통해 파드에 네트워크 볼륨이 마운트 되기까지 과정은 아래와 같다.

image

중요한 것은 사용자가 YAML 코드를 가지고 디플로이먼트를 만들 때 볼륨의 상세한 스펙을 정의하지 않아도 된다는 것이다.

YAML 파일에서는 ‘이 디플로이먼트는 볼륨을 마운트 할 수 있어야 한다' 는 의미의 PVC만 명시할 뿐이며, 실세로 마운트 되는 볼륨이 뭔지 몰라도 된다.

AWS EBS 를 PV로 사용하기

  1. 어드민 - AWS EBS 생성. (콘솔이나 aws-cli 사용) 제약사항은 여기 참고.
  1. 어드민 - 퍼시스턴트 볼륨 생성 (access mode 종류는 여기 참고.)
  2. EBS_VOLUME_ID 는 콘솔이나 cli 통해서 EBS를 생성할 때 받는 ID 와 동일하다.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: ebs-pv
spec:
  capacity:
    storage: 4Gi
  accessModes:
    # 하나의 노드에서 해당 볼륨이 읽기-쓰기로 마운트 될 수 있다.
    # ReadWriteOnce 접근 모드에서도 파드가 동일 노드에서 구동되는 경우에는 복수의 파드에서 볼륨에 접근할 수 있다.
    - ReadWriteOnce
  awsElasticBlockStore:
    fsType: ext4
    volumeID: ${EBS_VOLUME_ID}

PV가 생성된 것을 확인한다. (PV는 네임스페이스에 속하지 않는 클러스터 단위의 오브젝트.)

image
  1. 사용자 - PVC 생성