티스토리 뷰

728x90
반응형

[Kubernetes - Storage] How to configure a dynamic storage provisioner for Kubernetes using a network file system on CentOS 8

참고

이 문서는 Network File System을 CentOS 8에 설치하여 NFS Server로 운영하면서 Kubernetes의 PVC (Perssistent Volume Claim) - StorageClass - NFS 로 연동되는 PV (Persistent Volume)를 자동으로 구성하는 방법을 정리한 것입니다.

CentOS 8에 설치되는 NFS를 Kubernetes의 Dynamic Storage Provisioning 으로 활용해서 PV (Persistent Volume)를 구성해 본다.

Network file system 구성

NFS 서버를 구성하는 부분은 CentOS 8에 NFS 설정 및 테스트 글을 참고해서 진행하도록 한다.

NFS 서버는 물리적인 머신으로 네트워크 상에 존재하면 되며, Network을 통해서 Kubernetes Cluster에서 NFS 서버로 접근할 수 있어야 한다.

위에서 구성한 NFS 서버를 사용할 수 있도록 처리하는 NFS Provisioner Pod가 Kubernetes Cluster에 PV를 배포할 수 있도록 하기 위해서는 필요한 권한 설정이 필요하다. 따라서 PV를 배포할 수 있도록 ClusterRole, ClusterRoleBinding, Role, RoleBinding 설정을 가지는 Service Account를 생성해 줘야 한다.

Service Account 생성

서비스 계정을 생성한다. (serviceaccount.yaml)

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-provisioner

아래의 명령을 사용해서 Kubernetes에 적용한다.

$ kubectl apply -f serviceaccount.yaml

ClusterRole 생성

Cluster를 위한 역할을 생성한다. (clusterrole.yaml)

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-provisioner-runner
rules:
  - 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: ["watch", "create", "update", "patch"]
  - apiGroups: [""]
    resources: ["services", "endpoints"]
    verbs: ["get"]
  - apiGroups: ["extensions"]
    resources: ["podsecuritypolicies"]
    resourceNames: ["nfs-provisioner"]
    verbs: ["use"]

아래의 명령을 사용해서 Kubernetes에 적용한다.

$ kubectl apply -f clusterrole.yaml

ClusterRoleBinding 생성

Cluster를 위한 역할 바인딩을 생성한다. (clusterbinding.yaml)

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-provisioner
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-provisioner-runner
  apiGroup: rbac.authorization.k8s.io

---

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: nfs-provisioner-otherRoles
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: nfs-provisioner-otherRoles
subjects:
  - kind: ServiceAccount
    name: nfs-provisioner
    namespace: default    # provisioner가 배포될 네임스페이스
roleRef:
  kind: Role
  name: nfs-provisioner-otherRoles
  apiGroup: rbac.authorization.k8s.io

아래의 명령을 사용해서 Kubernetes에 적용한다.

$ kubectl apply -f clusterbinding.yaml

NFS Client Provisioner 생성

Provisioner는 PVC와 StorageClass를 통해서 자동으로 PV를 구성해 주는 역할을 담당한다.

NFS 서버를 Dynamic Storage Provisioning으로 사용할 수 있도록 NFS Client Dynmaic Provisioner Pod를 배포하도록 구성한다. (deployment-nfs.yaml)

kind: Deployment
apiVersion: apps/v1
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccount: nfs-provisioner
      containers:
        - name: nfs-client-provisioner
          image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 10.0.1.20
            - name: NFS_PATH
              value: /data/NFS
      volumes:
        - name: nfs-client-root
          nfs:
            server: 10.0.1.20
            path: /data/NFS

아래의 명령을 사용해서 Kubernetes에 적용한다.

$ kubectl apply -f deployment-nfs.yaml

StorageClass 생성

NFS 연계를 위한 StorageClass를 생성한다. (storageclass-nfs.yaml)

apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name: managed-nfs-storage 
provisioner: fuseim.pri/ifs

아래의 명령을 사용해서 Kubernetes에 적용한다.

$ kubectl apply -f storageclass-nfs.yaml

Statefulset 생성 및 PV 검증

NFS 연계를 검증하기 위한 Statefulset을 생성하고 PV의 생성여부를 검증한다. (statefulset-nfs.yaml)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx1"
  replicas: 1
  selector:
    matchLabels:
      app: nginx1
  volumeClaimTemplates:
  - metadata:
      name: test 
      annotations:
        volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 2Gi 
  template:
    metadata:
     labels:
       app: nginx1
    spec:
     serviceAccount: nfs-provisioner
     containers:
     - name: nginx1
       image: nginx:1.7.9
       volumeMounts:
       - mountPath: "/mnt"
         name: test

아래의 명령을 사용해서 Kubernetes에 적용한다.

$ kubectl apply -f statefulset-nfs.yaml

Dynamic Provisioner Pod 실행 상태 확인

$ kubectl get all
NAME                                       READY   STATUS    RESTARTS   AGE
pod/nfs-pod-provisioner-5f8686f8dd-bfkgz   1/1     Running   0          8m51s

주의

만일 어느 정도의 시간이 지나도 STATUS가 ContainerCreating 또는 Pending 이라고 나오는 경우는 NFS 설정에 따라서 오류가 발생했을 수 있다.
kubectl describe <pod name>으로 확인해 보면 오류 상황을 알 수 있다.

  • connection timeout: NFS 서버의 IP에 접근이 안되는 경우이므로 실제 접근 가능한 IP인지 확인해야 한다. IP가 맞다면 NFS 서버에서 /etc/exports 설정을 다시 확인해 보고 sudo exportfs -ra를 수행하고 다시 처리한다.
  • access denied by server: NFS 서버에는 접근을 했지만 권한이 없는 경우이므로 NFS 서버에서 sudo chmod 666 <nfs directory>를 수행하고 다시 처리한다.
  • wrong fs type, bad option...: NFS 관련 패키지가 설치되지 않았을 경우이므로 클러스터의 각 노드에 sudo dnf install -y nfs-utils를 수행하고 다시 처리한다.

그 이외의 오류가 발생했다면 관련된 메시지를 통해서 원인을 파악하고 해결해야 한다.

PVC (Persistent Volume Claim)를 통한 PV 생성 검증

StorageClass를 이용해서 간단한 테스트를 위한 PVC를 구성한다. (fns-pvc.yaml)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc-test
spec:
  storageClassName: managed-nfs-storage # StorageClass 명
  accessModes:
    - ReadWriteMany # 생성될 PV에 적용할 사용 모드
  resources:
    requests:
      storage: 10Mi  # 생성될 PV 크기

참고

사용할 수 있는 AccessMode는 다음과 같다.

  • ReadWriteOnce (RWO): 하나의 Pod에만 마운트되고 하나의 Pod에서만 읽고 쓰기 가능
  • ReadWriteMany (RWX): 여러 개의 Pod에 마운트 가능하고 여러 개의 Pod에서 읽고 쓰기 가능
  • ReadOnlyMany (ROX): 여러 개의 Pod에 마운트 가능하고 여러 개의 Pod에서 읽기는 가능하지만 쓰기는 불가능

테스트이므로 작은 크기로 설정하고 Kubernete에 적용하고 확인한다.

$ kubectl apply -f nfs-pvc.yaml
persistentvolumeclaim/nfs-pvc-test created

$ kubectl get pv,pvc
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                  STORAGECLASS         REASON   AGE
persistentvolume/pvc-2dca7757-d8c1-4e80-8a21-f1d661d69b19   10Mi       RWX            Delete           Bound    default/nfs-pvc-test   managed-nfs-storage            7s

NAME                                  STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS         AGE
persistentvolumeclaim/nfs-pvc-test    Bound     pvc-2dca7757-d8c1-4e80-8a21-f1d661d69b19   10Mi       RWX            managed-nfs-storage   7s

NFS 서버에서 실제 생성된 정보 확인

PVC를 통해서 생성된 PV를 확인했으므로 실제 NFS 서버에도 생성이 되었는지 확인해 보면 된다.

# NFS 서버에서 공유 디렉터리 확인
$ sudo ls /data/NFS
default-nfs-pvc-test-pvc-2dca7757-d8c1-4e80-8a21-f1d661d69b19

실제 PVC와 PV 관련된 이름으로 유추할 수 있는 디렉터리가 생성된 것을 확인할 수 있다.

Deploy된 Pod의 Volume Mount 확인

실제 사용할 애플리케이션 Pod에서도 정상적으로 동작하는지를 확인하기 위해서 간단한 샘플을 구성해 보도록 한다. (nfs-test-app.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ccambo-nfs-test
  labels:
    app: nginxnfs
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginxnfs
  template:
    metadata:
      labels:
        app: nginxnfs
    spec:
      containers:
      - name: nginxnfs
        image: nginx:latest
        ports:
        - containerPort: 80
        volumeMounts:                    
          - mountPath: /nfs
            name: nfsvolume          
      volumes:                           
      - name: nfsvolume
        persistentVolumeClaim:           
          claimName: nfs-pvc-test

위의 YAML을 Kubernetes에 적용하고 확인한다.

$ kubectl apply -f nfs-test-app.yaml
deployment.apps/ccambo-nfs-test created

# Deployment 확인
$ kubectl get deploy
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
ccambo-nfs-test           0/1   1            0           15s
nfs-client-provisioner    1/1   1            1           75m

# Pod 확인
$ kubectl get pods
NAME                                     READY   STATUS    RESTARTS   AGE
ccambo-nfs-test-9d7fc4c6c-25xr4            1/1   Running   0          39s
ccambo-nfs-test-9d7fc4c6c-js5pl            1/1   Running   0          39s
nfs-client-provisioner-775496b5bb-vpglp    1/1   Running   0          82m

생성된 두 개의 Pod 중에 하나의 Pod에 접속해서 마운트된 경로에서 테스트용 파일을 생성한다.

$ kubectl exec -it ccambo-nfs-test-9d7fc4c6c-25xr4 -- /bin/bash

# 연결된 Pod에서 마운트된 /nfs 디렉터리로 이동해서 테스트용 파일을 하나 생성한다.
> cd /nfs
> echo "This is NFS test" > /nfs/test.log
> cat /nfs/test.log
This is NFS test

다른 Pod에 연결해서 마운트된 /nfs 디렉터리에 파일이 존재하는지 확인한다.

$ kubectl exec -it ccambo-nfs-test-9d7fc4c6c-js5pl -- /bin/bash

# 연결된 Pod에서 마운트된 /nfs 디렉터리로 이동해서 테스트용 파일을 확인한다.
> ls /nfs
test.log

> cat /nfs/test.log
This is NFS test

위의 테스트와 같이 생성된 POD가 동일한 NFS를 PV로 마운트해서 사용하고 있는 것을 확인할 수 있다.

728x90
반응형
댓글
댓글쓰기 폼