k8s

Kubernetes에서 NAS 사용하기

marble25 2023. 3. 26. 21:04

쿠버네티스 환경에서 nas를 마운트해서 사용하고 싶었는데 방법이 어떤 것이 있을지 찾아보았다.

NFS

NFS(Network File System)

nfs는 네트워크에 파일을 저장하는 방식으로, 사용자가 원격 컴퓨터에 있는 파일 및 디렉토리에 액세스할 수 있게 한다. 주로 NAS에서 사용한다.

Kubernetes에서 NFS 사용하기

  1. pod에 직접 마운트

    마운트가 필요한 파드에 직접 값을 넣어주는 방법이 존재한다.

     volumes:
           - name: nas-cli-volume
             nfs:
               server: xxx.xxx.xxx.xxx
               path: <nas-mount-dir>

    그러나 추상화 측면에서 좋지 않아 보이고, 모든 pod마다 nfs 정보를 가지고 있는 것이 좋지 않아 보인다.

  2. nfs-pod-provisioner를 통해 pv 생성을 pvc 요청할 때마다 해줌

    (kubernetes) - nfs storage사용하기

    pvc를 요청 → nfs-pod-provisioner에서 pv를 dynamic하게 생성 → 마운트 완료 의 과정으로 진행된다.

    사용하는 입장에서는 pv를 선언할 필요 없이 pvc만 선언하면 provisioner에서 알아서 해주는 다이나믹 프로비저닝 방식이다.

    Provisioner

    rbac

     apiVersion: v1
     kind: ServiceAccount
     metadata:
       name: nfs-client-provisioner
       # replace with namespace where provisioner is deployed
       namespace: default
     ---
     kind: ClusterRole
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
       name: nfs-client-provisioner-runner
     rules:
       - apiGroups: [""]
         resources: ["nodes"]
         verbs: ["get", "list", "watch"]
       - apiGroups: [""]
         resources: ["persistentvolumes"]
         verbs: ["get", "list", "watch", "create", "delete"]
       - apiGroups: [""]
         resources: ["persistentvolumeclaims"]
         verbs: ["get", "list", "watch", "update"]
       - apiGroups: ["storage.k8s.io"]
         resources: ["storageclasses"]
         verbs: ["get", "list", "watch"]
       - apiGroups: [""]
         resources: ["events"]
         verbs: ["create", "update", "patch"]
     ---
     kind: ClusterRoleBinding
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
       name: run-nfs-client-provisioner
     subjects:
       - kind: ServiceAccount
         name: nfs-client-provisioner
         # replace with namespace where provisioner is deployed
         namespace: default
     roleRef:
       kind: ClusterRole
       name: nfs-client-provisioner-runner
       apiGroup: rbac.authorization.k8s.io
     ---
     kind: Role
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
       name: leader-locking-nfs-client-provisioner
       # replace with namespace where provisioner is deployed
       namespace: default
     rules:
       - apiGroups: [""]
         resources: ["endpoints"]
         verbs: ["get", "list", "watch", "create", "update", "patch"]
     ---
     kind: RoleBinding
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
       name: leader-locking-nfs-client-provisioner
       # replace with namespace where provisioner is deployed
       namespace: default
     subjects:
       - kind: ServiceAccount
         name: nfs-client-provisioner
         # replace with namespace where provisioner is deployed
         namespace: default
     roleRef:
       kind: Role
       name: leader-locking-nfs-client-provisioner
       apiGroup: rbac.authorization.k8s.io

    StorageClass

     apiVersion: storage.k8s.io/v1
     kind: StorageClass
     metadata:
       name: nfs-client
     provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME'
     parameters:
       archiveOnDelete: "false"

    Provisoner

     apiVersion: apps/v1
     kind: Deployment
     metadata:
       name: nfs-client-provisioner
       labels:
         app: nfs-client-provisioner
       # replace with namespace where provisioner is deployed
       namespace: default
     spec:
       replicas: 1
       strategy:
         type: Recreate
       selector:
         matchLabels:
           app: nfs-client-provisioner
       template:
         metadata:
           labels:
             app: nfs-client-provisioner
         spec:
           serviceAccountName: nfs-client-provisioner
           containers:
             - name: nfs-client-provisioner
               image: k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
               volumeMounts:
                 - name: nfs-client-root
                   mountPath: /persistentvolumes
               env:
                 - name: PROVISIONER_NAME
                   value: k8s-sigs.io/nfs-subdir-external-provisioner
                 - name: NFS_SERVER # do not change
                   value: xxx.xxx.xxx.xxx # Ip of the NFS SERVER
                 - name: NFS_PATH # do not change
                   value: <nfs-path>  # path to nfs directory setup
           volumes:
             - name: nfs-client-root
               nfs:
                 server: xxx.xxx.xxx.xxx
                 path: <nfs-path>

    실제 사용하기

    pvc

     apiVersion: v1
     kind: PersistentVolumeClaim
     metadata:
       name: task-pv-claim
     spec:
       storageClassName: nfs-client
       accessModes:
         - ReadWriteOnce
       resources:
         requests:
           storage: 20Gi

    pod

     apiVersion: v1
     kind: Pod
     metadata:
       name: task-pv-pod
     spec:
       volumes:
         - name: task-pv-storage
           persistentVolumeClaim:
             claimName: task-pv-claim
       containers:
         - name: task-pv-container
           image: nginx
           ports:
             - containerPort: 80
               name: "http-server"
           volumeMounts:
             - mountPath: "/usr/share/nginx/html"
               name: task-pv-storage

    동적 프로비저닝 방식이기 때문에 따로 pv를 관리하지 않아도 nfs-client-provisioner deployment에서 자동으로 pv를 생성해준다.

    Deployment에서 클러스터 레벨의 pv를 생성할 수 있는 이유는 nfs-client-provisioner 서비스 어카운트에 nfs-client-provisioner-runner 클러스터 롤과 leader-locking-nfs-client-provisioner 롤이 바인딩되어 kubernetes api를 자유롭게 호출할 수 있기 때문이다. Deployment 내에서 pv를 만들면서 mounting될 path도 host에 자연스럽게 만들어 준다.

    단점

    • NFS가 제한하는 total size보다 더 많은 양을 allocate할 수 있다.
    • Storage resize나 expansion를 지원하지 않는다.