Kubernetes: Resource: PV and PVC

13th April 2021 at 2:02pm

PV 指 PersistentVolumns,代表可持久化的存储资源,其底下会有对应的实际存储资源(比如 GCE Persistent Disk);PVC 指 PersistentVolumnClaims,代表开发声明所需要使用的存储资源量。

机制

主要作用:将基础架构的管理交还给运维,由运维维护 PV;开发者仅需要向集群申请需要使用的持久化存储(通过 PVC),无需再关心基础架构。

PV 的 YAML 样例及功能解读:

Acesss mode 有三种:RWO (ReadWriteOnce)、ROX (ReadOnlyMany) 及 RWX (ReadWriteMany)。不同类型的 volumn 支持不同的 access mode,见 官方文档

PV 不属于任何命名空间,它是集群级的资源,跟 node 类似。

PVC 由开发创建,表示需要怎样的(大小、访问模式等)持久化存储供 pod 使用。PVC 这种资源不再是附属在 pod 中,而是属于命名空间的,并且只有同个命名空间的 pod 可以使用该 PVC。

PVC 的 YAML 样例及功能解读:

Pod 中使用 PVC:

生命周期

一个 PV 有几个 phase:

  • Available:可以被 bound 到 claim 上
  • Bound:已经被 bound 到 claim 上
  • Released:不再被 bound 到 claim 上,但是还没被 reclaim
  • Failed:自动 reclaim 失败

一个 PVC,假如没有合适的 PV 可以 bind 上,则状态会是 pending;此时如果有 pod 使用了该 PVC,pod 无法成功启动,会处于 pending 状态,event 中会有 FailedScheduling 事件:1 pod has unbound immediate PersistentVolumeClaims。

假如你删掉了正在被使用的 PV 和 PVC 资源,k8s 并不会马上销毁它,而是等到没有被使用时再销毁。见 官方文档

使用了 PVC 的 pod 被销毁时,PVC 并不会被同时销毁,仍然可以被使用;同样的,PVC 如果被销毁,PV 并不会被销毁。

PV 及 PVC 对应关系

一个 PV 只能被一个 PVC 绑定。即使 PV 的空间有 100G,而 PVC 仅要求 10G,剩余没有使用的 90G 仍然不能被其他 PVC 使用。下文描述的 dynamic provisioning 可以避免这种资源浪费。

Reclaim Policy

一旦 PVC 被销毁,其所绑定的 PV 的状态从 bound 变为 released。这种情况下它无法马上被其他 PVC 绑定,因为上面还有旧的数据。你可以在 PV 的 spec 中定义 reclaim policy,指导 k8s 在 PV 变为 released 后的行为。Reclaim policy 有三种:

  • Retain:保留 PV,不做动作,留给运维手工处理。手工处理的过程是:
    1. 删除 PV。其下的存储资源仍然存在
    2. 如果需要,对存储资源中的文件做清理
    3. 再次创建 PV,使其使用同个存储资源。此时 PV 可以再被 PVC 绑定,使底下的存储资源再次被 pod 使用
  • Recycle:已废弃,基本上是做次删除(rm -rf /thevolume/*
  • Delete:自动将 PV 及其下的存储资源(比如 Azure Disk)同时删除

不同的存储资源支持的 reclaim policy 不一样。比如 GCE Persistent Disk 不支持 recycle,只支持其他两种。

Dynamic provisioning of PersistentVolumes

上述的流程均是运维预先准备好(provision)资源及 PV,使用者再 claim 它们要多少资源。Dynamic provisioning 可以使运维无需预先准备 PV,使集群在用户创建 PVC 时动态生成 PV。

k8s 通过定义了一种新资源 StorageClass 完成这个过程。StorageClass 是集群下的资源,不属于具体命名空间,它的定义如下:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast                          # StorageClass 名字,会被 PVC 使用
provisioner: kubernetes.io/gce-pd     # provisioner,即分配资源的插件,比如这个是 GCE 的 persistent disk
parameters:                           # 参数是传给 provisioner 插件的,各插件的参数定义不同
  type: pd-ssd                        # 表示 provisioner 生成的 PV 应该是基于 SSD 的
  zone: europe-west1-b

各云厂商 定义 了它们自己的 provisioner。

如果你用 GKE,GKE 会在你的 k8s 集群 预先配置 好一个默认的 StorageClass,其使用的是标准磁盘(pd-standard,而非 SSD)。

你可以配置多个 StorageClass 来满足不同要求,比如定义一个名为 standard,表示标准磁盘的;再定义一个名为 fast,表示 SSD 的。

配置好 StorageClass 后,你就可以在 PVC 中定义要使用的 StorageClass,如:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mongodb-pvc 
spec:
  storageClassName: fast     # 要使用的 StorageClass
  resources:
    requests:
      storage: 100Mi
    accessModes:
    - ReadWriteOnce

k8s 就会让相应的 provisioner 分配磁盘,产生 PV。整个过程如下:

假如你在 PVC 中不定义 storageClassName,k8s 会用 默认的 StorageClass。假如你不想用动态生成的 PV,想用手工分配的 PV,你需要将 storageClassName 设置为空字符串 ""

kubectl get sc 可以用来检查已有的 StorageClass,比如 kubectl get sc standard -o yaml

StorageClass 中可以设置 reclaim policy,来控制生成的 PV 的 reclaim policy。默认一般是 delete,即一旦 PVC 被删除,绑定的 PV 不再被使用,则会自动删除 PV 及其底下的磁盘资源。