2

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

 1 year ago
source link: https://www.cnblogs.com/renshengdezheli/p/16972814.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一.系统环境

服务器版本 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动态扩容报错》


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK