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

一.系统环境

服务器版本 docker软件版本 Kubernetes(k8s)集群版本 CPU架构
CentOS Linux release 7.4.1708 (Core) Docker version 20.10.12 v1.21.9 x86_64

Kubernetes集群架构:k8scloude1作为master节点,k8scloude2,k8scloude3作为worker节点

服务器 操作系统版本 CPU架构 进程 功能描述
k8scloude1/192.168.110.130 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico k8s master节点
k8scloude2/192.168.110.129 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s worker节点
k8scloude3/192.168.110.128 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s worker节点

二.前言

Kubernetes(k8s)数据卷volumes类型众多,本文介绍使用存储类StorageClass动态制备持久卷Persistent Volume,关于静态制备持久卷Persistent Volume,请查看博客《Kubernetes(k8s)存储管理之数据卷volumes(四):持久卷Persistent Volume》

使用数据卷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   <none>           <none> 

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:          <none> 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:   <none> 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:        <none> 

删除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   <none>           <none> pvcshare                                  1/1     Running   0          5s    10.244.251.195   k8scloude3   <none>           <none> 

进入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动态扩容报错》

发表评论

评论已关闭。

相关文章