持久存储卷

在介绍网络存储卷的时候已经提到,Kubernetes支持为数众多的云提供商和网络存储方案,如NFS/iSCSI/GlusterFS/RDB/azureDisk/flocker等。但因为网络存储卷通常是集成各种第三方的存储系统,所以在配置上各有差别。

由于方案众多,配置有异,因此在存储参数的配置方面,可能只有对应的存储管理人员才能了解,而且这些都不应该是开发人员或集 群管理员需要关注的。

Kubernetes提供了3种基于存储的抽象对象——PersistentVolume(PV)、StorageClass和PersistentVolumeClaim(PVC),以支持基础设施和应用之间的分离。

这样开发人员、存储管理人员能各司其职,由存储管理人员设置PV或StorageClass,并在里面配置存储系统和参数,然后开发人员只 需要创建PVC来申请指定空间的资源以存储与共享数据即可,无须再关注存储的具体实现和操作,如图7-13所示。当删除PVC时,它写入具体存储资源中的数据可以根据回收策略自动清理。

PVC与PV的管理

image0

1. PV与PVC

PV表示持久存储卷,定义了Kubernetes集群中可用的存储资源,其中包含存储资源实现的细节,如包含如何使用 NFS/iSCSI/GlusterFS/RDB/azureDisk/flocker 等资源的具体设置。

·

PVC表示持久存储卷的申请,是由用户发起的对存储资源的请求。申请中只包含请求资源的大小和读写访问模式,无须关注具体的资源 实现细节,Kubernetes会自动为其绑定符合条件的PV。

1.1 PV与PVC的基本操作

examplefornfspv.yml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: examplefornfspv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: examplenfs
  nfs:
    path: /nfstest
    server: 192.168.1.60

该模板的主要含义如下。

  • kind表示要创建的资源对象,这里使用关键字PersistentVolume。

  • spec表示该资源对象的具体设置。

  • capacity:表示PV的容量,通过storage子属性可以指定占用的具体存储资源(如NFS)的大小,在本例中设定为1Gi

  • accessModes:定义 PV 对具体存储资源(如 NFS)的访问模式。一共有 3种访问模式,分别为ReadWriteOnce(该卷可以被单个节点以读写模式挂载),ReadOnlyMany(该卷可以被多个节点以只读模式挂载),ReadWriteMany(该卷可以被多个节点以读写模式挂载)。

  • 在本例中使用ReadWriteMany。persistentVolumeReclaimPolicy:表示当删除PVC 时,PV资源的回收策略。一共有3种策略,分别为Retain(保留)、Recycle(自动回收)Delete(自动删除)。当前只有NFS和hostPath支持Recycle策略,AWSEBS、GCE PD、Azure Disk和Cinder卷支持Delete策略。在 本例中使用Recycle。storageClassName:表示PV资源的描述性分类名称,例如,可以使用“ssd”“slowdisk”等具备分类的描述性名称。后续在创建PVC时可以引用这个名称来绑定PV。

  • nfs:表示该PV使用NFS服务器作为具体的存储资源,server和path属性为之前网络存储卷示例中配置的NFS服务 器及共享目录。

接下来,执行以下命令,创建PV。

$ kubectl apply -f examplefornfspv.yml

PV创建完成后,可以通过以下命令查询PV资源。

$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                                                   STORAGECLASS          REASON   AGE
examplefornfspv                            1Gi        RWX            Recycle          Available

查询结果如上所示。PV已成功创建,其STATUS属性为Available,这表示资源空闲,尚未被PVC申请使用。

接下来,使用以下命令,可以查询PV资源的详情。

$ kubectl describe pv {PV名称}

在本例中,命令为$ kubectl describe pvexamplefornfspv。执行结果如图7-15所示,在Source处可以看到具体的资源配置信息。

$ kubectl describe pv examplefornfspv
Name:            examplefornfspv
Labels:          <none>
Annotations:     <none>
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:    examplenfs
Status:          Available
Claim:
Reclaim Policy:  Recycle
Access Modes:    RWX
VolumeMode:      Filesystem
Capacity:        1Gi
Node Affinity:   <none>
Message:
Source:
    Type:      NFS (an NFS mount that lasts the lifetime of a pod)
    Server:    192.168.1.60
    Path:      /nfstest
    ReadOnly:  false
Events:        <none>

PV定义完成后就可以创建PVC以申请使用存储卷资源。

接下来,创建examplefornfspvc.yml文件。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: examplefornfspvc
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: "examplenfs"
  resources:
    requests:
      storage: 500Mi

该模板的主要含义如下。

  • kind表示要创建的资源对象,这里使用关键字PersistentVolumeClaim。

  • spec表示该资源对象的具体设置。accessModes:定义对PV的访问模式。Kubernetes会给PVC绑定满足此访问模式的PV。在本例中使用ReadWriteMany,与之前定义的PV保持一致。

  • storageClassName:表示要引用的PV资源的描述性分类名称。Kubernetes会根据这个名称将PVC绑定到符合条件的 PV。在本例中使用examplenfs,这与之前定义的PV保持一致。

  • resources:定义PVC的资源参数。requests属性会设置具体资源需求,Kubernetes会给PVC绑定满足资源大小的PV。 本例中设置为“storage: 500Mi”,这表示申请500MiB(1MiB=2 20 B,1MB=10 6 B)的资源大小。之前我们创建 的PV为1GiB(1GiB=2 30 B,1GB=10 9 B),足够容纳该资源请求。

接下来,执行以下命令,创建PVC。

$ kubectl apply -f examplefornfspvc.yml

PVC创建完成后,可以通过以下命令查询PVC资源。

$ kubectl get pvc
NAME               STATUS   VOLUME            CAPACITY   ACCESS MODES   STORAGECLASS   AGE
examplefornfspvc   Bound    examplefornfspv   1Gi        RWX            examplenfs     0s

查询结果如上面所示。PVC已成功创建,其STATUS属性为Bound,表示已成功绑定到符合PVC资源申请条件的PV上;

VOLUME属性显示了绑定的PV的名称,这正是我们之前创建的examplefornfspv。

此时如果再通过$ kubectl get pv命令查看已创建的PV,可以发现其STATUS属性由之前的Available变为Bound,CLAIM属性由 空值变为刚才创建的PVC。

$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                                                   STORAGECLASS          REASON   AGE
examplefornfspv                            1Gi        RWX            Recycle          Bound      default/examplefornfspvc

使用以下命令,可以查询PVC资源的详情。

$ kubectl describe pvc examplefornfspvc
Name:          examplefornfspvc
Namespace:     default
StorageClass:  examplenfs
Status:        Bound
Volume:        examplefornfspv
Labels:        <none>
Annotations:   pv.kubernetes.io/bind-completed: yes
               pv.kubernetes.io/bound-by-controller: yes
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      1Gi
Access Modes:  RWX
VolumeMode:    Filesystem
Used By:       <none>
Events:        <none>

PVC创建完成后,为了定义Pod并使用PVC引用的资源,首先,创建exampledeployforpvc.yml文件。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: exampledeployforpvc
spec:
  replicas: 2
  selector:
    matchLabels:
      example: exampleforpvc
  template:
    metadata:
      labels:
        example: exampleforpvc
    spec:
      containers:
      - name: containerforpvc
        image: busybox
        imagePullPolicy: IfNotPresent
        command: ['sh', '-c']
        args: ['echo "The host is $(hostname)" >> /dir/dataforpvc; sleep 3600']
        volumeMounts:
        - name: pvcdata
          mountPath: /dir
      volumes:
      - name: pvcdata
        persistentVolumeClaim:
          claimName: examplefornfspvc

本例中创建的存储卷名称为pvcdata,这个名称会被容器设置中的volumeMounts所引用。存储卷的类型是persistentVolumeClaim(即使用PVC),claimName属性表示引用的PVC名称,本例中为examplefornfspvc。

接下来,执行以下命令,创建Deployment控制器。

$ kubectl apply -f exampledeployforpvc.yml

创建后可以通过$ kubectl get deploy命令查看启动状态

$ kubectl get deployment
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
exampledeployforpvc   2/2     2            2           29s

接下来,执行$ kubectl get pod -o wide命令,可以看到Deployment控制器一共创建了两个Pod,分别位于不同 的机器上。

在本例中,PVC所绑定的PV引用中NFS服务器的共享目录为/data/nfs/nfstest。在NFS服务器上执行cat /data/nfs/nfstest/data,可输出NFS共享目录下的文件内容。

$ cat /data/nfs/nfstest/dataforpvc
The host is exampledeployforpvc-697cbdb4d9-qjg8h
The host is exampledeployforpvc-697cbdb4d9-zvkk4

任意抽取一个Pod(在本例中为exampledeployforpvc-697cbdb4d9-qjg8h),通过以下命令进入Pod内部的命令界面。

$ kubectl exec -it pod/exampledeployforpvc-697cbdb4d9-qjg8h -- /bin/sh
/ # cat /dir/dataforpvc
The host is exampledeployforpvc-697cbdb4d9-qjg8h
The host is exampledeployforpvc-697cbdb4d9-zvkk4
/ # echo "hujianli20220417!" >> /dir/dataforpvc
/ # cat /dir/dataforpvc
The host is exampledeployforpvc-697cbdb4d9-qjg8h
The host is exampledeployforpvc-697cbdb4d9-zvkk4
hujianli20220417!

回到nfs服务器目录查看数据的一致性

$ cat /data/nfs/nfstest/dataforpvc
The host is exampledeployforpvc-697cbdb4d9-qjg8h
The host is exampledeployforpvc-697cbdb4d9-zvkk4
hujianli20220417!

1.2 PV的解绑与回收

在之前的示例中已经将exampledeployforpvc绑定到唯一的PV—exampledeployforpv上,如果此时再创建一个新的PVC,会发生什么情 况呢?

examplefornfspvc2.yml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: examplefornfspvc2
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: "examplenfs"
  resources:
    requests:
      storage: 500Mi

接下来,执行以下命令,创建PVC。

$ kubectl apply -f examplefornfspvc2.yml

PVC创建完成后,可以通过以下命令查询PVC资源。

$ kubectl get pvc
NAME                STATUS    VOLUME            CAPACITY   ACCESS MODES   STORAGECLASS   AGE
examplefornfspvc    Bound     examplefornfspv   1Gi        RWX            examplenfs     5m43s
examplefornfspvc2   Pending                                               examplenfs     <invalid>

可以看到examplefornfspvc2的STATUS属性为Pending,这表示PVC一直处于挂起状态,没有找到合适的PV资源。

虽然examplefornfspv定义的空间为1GiB,而后面定义的两个PVC都各自只申请了500MiB的资源,但PV和PVC只能一对一绑定,不能一对多绑定,所以examplefornfspvc2无法申请到合适的PV资源。要使用examplefornfspvc2,要么再创建一个新的PV资源,要么就让之前的PVC和PV资源解除绑定。

此时我们可以执行以下命令,先删除之前创建的PVC资源。

$ kubectl delete pvc exampledeployforpvc

执行删除命令后,执行$ kubectl get pv命令,可以看到examplefornfspv的STATUS属性由Bound变回Available,CLAIM属性 再次变为空值。PV和PVC已解除绑定,examplefornfspvc2自动绑定到了pv上。

此时再执行$ kubectl get pv命令,可以看到examplefornfspv和examplefornfspvc2已成功绑定

$ kubectl get pvc
NAME                STATUS   VOLUME            CAPACITY   ACCESS MODES   STORAGECLASS   AGE
examplefornfspvc2   Bound    examplefornfspv   1Gi        RWX            examplenfs     2m41s

$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                                   STORAGECLASS          REASON   AGE
examplefornfspv                            1Gi        RWX            Recycle          Bound    default/examplefornfspvc2                               examplenfs                     10m

因为之前PV定义的回收策略(persistentVolumeReclaimPolicy)为Recycle,这表示自动回收,所以解绑后会清理PVC在PV上写入的内 容。此时如果再执行$ cat /data/nfs/nfstest/dataforpvc,可以看到文件已不存在。

$ cat /data/nfs/nfstest/dataforpvc
cat: /data/nfs/nfstest/dataforpvc: No such file or directory

如果自动回收失败,则PV的STATUS属性将变为Failed,这表示暂时无法使用。

如果之前PV定义的回收策略是Retain,则删除PVC后资源不会自动回收。

此时/data/nfs/nfstest/dataforpvc文件依然存在,而PV的STATUS属性将变为Released,因此依然不能重新绑定其 他PVC,除非重新创建PV。