K8S持久化存储:NFS+StorageClass实现动态供给

快速创建NFS类型的StorageClass,实现动态供给

一、简介:K8S中的持久化存储

K8s 中又引入了 Persistent Volumes 概念,它可以将存储和计算分离,通过不同的组件来管理存储资源和计算资源,然后解耦 pod 和 Volume 之间生命周期的关联。这样,当把 pod 删除之后,它使用的PV仍然存在,还可以被新建的 pod 复用。

K8S中的持久化存储又分为静态供给(Static Volume Provisioning)和动态供给(Dynamic Volume Provisioning)两种方式

动态供给是什么意思呢?就是说现在集群管理员不预分配 PV,他写了一个模板文件,这个模板文件是用来表示创建某一类型存储(块存储,文件存储等)所需的一些参数,这些参数是用户不关心的,给存储本身实现有关的参数。用户只需要提交自身的存储需求,也就是PVC文件,并在 PVC 中指定使用的存储模板(StorageClass)。
K8s 集群中的管控组件,会结合 PVC 和 StorageClass 的信息动态,生成用户所需要的存储(PV),将 PVC 和 PV 进行绑定后,pod 就可以使用 PV 了。通过 StorageClass 配置生成存储所需要的存储模板,再结合用户的需求动态创建 PV 对象,做到按需分配,在没有增加用户使用难度的同时也解放了集群管理员的运维工作。
阿里云原生公开课:应用存储和持久化数据卷:核心知识

在这里插入图片描述
(图片来源:阿里云原生公开课:应用存储和持久化数据卷:核心知识)

环境:
Kubernetes 1.21.1

二、部署nfs-provisioner

NFS Provisioner 是一个自动配置卷程序,它使用现有的和已配置的 NFS 服务器来支持通过持久卷声明动态配置 Kubernetes 持久卷。

NFS subdir external provisioner is an automatic provisioner that use your existing and already configured NFS server to support dynamic provisioning of Kubernetes Persistent Volumes via Persistent Volume Claims. Persistent volumes are provisioned as n a m e s p a c e − {namespace}- namespace{pvcName}-${pvName}.

注意:k8s 1.21版本中创建pvc时nfs-provisioner会报错

E0903 08:00:24.858523 1 controller.go:1004] provision “default/test-claim” class “managed-nfs-storage”: unexpected error getting claim reference: selfLink was empty, can’t make reference

解决方法:
修改 /etc/kubernetes/manifests/kube-apiserver.yaml文件
增加 - --feature-gates=RemoveSelfLink=false

spec:
  containers:
  - command:
    - kube-apiserver
    - --feature-gates=RemoveSelfLink=false   # 增加这行
    - --advertise-address=172.24.0.5
    - --allow-privileged=true
    - --authorization-mode=Node,RBAC
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    ... 省略剩余部分 ...

由于是kubeadm部署的集群,修改kube-apiserver.yaml文件后,会自动重载

以下开始部署nfs-provisioner
注意:本次测试都部署在default namespace下,如果需要部署到其他的ns,需要修改yaml文件中namespace。
(1)创建ServiceAccount、ClusterRole、ClusterRoleBinding等,为nfs-client-provisioner授权

# rbac.yaml
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
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

(2)部署nfs-client-provisioner
nfs-client-provisioner 是一个 Kubernetes 的简易 NFS 的外部 provisioner,本身不提供 NFS,需要现有的 NFS 服务器提供存储。
注意:地址和目录要改成实际的NFS服务对应配置

# nfs-provisioner.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default  #与RBAC文件中的namespace保持一致
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs-client-provisioner
  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: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: gxf-nfs-storage  #provisioner名称,请确保该名称与 nfs-StorageClass.yaml文件中的provisioner名称保持一致
            - name: NFS_SERVER
              value: 10.24.X.X    #NFS Server IP地址
            - name: NFS_PATH  
              value: /home/nfs/1    #NFS挂载卷
      volumes:
        - name: nfs-client-root
          nfs:
            server: 10.24.X.X  #NFS Server IP地址
            path: /home/nfs/1     #NFS 挂载卷
# 部署
kubectl apply -f rbac.yaml 
kubectl apply -f nfs-provisioner.yaml 
kubectl get pod 
NAME                                     READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-888d748c6-7c8hh   1/1     Running   0          4m24s

nfs-provisioner 启动
在这里插入图片描述

三、创建StorageClass

StorageClass是对存储资源的抽象定义,对用户设置的PVC申请屏蔽后端存储的细节,减轻管理员手工管理PV的工作,由系统自动完成PV的创建和绑定,实现动态资源供给。
StorageClass的定义主要包括名称、后端存储的提供者(provisioner)和后端存储对应的参数。对于后端NFS存储来说,配置相对简单,只需要指定provisioner即可。

# nfs-StorageClass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: gxf-nfs-storage #这里的名称要和provisioner配置文件中的环境变量PROVISIONER_NAME保持一致
reclaimPolicy: Retain # 默认为delete
parameters:
  archiveOnDelete: "true" # false表示pv被删除时,在nfs下面对应的文件夹也会被删除,true正相反
  1. nfs-StorageClass.yaml中reclaimPolicy不写(或者为delete, 默认),archiveOnDelete: “false”,当pvc删除时,对应的pv也会被自动删除,而且nfs文件目录中的文件也同时被删除;
  2. 当nfs-StorageClass.yaml中reclaimPolicy: retain,archiveOnDelete: “true”,pvc删除后需要手工删除pv,nfs上文件不会被删除。
# 部署
kubectl apply -f nfs-StorageClass.yaml
kubectl get sc
NAME                  PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
managed-nfs-storage   gxf-nfs-storage         Retain          Immediate              false                  6s

四、实验

实验1:部署deployment

部署一个有2个副本的deployment,挂载共享目录

创建pvc

创建pvc,“storageClassName"为上面创建的"managed-nfs-storage”,即指定动态创建PV的模板文件的名字。

# test-pvclaim.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 100Mi
  storageClassName: managed-nfs-storage

使用动态供给方式,pv被自动创建,pvc与pv自动绑定

kubectl apply -f test-pvclaim.yaml
kubectl get pvc,pv
NAME                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
persistentvolumeclaim/test-claim   Bound    pvc-d743747b-3b68-4e35-b18f-560d42cc79ec   100Mi      RWX            managed-nfs-storage   49s

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS          REASON   AGE
persistentvolume/pvc-d743747b-3b68-4e35-b18f-560d42cc79ec   100Mi      RWX            Retain           Bound    default/test-claim   managed-nfs-storage            49s

在这里插入图片描述
在nfs目录下生成了文件夹(与pv对应,名称为{namespace}.{pvc name}.{pv name})
在这里插入图片描述

部署deployment

deployment中两个pod的将共享存储挂载到/mnt目录

# test-deploy.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deploy
  labels:
    app: test-deploy
  namespace: default  #与RBAC文件中的namespace保持一致
spec:
  replicas: 2
  selector:
    matchLabels:
      app: test-deploy
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: test-deploy
  template:
    metadata:
      labels:
        app: test-deploy
    spec:
      containers:
      - name: test-pod
        image: busybox:1.24
        command:
          - "/bin/sh"
        args:
          - "-c"
          # - "touch /mnt/SUCCESS3 && exit 0 || exit 1"   #创建一个SUCCESS文件后退出
          - touch /mnt/SUCCESS5; sleep 50000
        volumeMounts:
          - name: nfs-pvc
            mountPath: "/mnt"
            # subPath: test-pod-3 # 子路径 (这路基代表存储卷下面的test-pod子目录)  
      volumes:
        - name: nfs-pvc
          persistentVolumeClaim:
            claimName: test-claim  #与PVC名称保持一致
kubectl apply -f test-deploy.yaml 
kubectl get pod
NAME                                     READY   STATUS    RESTARTS   AGE
test-deploy-5d649d6566-q9kmr             1/1     Running   0          34m
test-deploy-5d649d6566-rm7bv             1/1     Running   0          34m

进入其中一个pod,在/mnt目录中创建一个文件,即将这个文件持久化到nfs共享目录中,再到另一个pod也能看到。

# 进入test-deploy-5d649d6566-q9kmr, 新建文件test.c
kubectl exec -it test-deploy-5d649d6566-q9kmr -- /bin/sh
/ # cd /mnt
cat > test.c << EOF
> 2021
> EOF
# 进入test-deploy-5d649d6566-rm7bv, 查看共享目录
kubectl exec -it test-deploy-5d649d6566-rm7bv -- /bin/sh
/ # cd /mnt
/mnt # ls
SUCCESS5  test.c
/mnt # cat test.c
2021

实验2:部署statefulset

# test-sts-1.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: test-sts
  labels:
    k8s-app: test-sts
spec:
  serviceName: test-sts-svc
  replicas: 3
  selector:
    matchLabels:
      k8s-app: test-sts
  template:
    metadata:
      labels:
        k8s-app: test-sts
    spec:
      containers:
        - image: busybox:1.24
          name: test-pod
          command:
            - "/bin/sh"
          args:
            - "-c"
            # - "touch /mnt/SUCCESS3 && exit 0 || exit 1"   #创建一个SUCCESS文件后退出
            - touch /mnt/SUCCESS5; sleep 50000
          imagePullPolicy: IfNotPresent
          volumeMounts:
            - name: nfs-pvc
              mountPath: "/mnt"
  volumeClaimTemplates:
  - metadata:
      name: nfs-pvc
    spec:
      accessModes: ["ReadWriteMany"]
      storageClassName: managed-nfs-storage
      resources:
        requests:
          storage: 20Mi
kubectl apply -f test-sts-1.yaml
kubectl get sts
NAME       READY   AGE
test-sts   3/3     4m46s

这里直接用volumeClaimTemplates,指定storageClass和需要的存储容量,无需事先创建pvc,k8s直接创建出对应的pvc和pv。由于是有状态应用,所以创建3个pvc和对应的pv。
在这里插入图片描述

参考:
k8s学习笔记之StorageClass+NFS
Ubuntu 下搭建 NFS 服务

猜你喜欢

转载自blog.csdn.net/gxf1027/article/details/120063398