쿠버네티스 PVC NFS 연결 정리

쿠버네티스 NFS 연결에 세 가지로 사용한다.

PVC 연결

  • Direct
  • Dynamic PVC
  • Static PVC

각각의 장단점들을 살펴보자.

Direct

NFS 연결에 Deplyment, Statefulset 배포 YAML 에서 직접 NFS Host 네임과 Path 입력하여 NFS 연결로 사용할 수 있다.

이는 PV / PVC 구성 Yaml 필요가 없으므로 간편하게 바로 사용할 수 있다는 장점이 있다. 그렇지만 NFS 관련으로 변동 사항이 생긴 경우 배포되는 컨테이너 Pods 마다 일일이 직접 수정하며 Deplyment 재배포가 필요하다. 이로 인해 사람의 실수로 인한 배포 지연이 발생될 수 있다.

Dynamic PVC

NFS 볼륨을 Provisioning 상태로 취급하여 사용한다. 이는 Provisioning 라이프사이클 서비스가 필요하므로 전용 Pods를 사용한다.

StorageClass와 생성하여 서비스 PVC 정보 볼륨 권한과 용량을 지정하고 배포에서는 PVC의 claimname 입력만으로 NFS 볼륨을 동적으로 디렉토리를 연결할 수 있다.

이는 관리되는 서비스 컨테이너가 많을수록 관리하기가 수월하다.

단, NFS로 마운트되는 경로의 이름은 변경할 수 없지만 실제 사용에는 그렇제 많이 거슬리지는 않는다.

Static PVC

StorageClass, PV, PVC 모두 기입하여 정적 디렉토리 구성을 사용한다.

Dynamic PVC 에서 Provisioning 서비스 Pods 에서 NFS 관련 라이프사이클을 관리했다면, Static PVC는 쿠버네티스에서 직접 라이프사이클을 관리한다.

물리적인 PersistentVolume 물리 볼륨 정보 입력이 필요하므로 pv 작성이 요구된다.

다음으로 yaml 작성 방법에 대해 살펴보자.


NFS 연결 - Direct

참고로 본인은 Values 변수 yaml로 만들어 helm에서 렌더링 하는 방식으로 사용하고 있다.

사용되는 nfs 서버 정보는 아래로 사용하고 있다.

nfs 서버

  • server: 172.30.0.30
  • path: /project

values-direct-pvc.yaml

volumes:
  nfs:
    server: 172.30.0.20
    path: /project
  log:
    name: logs-volume
    mountPath: /logs

deployment.yaml

...
volumes:
- name: {{ .values.volumes.log.name }}
  nfs:
    server: {{ .values.volumes.nfs.server }}
    path: {{ .values.volumes.nfs.path }}
containers:
- name: {{ .Values.appName }}
  volumeMounts:
  - name: {{ .values.volumes.log.name }}
    mountPath: {{ .values.volumes.log.mountPath }}

서비스 작성이 끝났다면 helm template 사용해 yaml 렌더링 결과로 nfs 정보가 받아오는지 살펴본다.


NFS 연결 - Dynamic PVC

helm 으로부터 NFS Subdir 서비스를 설치하여 Provisioner를 올려야한다.

터미널 #

helm repo add nfs-subdir-external-provisioner \
https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/

helm repo update
helm install \
nfs-subdir-external-provisioner \
nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--set nfs.server=172.30.0.30 \
--set nfs.path=/project \
--set storageClass.name=nfs-client \
--set storageClass.defaultClass=true

kubectl get pods 입력하면 서비스 Provisioner 설치 유무를 확인할 수 있다.

helm에서 직접 storageClass를 지정했지만, 수동으로 만들어서 관리하고 싶다면 Povisioner와 연동하는 StorageClass를 작성할 수 있다.

PV 정보는 Provisioner 서비스 Pods가 직접 관리하므로 별도로 작성할 필요는 없다.

sc.yaml

cat << EOF > sc.yaml
allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs
parameters:
  archiveOnDelete: "True"
provisioner: cluster.local/nfs-subdir-external-provisioner
reclaimPolicy: Delete
volumeBindingMode: Immediate
EOF

kubectl apply -f sc.yaml

다음 PVC 구성

pvc.yaml

cat << EOF > pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: logs-nfs-pvc
  namespace: portal
spec:
  accessModes:
  - ReadWriteMany
  storageClassName: nfs-provisioner
  resources:
    requests:
      storage: 3Gi
EOF

kubectl apply -f pvc.yaml

필요한 NFS 구성은 모두 완료되었다. 구성한 nfs 사용하기 위해서는 서비스 Pods의 helm 정보를 구성해주자.

values-direct-pvc.yaml

volumes:
  log:
    name: logs-volume
    mountPath: /logs
    claimName: logs-nfs-pvc

deployment.yaml

...
volumes:
- name: {{ .values.volumes.log.name }}
  persistantVolumeClaim:
    claimName: {{ values.volumes.log.claimName }}
containers:
- name: {{ .Values.appName }}
  volumeMounts:
  - name: {{ .values.volumes.log.name }}
    mountPath: {{ .values.volumes.log.mountPath }}


NFS 연결 - Static

static 에서는 추가로 물리적인 NFS 주소와 경로로 Persistent Volume에서 입력이 필요하다.

pv.yaml

cat << EOF > pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 5Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain # pv 삭제되어도 데이터 유지
  nfs:
    server: 172.30.0.30
    path: /project/app1
EOF

kubectl apply -f pv.yaml

pv.yaml 에서 nfs.path 입력을 자세히 살펴보자. 배포되는 서비스 Pods 이름과는 동일한 필요가 없지만, 본인은 편의성 서비스 Pods와 동일하게 맞춰주고 있다.

pvc.yaml

cat << EOF > pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: logs-nfs-pvc
  namespace: portal
spec:
  accessModes:
  - ReadWriteMany
  storageClassName: ""
  volumeName: nfs-pv
  resources:
    requests:
      storage: 3Gi
EOF

kubectl apply -f pvc.yaml

이전과 마찬가지로 서비스 Pods의 helm 정보를 구성한다.

values-direct-pvc.yaml

volumes:
  log:
    name: logs-volume
    mountPath: /logs
    claimName: logs-nfs-pvc

deployment.yaml

...
volumes:
- name: {{ .values.volumes.log.name }}
  persistantVolumeClaim:
    claimName: {{ values.volumes.log.claimName }}
containers:
- name: {{ .Values.appName }}
  volumeMounts:
  - name: {{ .values.volumes.log.name }}
    mountPath: {{ .values.volumes.log.mountPath }}


NFS 연결 - rancher

sc.yaml

cat << EOF > sc.yaml
allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-static
parameters:
  archiveOnDelete: "false"
provisioner: rancher.io/local-path  
reclaimPolicy: Delete
volumeBindingMode: Immediate
EOF

kubectl apply -f sc.yaml

kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml

provisioner 는 rancher 연구소의 local-path를 사용하였다.
그리고 StorageClass 에서 기본 값 사용으로 true / false 지정하려면 아래와 같이 명령어로 변경할 수 있다.

# local-nfs 스토리지 클래스 default 제거
kubectl patch storageclass nfs-class \
  -p '{"metadata": {"annotations": {"storageclass.kubernetes.io/is-default-class":"true"}}}'

StorageClass 구성부터는 pv 생성마다 해당 nfs로 생성된다.