如何在k8s中部署nfs-client-provisioner实现nfs共享存储的动态PV创建?

发布时间 2023-08-23 15:17:07作者: Zhai_David

0、背景说明

 

正常的情况,如果使用nfs的网络共享存储,需要手动的创建pv,然后创建pvc和pv进行绑定。

 

最后在应用程序的pod中来挂载使用这个pvc,达到挂载外部共享存储的目的。

 

那么,要实现动态的PV的创建,该怎么做呢?

 

在今天的内容里面,介绍一个nfs-client-provisoner工具,通过它,就能够基于stroageclass,动态的创建PV,也就是,在创建pvc的时候,自动创建出来pv,无需手动的创建。

 

接下来的部分,介绍如何在k8s中部署nfs-client-provisioner工具

 

1、部署过程

 

1.1、环境依赖

 

在部署nfs-client-provisioner之前,需要先部署nfs服务。

 

因为,nfs-client-provisioner创建的pv都是要在nfs服务器中搭建的。

 

本示例中的nfs server的地址如下:

[root@nccztsjb-node-23 ~]# showmount -e 172.20.58.83
Export list for 172.20.58.83:
/data/nfs_data *
[root@nccztsjb-node-23 ~]#

 

 

1.2、下载nfs-client-provisoner镜像

 

通过下面的命令下载nfs-client-provisioner的镜像

 

docker pull quay.io/vbouchaud/nfs-client-provisioner:lates

 

 

下载好之后,上传到本地的镜像仓库中

docker tag quay.io/vbouchaud/nfs-client-provisioner:latest \
            172.20.58.152/kubernetes/nfs-client-provisioner:latest


docker push 172.20.58.152/kubernetes/nfs-client-provisioner:latest    

 

 

1.3、在集群的每个节点部署nfs工具

 

执行以下的命令,在每个节点部署nfs工具,后面pod启动,挂载nfs的存储会使用

yum install nfs-utils -y

 

1.4、 创建授权账户信息

 

通过以下yaml文件,创建需要的service account

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: ["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

 

将以上的文件内容,放在rbac.yaml文件中

 

这里面的对象,是放在默认的命名空间中的。

 

执行命令,进行创建操作

[root@nccztsjb-node-23 yamls]# kubectl apply -f rbac.yaml 
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
[root@nccztsjb-node-23 yamls]# 

 

 

 

1.5、部署nfs-client-provisioner服务

 

使用下面的yaml配置文件,部署nfs-client-provisioner应用

kind: Deployment
apiVersion: apps/v1
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs-client-provisioner
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: 172.20.58.152/kubernetes/nfs-client-provisioner:latest # 修改为本地镜像地址
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs  # provisioner的名字,可以修改
            - name: NFS_SERVER
              value: 172.20.58.83   # nfs服务器的地址
            - name: NFS_PATH
              value: /data/nfs_data  # nfs服务器共享地址
      volumes:
        - name: nfs-client-root
          nfs:
            server: 172.20.58.83   # nfs服务器的地址
            path: /data/nfs_data   # nfs服务器共享地址
 

 

将上面的内容,放在nfs_client_provisioner.yaml文件中

 

执行以下命令进行创建:

[root@nccztsjb-node-23 yamls]# kubectl apply -f nfs_client_provisioner.yaml 
deployment.apps/nfs-client-provisioner created

 

 

查看nfs-client pod的状态

[root@nccztsjb-node-23 yamls]# kubectl get pod | grep nfs
nfs-client-provisioner-68c48f6f9b-rkxhv   1/1     Running            0                 5s
[root@nccztsjb-node-23 yamls]# 

 

 

pod状态为Running,正常。

 

1.6、创建storageclass

 

动态存储的关联关系,都是通过stroageclass来完成的

 

通过下面的yaml文件,创建storageclass

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
  archiveOnDelete: "false" # When set to "false" your PVs will not be archived
                           # by the provisioner upon deletion of the PVC.

 

 

执行的过程

[root@nccztsjb-node-23 yamls]# kubectl apply -f nfs-storage-class.yaml 
storageclass.storage.k8s.io/managed-nfs-storage created
[root@nccztsjb-node-23 yamls]# kubectl get sc
NAME                  PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
managed-nfs-storage   fuseim.pri/ifs   Delete          Immediate           false                  3s
[root@nccztsjb-node-23 yamls]# 

 

 

1.7、创建pvc

 

storageclass创建好了之后,需要创建pvc,pvc回去申请nfs的存储

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
  annotations:
    volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Mi

  

 

创建测试pvc,发现已经动态的绑定了pv:pvc-bece47f2-2164-4bfe-bba3-df88e9c75250

这个pv并没有手动的进行创建

[root@nccztsjb-node-23 yamls]# kubectl apply -f nfs-pvc.yaml 
persistentvolumeclaim/test-claim created
[root@nccztsjb-node-23 yamls]# kubectl get pvc
NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
test-claim   Bound    pvc-bece47f2-2164-4bfe-bba3-df88e9c75250   1Mi        RWX            managed-nfs-storage   4s
[root@nccztsjb-node-23 yamls]# 

 

 

在nfs 服务器的目录里面,自动创建出来一个目录,就是这个pv的目录

[root@nccztsjb-node-23 nfs_data]# pwd
/data/nfs_data
[root@nccztsjb-node-23 nfs_data]# ls
default-test-claim-pvc-bece47f2-2164-4bfe-bba3-df88e9c75250
[root@nccztsjb-node-23 nfs_data]# 

 

 

1.8、创建pod使用pvc

 

pvc已经创建好了,创建测试pod,使用pvc

 

kind: Pod
apiVersion: v1
metadata:
  name: test-pod
spec:
  containers:
  - name: test-pod
    image: 172.20.58.152/middleware/busybox:1.36
    command:
      - "/bin/sh"
    args:
      - "-c"
      - "touch /mnt/SUCCESS && exit 0 || exit 1"
    volumeMounts:
      - name: nfs-pvc
        mountPath: "/mnt"
  restartPolicy: "Never"
  volumes:
    - name: nfs-pvc
      persistentVolumeClaim:
        claimName: test-claim

 

 

 

正常执行后,退出

[root@nccztsjb-node-23 ~]# kubectl get pod |grep test-pod
test-pod                                  0/1     Completed          0                   16s
[root@nccztsjb-node-23 ~]# 

 

 

进入nfs server的目录里,已经创建好了SUCCESS文件

[root@nccztsjb-node-23 data]# cd nfs_data/
[root@nccztsjb-node-23 nfs_data]# ls
default-test-claim-pvc-bece47f2-2164-4bfe-bba3-df88e9c75250
[root@nccztsjb-node-23 nfs_data]# cd default-test-claim-pvc-bece47f2-2164-4bfe-bba3-df88e9c75250/
[root@nccztsjb-node-23 default-test-claim-pvc-bece47f2-2164-4bfe-bba3-df88e9c75250]# ls
SUCCESS
[root@nccztsjb-node-23 default-test-claim-pvc-bece47f2-2164-4bfe-bba3-df88e9c75250]# 

 

 

OK,到这里nfs-client-provisioner工具部署成功。

 

部署完成nfs-client-provisioner之后,创建好pvc,就可以动态的创建nfs的pv了,不需要手动的进行创建。

 

2、工作原理简要说明

 

基本的工作原理就是,nfs-client-provisioner持续的监控api server,查看创建pvc的请求,如果发现请求的pvc的存储类stroageclass,存储类的提供者和自己的是一致的

 

就会根据创建的pvc,动态的在nfs中创建pv。

 

下面是chatGPT中,关于nfs-client-provisioner工作流程的描述:

 

  • 部署 nfs-client-provisioner: 首先,您需要在 Kubernetes 集群中部署 nfs-client-provisioner。您可以通过使用 Kubernetes 配置文件或 Helm Chart 进行部署。这将创建一个运行在集群中的容器,用于监听 PVC 的创建。
  • 创建 StorageClass: 您需要创建一个 StorageClass,其中定义了与 nfs-client-provisioner 通信所需的配置信息,如 NFS 服务器地址、共享路径等。
  • 创建 PersistentVolumeClaim(PVC): 当您在集群中创建一个 PVC 并引用了之前定义的 StorageClassnfs-client-provisioner 将监听 PVC 的创建。
  • nfs-client-provisioner 的处理: 一旦 PVC 创建,nfs-client-provisioner 会检测到 PVC 的存在。它会解析 PVC 中定义的存储需求和 StorageClass 的配置,然后使用这些信息来与 NFS 服务器交互。
  • 创建 PersistentVolume(PV):nfs-client-provisioner 会使用 PVC 请求中的信息,以及 StorageClass 的配置,通过 NFS 协议与 NFS 服务器进行通信,并在 NFS 服务器上创建一个目录以供存储。
  • 绑定 PV 和 PVC: 一旦 NFS 服务器上的目录创建成功,nfs-client-provisioner 将创建一个 PV,并将其与创建 PVC 绑定起来,从而使 PVC 获得一个可用的 PV。
  • PVC 使用: 现在,PVC 已经与一个动态创建的 PV 绑定。您可以在 Pod 中使用这个 PVC,使 Pod 能够挂载 NFS 存储并访问其中的数据。

通过这个流程,nfs-client-provisioner 实现了动态创建和管理基于 NFS 的 PV,减轻了管理员的工作负担,同时使开发人员能够更轻松地使用动态的存储资源。需要注意的是,确保您在 PVC 和 StorageClass 的定义中提供正确的配置信息,以确保 nfs-client-provisioner 能够与 NFS 服务器正确交互。