从一个例子入手,深入理解 K8S 的持久卷 PV 和 PVC

2024-05-10 渥太华微生活

2402_2_1_Kubernetes_pv_pvc_No428.png


从一个例子入手PV、PVC

Kubernetes 项目引入了一组叫作 Persistent Volume Claim(PVC)和 Persistent Volume(PV)的 API 对象用于管理存储卷。

下面举个例子看看,这个例子来自《k8s in Action》:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mongodb-pvcspec:
  resources:
    requests:
      storage: 1Gi  
  accessModes:
  - ReadWriteOnce
  storageClassName: ""

yaml文件中定义了storage为1 GiB表示PVC需要的容量;

Access Modes表示需要的volume存储类型,ReadWriteOnce表示只能在一个node节点上进行读写操作,其他的Access Modes详见

https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes;

storageClassName为空,表示的是storageClass的名称,我们下面会说到。

然后获取一下PVC的状态:

$ kubectl get pvc
NAME                   STATUS   VOLUME              CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mongodb-pvc            Available    mongodb-pv          1Gi        RWO,ROX                       2m25s

此时可以看到,我们的PVC处于可用状态。

然后再定义一个PV:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mongodb-pvspec:
  capacity:
    storage: 1Gi  
  accessModes:
  - ReadWriteOnce  
  - ReadOnlyMany  
  persistentVolumeReclaimPolicy: Retain  
  gcePersistentDisk:
    pdName: mongodb    
    fsType: ext4

这个 PV 对象中会详细定义存储的类型是GCE,以及大小是1 GiB,这里没有声明storageClassName,是因为storageClassName默认就为空。

然后我们看一下PV和PVC的状态:

$ kubectl get pv
NAME                CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                          STORAGECLASS   REASON   AGE
mongodb-pv          1Gi        RWO,ROX        Retain           Bound       default/mongodb-pvc                                    77m

$ kubectl get pvc
NAME                   STATUS   VOLUME              CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mongodb-pvc            Bound    mongodb-pv          1Gi        RWO,ROX                       7m7s

可以看到PV和PVC已经相互绑定了。

PVC和PV相当于“接口”和“实现”,所以我们需要将PVC和PV绑定起来才可以使用。

而PVC和PV绑定的时候需要满足:

  • PV 和 PVC 的 spec 字段要匹配,比如PV 的存储(storage)大小,就必须满足 PVC 的要求。

  • PV 和 PVC 的 storageClassName 字段必须一样才能进行绑定。storageClassName表示的是StorageClass的name属性。

如果我们想要在Pod中使用这个PVC,那么我们可以这么做:

apiVersion: v1
kind: Pod
metadata:
  name: mongodb
spec:
  containers:
  - image: mongo    
    name: mongodb    
    volumeMounts:
    - name: mongodb-data      
      mountPath: /data/db    
    ports:
    - containerPort: 27017
      protocol: TCP  
  volumes:
  - name: mongodb-data    
    persistentVolumeClaim:
      claimName: mongodb-pvc

在Pod中只需要声明PVC的名字,等Pod创建后kubelet 就会把这个 PVC 所对应的 PV,也就是一个 GCE类型的 Volume,挂载在这个 Pod 容器内的目录上。

PersistentVolumeController会不断地查看当前每一个 PVC,是不是已经处于 Bound(已绑定)状态。如果不是,那它就会遍历所有的、可用的 PV,并尝试将其与这个“单身”的 PVC 进行绑定。

那么问题来了,k8s为什么要将一个存储卷分成两部分呢?

因为实际上,我们项目当中,研发人员和集群的管理人员是分开的,研发人员只管使用,但是并不关心底层到底用的是什么存储技术,所以研发人员只要声明一个PVC,表示我需要多大的一个存储,以及读写类型就可以了。

20200816215430.png


StorageClass 的 Dynamic Provisioning

在上面我们说的PV和PVC绑定的过程称为Static Provisioning,需要手动的创建PV。

我们在研发中可能有这样的情况,就是管理员没有及时给我们创建对应的PV,难道一直等着吗?

所以这个时候就需要用到StorageClass了,StorageClass提供了Dynamic Provisioning机制,可以根据模板创建PV。

StorageClass 对象会定义如下两个部分内容:

  • PV 的属性。比如,存储类型、Volume 的大小等等。

  • 创建这种 PV 需要用到的存储插件。比如,Ceph 等等。

这样k8s就能够根据用户提交的 PVC,找到一个对应的 StorageClass ,然后调用该 StorageClass 声明的存储插件,创建出需要的 PV。

例如声明如下StorageClass:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: block-service
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-ssd

这里定义了名叫 block-service 的 StorageClass,provisioner 字段的值是:kubernetes.io/gce-pd,这是k8s内置的存储插件,type字段也是跟着provisioner定义的,官方默认支持 Dynamic Provisioning 的内置存储插件:https://kubernetes.io/docs/concepts/storage/storage-classes/。

然后就可以在PVC中声明storageClassName为block-service,当创建好PVC 对象之后,k8s就会调用相应的存储插件API创建一个PV对象。

如下:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: claim1
spec:
  accessModes:
    - ReadWriteOnce  
  storageClassName: block-service  
  resources:
    requests:
      storage: 30Gi

这种自动创建PV的机制就是Dynamic Provisioning,Kubernetes 就能够根据用户提交的 PVC,找到一个对应的 StorageClass ,然后会调用StorageClass 声明的存储插件,创建出需要的 PV。

需要注意的是,如果没有声明StorageClassName在PVC中,PVC 的 storageClassName 的值就是"",这也意味着它只能够跟 storageClassName 也是""的 PV 进行绑定。


PV和PVC 的生命周期

PV和PVC之间的相互作用遵循这个生命周期:

Provisioning —>Binding —>Using —>Reclaiming

  • Provisioning

k8s提供了两种PV生成方式: statically or dynamically

statically:由管理员创建PV,它们携带可供集群用户使用的真实存储的详细信息。 它们存在于Kubernetes API中,可用于消费。

dynamically:当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim时,集群可能会尝试为PVC动态配置卷。 此配置基于StorageClasses,PVC必须请求一个StorageClasses,并且管理员必须已创建并配置该类才能进行动态配置。

  • Binding

由用户创建好PersistentVolumeClaim 后,PersistentVolumeController会不断地查看当前每一个 PVC,是不是已经处于 Bound(已绑定)状态。如果不是,那它就会遍历所有的、可用的 PV,并尝试将其与这个“单身”的 PVC 进行绑定。

  • Using

Pods声明并使用PVC作为volume后,集群会找到该PVC,如果该PVC已经绑定了PV,那么会将该volume挂载到Pod中。

  • Reclaiming

当用户已经不再使用该volume,可以将该PVC删除,以便让资源得以回收。相应的在PVC删除后,PV的回收策略可以是Retained, Recycled, or Deleted,这个策略可以在字段spec.persistentVolumeReclaimPolicy中设置。

    • Retain:这个策略允许手动回收资源,当PVC被删除后,PV仍然可以存在,管理员可以手动的执行删除PV,并且和PV绑定的存储资源也不会被删除,如果想要删除相应的存储资源的数据,需要手动删除对应存储资源的数据。

    • Delete:这个策略会在PVC被删除之后,连带将PV以及PV管理的存储资源也删除。

    • Recycle:相当于在volume中执行rm -rf /thevolume/*命令,以便让volume可以重复利用。

一般的情况下,我们遵循这个删除流程:

  1. 删除使用这个 PV 的 Pod (kubectl delete pod my-pod);

  2. 从宿主机移除本地磁盘(比如,umount 它);

  3. 删除 PVC (kubectl delete pvc my-pvc)

  4. 删除 PV (kubectl delete pv my-pv)

二维码 | 渥太华微生活

编者注:新闻取自各大新闻媒体,新闻内容并不代表本网立场!文字和图片来自网络,版权归原作者所有。如有侵权,请速联系小编,立即删除。

79
全部评论 (0)
展开快速发表评论

科技专栏