Kubernetes(k8s)存储管理之数据卷volumes(五):动态制备-存储类StorageClass


目录
  • https://www.cnblogs.com/renshengdezheli/p/16972289.html。

    使用数据卷volumes的前提是已经有一套可以正常运行的Kubernetes集群,关于Kubernetes(k8s)集群的安装部署,可以查看博客《Centos7 安装部署Kubernetes(k8s)集群》

    三.静态制备和动态制备

    创建持久卷Persistent Volume有两种方法:静态制备和动态制备 。

    静态制备(集群管理员创建若干 PV 卷。这些卷对象带有真实存储的细节信息, 并且对集群用户可用。PV 卷对象存在于 Kubernetes API 中,可供用户消费使用),简言之就是需要先创建pv,然后才能创建PVC

    动态制备 (如果管理员所创建的所有静态 PV 卷都无法与用户的 PersistentVolumeClaim 匹配, 集群可以尝试为该 PVC 申领动态制备一个存储卷。 这一制备操作是基于 StorageClass 来实现的:PVC 申领必须请求某个 存储类, 同时集群管理员必须已经创建并配置了该类,这样动态制备卷的动作才会发生。 如果 PVC 申领指定存储类为 "",则相当于为自身禁止使用动态制备的卷)。

    为了基于存储类完成动态的存储制备,集群管理员需要在 API 服务器上启用 DefaultStorageClass 准入控制器。 举例而言,可以通过保证 DefaultStorageClass 出现在 API 服务器组件的 --enable-admission-plugins 标志值中实现这点;该标志的值可以是逗号分隔的有序列表。

    简言之就是我们可以使用存储类StorageClass实现动态制备,不需要提前创建PV,只要创建好存储类StorageClass,用户创建PVC之后,存储类StorageClass会自动创建一个PV和PVC进行绑定。

    四.存储类StorageClass

    4.1 存储类StorageClass概览

    StorageClass 为管理员提供了描述存储 "类" 的方法。 不同的类型可能会映射到不同的服务质量等级或备份策略,或是由集群管理员制定的任意策略。 Kubernetes 本身并不清楚各种类代表的什么。这个类的概念在其他存储系统中有时被称为 "配置文件"。

    4.2 StorageClass 资源

    每个 StorageClass 都包含 provisioner、parameters 和 reclaimPolicy 字段, 这些字段会在 StorageClass 需要动态制备 PersistentVolume 时会使用到。

    存储制备器provisioner:每个 StorageClass 都有一个制备器(Provisioner),用来决定使用哪个卷插件制备 PV。 该字段必须指定。

    回收策略reclaimPolicy:由 StorageClass 动态创建的 PersistentVolume 会在类的 reclaimPolicy 字段中指定回收策略,可以是 Delete 或者 Retain。如果 StorageClass 对象被创建时没有指定 reclaimPolicy,它将默认为 Delete。通过 StorageClass 手动创建并管理的 PersistentVolume 会使用它们被创建时指定的回收策略。

    允许卷扩展allowVolumeExpansion:PersistentVolume 可以配置为可扩展。将此功能设置为 true 时,允许用户通过编辑相应的 PVC 对象来调整卷大小。此功能仅可用于扩容卷,不能用于缩小卷。

    挂载选项mountOptions:由 StorageClass 动态创建的 PersistentVolume 将使用类中 mountOptions 字段指定的挂载选项。如果卷插件不支持挂载选项,却指定了挂载选项,则制备操作会失败。 挂载选项在 StorageClass 和 PV 上都不会做验证,如果其中一个挂载选项无效,那么这个 PV 挂载操作就会失败。

    卷绑定模式volumeBindingMode:volumeBindingMode 字段控制了卷绑定和动态制备应该发生在什么时候。

    • Immediate 模式:默认情况下,Immediate 模式表示一旦创建了 PersistentVolumeClaim 也就完成了卷绑定和动态制备。 对于由于拓扑限制而非集群所有节点可达的存储后端,PersistentVolume 会在不知道 Pod 调度要求的情况下绑定或者制备。
    • WaitForFirstConsumer 模式:集群管理员可以通过指定 WaitForFirstConsumer 模式来解决此问题。 该模式将延迟 PersistentVolume 的绑定和制备,直到使用该 PersistentVolumeClaim 的 Pod 被创建。 PersistentVolume 会根据 Pod 调度约束指定的拓扑来选择或制备。 这些包括但不限于资源需求、 节点筛选器、 Pod 亲和性和互斥性、 以及污点和容忍度。

    注意:如果你选择使用 WaitForFirstConsumer,请不要在 Pod 规约中使用 nodeName 来指定节点亲和性。 如果在这种情况下使用 nodeName,Pod 将会绕过调度程序,PVC 将停留在 pending 状态。相反,在这种情况下,你可以使用节点选择器nodeSelector指定主机名。

    参数parameters:Storage Classes 的参数描述了存储类的卷。取决于制备器,可以接受不同的参数。 例如,参数 type 的值 io1 和参数 iopsPerGB 特定于 EBS PV。 当参数被省略时,会使用默认值。一个 StorageClass 最多可以定义 512 个参数。这些参数对象的总长度不能超过 256 KiB, 包括参数的键和值。

    五.创建存储类StorageClass

    5.1 配置NFS服务端以及共享目录

    在一台机器上安装NFS服务端,k8s的两个worker安装NFS客户端。

    etcd1机器作为NFS的服务端,安装NFS。

    [root@etcd1 ~]# yum -y install nfs-utils
    
    [root@etcd1 ~]# rpm -qa | grep nfs
    libnfsidmap-0.25-19.el7.x86_64
    nfs-utils-1.3.0-0.68.el7.2.x86_64
    

    启动NFS

    #使nfs开机自启动并现在就启动
    [root@etcd1 ~]# systemctl enable nfs-server --now
    Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service.
    
    #查看nfs状态
    [root@etcd1 ~]# systemctl status nfs-server 
    ● nfs-server.service - NFS server and services
       Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled; vendor preset: disabled)
       Active: active (exited) since 二 2022-01-18 17:24:24 CST; 8s ago
      Process: 1469 ExecStartPost=/bin/sh -c if systemctl -q is-active gssproxy; then systemctl reload gssproxy ; fi (code=exited, status=0/SUCCESS)
      Process: 1453 ExecStart=/usr/sbin/rpc.nfsd $RPCNFSDARGS (code=exited, status=0/SUCCESS)
      Process: 1451 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS)
     Main PID: 1453 (code=exited, status=0/SUCCESS)
       CGroup: /system.slice/nfs-server.service
    
    1月 18 17:24:24 etcd1 systemd[1]: Starting NFS server and services...
    1月 18 17:24:24 etcd1 systemd[1]: Started NFS server and services.
    

    先在NFS服务端创建/dongtaijuandongying,并把目录/dongtaijuandongying共享出去

    #在NFS服务端创建共享目录/dongtaijuandongying
    [root@etcd1 ~]# mkdir /dongtaijuandongying
    
    [root@etcd1 ~]# vim /etc/exports
    
    #把/dongtaijuandongying目录共享出去
    [root@etcd1 ~]# cat /etc/exports
    /dongtaijuandongying *(rw,async,no_root_squash)
    
    [root@etcd1 ~]# exportfs -arv
    exporting *:/dongtaijuandongying
    

    5.2 配置NFS客户端

    在k8s集群的worker节点安装nfs的客户端

    [root@k8scloude3 ~]# yum -y install nfs-utils
    
     #安装nfs的客户端
    [root@k8scloude2 ~]# yum -y install nfs-utils
    

    查看etcd1(192.168.110.133)机器共享出来的目录是哪个?

    [root@k8scloude2 ~]# showmount -e 192.168.110.133
    Export list for 192.168.110.133:
    /dongtaijuandongying *
    

    5.3 配置StorageClass支持NFS

    NFS类型的StorageClass没有内部制备器provisioner,但可以使用外部制备器。 也有第三方存储供应商提供自己的外部制备器。Kubernetes 不包含内部 NFS 驱动。你需要使用外部驱动为 NFS 创建 StorageClass。

    由于k8s默认不支持nfs类型的StorageClass,需要修改参数然后自定义nfs StorageClass

    [root@k8scloude1 volume]# vim /etc/kubernetes/manifests/kube-apiserver.yaml 
    
    #添加参数如下
    [root@k8scloude1 volume]# cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep RemoveSelfLink
        - --feature-gates=RemoveSelfLink=false
    

    重启kubelet使配置生效

    [root@k8scloude1 volume]# systemctl restart kubelet
    
    [root@k8scloude1 volume]# systemctl status kubelet
    ● kubelet.service - kubelet: The Kubernetes Node Agent
       Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
      Drop-In: /usr/lib/systemd/system/kubelet.service.d
               └─10-kubeadm.conf
       Active: active (running) since 三 2022-01-19 18:11:09 CST; 6s ago
         Docs: https://kubernetes.io/docs/
     Main PID: 89887 (kubelet)
       Memory: 37.4M
       CGroup: /system.slice/kubelet.service
               ├─89887 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --network-plugin=cni --pod-in...
               └─90152 [find]
    

    下载git

    [root@k8scloude1 volume]# yum -y install git
    

    下载扩展存储卷yaml文件

    [root@k8scloude1 volume]# git clone https://github.com/kubernetes-incubator/external-storage.git
    
    [root@k8scloude1 volume]# ls
    external-storage  
    
    [root@k8scloude1 volume]# cd external-storage/nfs-client/
    
    [root@k8scloude1 nfs-client]# cd deploy/
    
    [root@k8scloude1 deploy]# ls
    class.yaml  deployment-arm.yaml  deployment.yaml  objects  rbac.yaml  test-claim.yaml  test-pod.yaml
    

    因为deployment.yaml文件里需要NFS制备器镜像:nfs-client-provisioner:latest镜像,可以提前下载下来镜像

    [root@k8scloude1 deploy]# cat deployment.yaml | grep image
              image: quay.io/external_storage/nfs-client-provisioner:latest
              
    #在master和worker上都下载好镜像
    [root@k8scloude1 deploy]# docker pull quay.io/external_storage/nfs-client-provisioner:latest
    
    [root@k8scloude2 ~]# docker pull quay.io/external_storage/nfs-client-provisioner:latest
    
    [root@k8scloude3 ~]# docker pull quay.io/external_storage/nfs-client-provisioner:latest  
    
    [root@k8scloude1 deploy]# docker images | grep nfs-client-provisioner
    quay.io/external_storage/nfs-client-provisioner                   latest     16d2f904b0d8   3 years ago     45.5MB
    

    安装NFS制备器

    [root@k8scloude1 deploy]# pwd
    /root/volume/external-storage/nfs-client/deploy
    
    #当前的namespace为:volume
    [root@k8scloude1 deploy]# kubens 
    default
    kube-node-lease
    kube-public
    kube-system
    ns1
    ns2
    pod
    volume
    
    [root@k8scloude1 deploy]# ls
    class.yaml  deployment-arm.yaml  deployment.yaml  objects  rbac.yaml  test-claim.yaml  test-pod.yaml
    
    #修改namespace
    [root@k8scloude1 deploy]# sed -i 's/namespace: default/namespace: volume/g' rbac.yaml
    
    [root@k8scloude1 deploy]# 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@k8scloude1 deploy]# grep image deployment.yaml 
              image: quay.io/external_storage/nfs-client-provisioner:latest
    
    [root@k8scloude1 deploy]# vim deployment.yaml 
    
    #修改NFS的服务器地址和共享目录,设置镜像下载策略为: imagePullPolicy: IfNotPresent:本地有镜像就不下载
    [root@k8scloude1 deploy]# cat deployment.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nfs-client-provisioner
      labels:
        app: nfs-client-provisioner
      # replace with namespace where provisioner is deployed,命名空间要修改
      namespace: volume
    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: quay.io/external_storage/nfs-client-provisioner:latest
              #镜像下载策略要修改
              imagePullPolicy: IfNotPresent
              volumeMounts:
                - name: nfs-client-root
                  mountPath: /persistentvolumes
              env:
                - name: PROVISIONER_NAME
                  value: fuseim.pri/ifs
                #NFS服务器地址
                - name: NFS_SERVER
                  value: 192.168.110.133
                #NFS共享目录
                - name: NFS_PATH
                  value: /dongtaijuandongying
          volumes:
            - name: nfs-client-root
              nfs:
                #NFS服务器地址
                server: 192.168.110.133
                #NFS共享目录
                path: /dongtaijuandongying
    
    
    [root@k8scloude1 deploy]# kubectl apply -f deployment.yaml 
    deployment.apps/nfs-client-provisioner created
    
    #可以看到nfs制备器nfs-client-provisioner-76c576954d-5x7t2
    [root@k8scloude1 deploy]# kubectl get pod -o wide
    NAME                                      READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
    nfs-client-provisioner-76c576954d-5x7t2   1/1     Running   0          17s   10.244.112.129   k8scloude2              
    

    5.4 创建StorageClass

    查看StorageClass

    [root@k8scloude1 deploy]# kubectl get sc
    No resources found
    

    配置StorageClass

    [root@k8scloude1 deploy]# vim class.yaml 
    
    #archiveOnDelete参数表示:If it exists and has a false value, delete the directory. if onDelete exists, archiveOnDelete will be ignored.
    [root@k8scloude1 deploy]# cat class.yaml 
    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"
    

    创建storageclass

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

    5.5 创建持久卷申领PersistentVolumeClaim(PVC)

    现在没有pv和PVC

    [root@k8scloude1 deploy]# kubectl get pv
    No resources found
    
    [root@k8scloude1 deploy]# kubectl get pvc
    No resources found in volume namespace.
    

    配置PVC

    [root@k8scloude1 deploy]# vim pvc1.yaml 
    
    #storageClassName要和刚才创建的storageClass一样
    [root@k8scloude1 deploy]# cat pvc1.yaml 
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: mypvc
    spec:
      accessModes:
        - ReadWriteOnce
      volumeMode: Filesystem
      resources:
        requests:
          storage: 1Gi
      storageClassName: managed-nfs-storage
    

    创建PVC

    [root@k8scloude1 deploy]# kubectl apply -f pvc1.yaml 
    persistentvolumeclaim/mypvc created
    
    [root@k8scloude1 deploy]# kubectl get pvc
    NAME    STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
    mypvc   Bound    pvc-4b73eeaa-1530-4599-b2c8-6057bb16658a   1Gi        RWO            managed-nfs-storage   6s
    

    创建PVC之后,pv也自动创建了

    [root@k8scloude1 deploy]# kubectl get pv
    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM          STORAGECLASS          REASON   AGE
    pvc-4b73eeaa-1530-4599-b2c8-6057bb16658a   1Gi        RWO            Delete           Bound    volume/mypvc   managed-nfs-storage            9s
    

    查看pv的详细信息

    [root@k8scloude1 deploy]# kubectl describe pv pvc-4b73eeaa-1530-4599-b2c8-6057bb16658a 
    Name:            pvc-4b73eeaa-1530-4599-b2c8-6057bb16658a
    Labels:          
    Annotations:     pv.kubernetes.io/provisioned-by: fuseim.pri/ifs
    Finalizers:      [kubernetes.io/pv-protection]
    StorageClass:    managed-nfs-storage
    Status:          Bound
    Claim:           volume/mypvc
    Reclaim Policy:  Delete
    Access Modes:    RWO
    VolumeMode:      Filesystem
    Capacity:        1Gi
    Node Affinity:   
    Message:         
    Source:
        Type:      NFS (an NFS mount that lasts the lifetime of a pod)
        Server:    192.168.110.133
        Path:      /dongtaijuandongying/volume-mypvc-pvc-4b73eeaa-1530-4599-b2c8-6057bb16658a
        ReadOnly:  false
    Events:        
    

    删除pvc,PV也自动删除

    [root@k8scloude1 deploy]# kubectl delete pvc mypvc 
    persistentvolumeclaim "mypvc" deleted
    
    [root@k8scloude1 deploy]# kubectl get pv
    No resources found
    
    [root@k8scloude1 deploy]# kubectl get pvc
    No resources found in volume namespace.
    

    重新创建PVC

    [root@k8scloude1 deploy]# kubectl apply -f pvc1.yaml 
    persistentvolumeclaim/mypvc created
    
    [root@k8scloude1 deploy]# kubectl get pvc
    NAME    STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
    mypvc   Bound    pvc-7d17891d-f95a-417f-abf4-06f9e84dc82e   1Gi        RWO            managed-nfs-storage   6s
    
    [root@k8scloude1 deploy]# kubectl get pv
    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM          STORAGECLASS          REASON   AGE
    pvc-7d17891d-f95a-417f-abf4-06f9e84dc82e   1Gi        RWO            Delete           Bound    volume/mypvc   managed-nfs-storage            9s
    

    六.把卷挂载到pod

    配置pod把PVC挂载到容器的/xx目录

    [root@k8scloude1 deploy]# vim pvcpod.yaml 
    
    [root@k8scloude1 deploy]# cat pvcpod.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      creationTimestamp: null
      labels:
        run: pvcshare
      name: pvcshare
    spec:
      #nodeName指定pod运行在k8scloude3节点
      nodeName: k8scloude3
      terminationGracePeriodSeconds: 0
      volumes:
      - name: v1
        #卷类型为PVC
        persistentVolumeClaim:
          claimName: mypvc
      containers:
      - image: nginx
        imagePullPolicy: IfNotPresent
        name: h1
        resources: {}
        volumeMounts:
        - name: v1
          mountPath: /xx
      dnsPolicy: ClusterFirst
      restartPolicy: Always
    status: {}
    

    创建pod

    [root@k8scloude1 deploy]# kubectl get pod
    NAME                                      READY   STATUS    RESTARTS   AGE
    nfs-client-provisioner-76c576954d-5x7t2   1/1     Running   0          15m
    
    [root@k8scloude1 deploy]# kubectl apply -f pvcpod.yaml 
    pod/pvcshare created
    
    [root@k8scloude1 deploy]# kubectl get pod -o wide
    NAME                                      READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
    nfs-client-provisioner-76c576954d-5x7t2   1/1     Running   0          15m   10.244.112.129   k8scloude2              
    pvcshare                                  1/1     Running   0          5s    10.244.251.195   k8scloude3              
    

    进入pod,创建文件

    [root@k8scloude1 deploy]# kubectl exec -it pvcshare -- bash
    root@pvcshare:/# ls /xx/
    
    root@pvcshare:/# touch /xx/{1..10}.txt
    
    root@pvcshare:/# ls /xx/
    1.txt  10.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt	9.txt
    
    root@pvcshare:/# exit
    exit
    

    NFS服务器对应目录下也有文件

    [root@etcd1 ~]# ls /dongtaijuandongying/volume-mypvc-pvc-7d17891d-f95a-417f-abf4-06f9e84dc82e/
    10.txt  1.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt  9.txt
    

    删除pod

    [root@k8scloude1 deploy]# kubectl get pods 
    NAME                                      READY   STATUS    RESTARTS   AGE
    nfs-client-provisioner-76c576954d-5x7t2   1/1     Running   0          17m
    pvcshare                                  1/1     Running   0          2m9s
    
    [root@k8scloude1 deploy]# kubectl delete -f pvcpod.yaml 
    pod "pvcshare" deleted
    
    [root@k8scloude1 deploy]# kubectl get pods 
    NAME                                      READY   STATUS    RESTARTS   AGE
    nfs-client-provisioner-76c576954d-5x7t2   1/1     Running   0          18m
    

    删除PVC

    [root@k8scloude1 deploy]# kubectl delete -f pvc1.yaml 
    persistentvolumeclaim "mypvc" deleted
    
    [root@k8scloude1 deploy]# kubectl get pv
    No resources found
    
    [root@k8scloude1 deploy]# kubectl get pvc
    No resources found in volume namespace.
    

    pvc被删除之后,NFS服务端文件也没了,是因为回收策略RECLAIM POLICY为Delete

    [root@etcd1 ~]# ls /dongtaijuandongying/volume-mypvc-pvc-7d17891d-f95a-417f-abf4-06f9e84dc82e/
    ls: 无法访问/dongtaijuandongying/volume-mypvc-pvc-7d17891d-f95a-417f-abf4-06f9e84dc82e/: 没有那个文件或目录
    

    当配置了存储类StorageClass,PVC可以进行动态扩容,关于PVC动态扩容请查看博客《troubleshoot:PVC动态扩容报错》。