본문 바로가기

Cloud

(kubernetes) - nfs storage사용하기

반응형

🍳머리말

nfs server와 client설정 후 nfs provisioner로 dynamic provisioning을 하는 설명글입니다. {}로 감싼 부분은 사용자 설정이 필요합니다.


📕 NFS

📔 NFS란

net상에서 다른 computer의 filesystem을 mount해서 공유하는 것입니다.


📕 NFS provisioner

📔 NFS provisioner란

nfs를 이용해 storage를 사용하는 pod를 배포하려면 k8s cluster상에서 nfs storage를 사용할 수 있도록 설정된 provisioner가 필요합니다. 이는 serviceaccount로써 k8s cluster상에 pv를 배포할 수 있도록 권한을 부여해 주는 역할을 수행합니다.


📕 환경

📔 server

 📑 KERNEL-VERSION

 4.18.0-240.el8.x86_64

📔 client

 📑 KERNEL-VERSION

 4.18.0-193.0.1.el8.x86_64

 📑 k8s VERSION

 v1.22.2

 📑 CONTAINER-RUNTIME

cri-o://1.22.3


📕 Prerequisite

📔 k8s cluster


📕 NFS server 구성

📔 NFS 설치

yum install -y nfs-utils

📔 server측에서 exports할 directory 설정

root경로에 nfs_test folder생성 후 하위에 a, b, c folder를 생성해줍니다.

cd /
mkdir /nfs_test
cd nfs_test
mkdir a
mkdir b
mkdir c
vi /etc/exports

📔 exports file 수정

vi /etc/exports

 

다음 정보를 입력 후 저장합니다.

/nfs_test *(rw,subtree_check,no_root_squash)

이는 다음과 같습니다.

/{export할 folder명} {허용할 client ip대역}(client에게 줄 권한)

client에게 줄 권한들은 여러가지가 있습니다.

rw: 읽기 쓰기 가능

ro: 읽기만 가능

sync: filesystem변경시 즉시 client동기화

no_root_squash: client와 server의 root 동일화

subtree_check: 공유 디렉토리는 서브디렉토리를 가질 수 있음

client가 특정 file 요청시 server는 subtree checking을 실행해 sub dir까지 탐색, client가 요청한 file의 위치 확인

 

📑 nfs server와 rpcbind실행

systemctl start nfs-server
systemctl start rpcbind

 

📔 export여부 확인

다음 명령어로 확인합니다.

exportfs -v

 

출력결과


📕 NFS client 구성

📔 NFS 설치

yum install -y nfs-utils

📔 mount해 사용할 folder생성

아래처럼 경로에 nfs_test folder를 생성해줍니다.

mkdir /root/install/nfs_test

📔 확인

server의 지정한 folder를 mount후 

다음 명령어로 확인해줍니다.

mount -t nfs {server의 ip}:{export한 folder명} {mount할 client folder경로}

 

제 경우는 다음과 같습니다.

mount -t nfs 172.22.6.6:/nfs_test /root/install/nfs_test

실행 후 해당 folder로 접속해 ls명령어로 확인하면 server의 nfs_test로 부터 mount된 folder들인 a,b,c가 있음을 확인할 수 있습니다.

📔 NFS provisioner 설치

이제 원격으로 file을 mount함을 확인했으니 본격적으로 k8s cluster에 nfs provisioner를 배포해 봅시다.

📑 service account 생성

kind: ServiceAccount
apiVersion: v1
metadata:
  name: nfs-pod-provisioner-sa
  
---
kind: ClusterRole # Role of kubernetes
apiVersion: rbac.authorization.k8s.io/v1 
metadata:
  name: nfs-provisioner-clusterRole
rules:
  - apiGroups: [""] # rules on persistentvolumes
    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: nfs-provisioner-rolebinding
subjects:
  - kind: ServiceAccount
    name: nfs-pod-provisioner-sa
    namespace: default
roleRef: # binding cluster role to service account
  kind: ClusterRole
  name: nfs-provisioner-clusterRole # name defined in clusterRole
  apiGroup: rbac.authorization.k8s.io
---

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

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-pod-provisioner-otherRoles
subjects:
  - kind: ServiceAccount
    name: nfs-pod-provisioner-sa # same as top of the file
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: Role
  name: nfs-pod-provisioner-otherRoles
  apiGroup: rbac.authorization.k8s.io

📑 deployment 생성

kind: Deployment
apiVersion: apps/v1
metadata:
  name: nfs-pod-provisioner
spec:
  selector:
    matchLabels:
      app: nfs-pod-provisioner
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-pod-provisioner
    spec:
      serviceAccountName: nfs-pod-provisioner-sa # name of service account
      containers:
        - name: nfs-pod-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-provisioner
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME # do not change
              value: nfs-home # SAME AS PROVISIONER NAME VALUE IN STORAGECLASS
            - name: NFS_SERVER # do not change
              value: {server의 IP} # Ip of the NFS SERVER
            - name: NFS_PATH # do not change
              value: {server의 nfs설정한 folder명}  # path to nfs directory setup
      volumes:
       - name: nfs-provisioner # same as volumemouts name
         nfs:
           server: {server의 IP}
           path: {server의 nfs설정한 folder명}

 

제 경우는 다음과 같이 설정했습니다.

kind: Deployment
apiVersion: apps/v1
metadata:
  name: nfs-pod-provisioner
spec:
  selector:
    matchLabels:
      app: nfs-pod-provisioner
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-pod-provisioner
    spec:
      serviceAccountName: nfs-pod-provisioner-sa # name of service account
      containers:
        - name: nfs-pod-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-provisioner
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME # do not change
              value: nfs-test # SAME AS PROVISIONER NAME VALUE IN STORAGECLASS
            - name: NFS_SERVER # do not change
              value: 172.22.6.6 # Ip of the NFS SERVER
            - name: NFS_PATH # do not change
              value: /nfs_test  # path to nfs directory setup
      volumes:
       - name: nfs-provisioner # same as volumemouts name
         nfs:
           server: 172.22.6.6
           path: /nfs_test

📑 storageclass생성

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storageclass
provisioner: nfs-test
parameters:
  archiveOnDelete: "false"

📑 pvc 생성

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: task-pv-claim
spec:
  storageClassName: nfs-storageclass
  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

📑 container접속, 확인

하기 명령어로 pod명을 확인해줍니다.

kubectl get pods

출력결과

다음 명령어로 container로 접속합니다.

kubectl exec -it task-pv-pod -- bash

pod생성시 mount했던 path인 /usr/share/nginx/html로 들어갑니다. 이 후 nfs server에 설정했던 a, b, c folder를 확인할 수 있습니다.


📕 기타

​기타 provisioner가 error logs를 남기기도 합니다.

https://github.com/kubernetes-retired/external-storage/issues/978

 

[nfs-client] Unable to start nfs-client-provisionner · Issue #978 · kubernetes-retired/external-storage

We have a local k8s cluster and want to use an external NFS server as a persistance storage. On every node of this cluster we are able to mount manually the NFS share with mount -t nfs 10.8.26.123:...

github.com