PV与PVC

  • PV的回收策略

  • PV与PVC的状态

  • PVC与PV的绑定条件

  • PV的Attach与Mount

PV的回收策略

在PV的yaml文件中有一个字段persistentVolumeReclaimPolicy,表示PV的回收策略(即当与P绑定的PVC被删掉后,集群该如何自动处理这个PV),该字段的取值有如下三个:

  • Retain

当与PV绑定的PVC被删掉后,集群不对PV做任何的处理。此时,需要人工进行手动操作,比如手动删除这个PV以及PV后面的卷。

  • Delete

当与PV绑定的PVC被删掉后,集群会自动删除PV及PV绑定的卷(比如PV是RBD类型,那么会自动删除PV关联的RBD块)。注意,不是所有类型的PV都支持Delete,一般只有RBD、GCEPersistentDisk等支持动态供给的才支持

  • Recycle

当与PV绑定的PVC被删掉后,集群不会删除PV,但会清理PV关联的卷下面的内容(比如PV关联的是一个NFS目录/nfs/,那么会自动清理/nfs/下的内容)。不是所有类型的PV都支持Recycle,一般只有NFS等不支持动态供给的文件系统才支持

PV与PVC的状态

PV的yaml文件中有一个字段status.phase,表示PV的状态,该字段有如下四个取值

  • Available:PV可用,等待被PVC绑定

  • Bound:PV已经被PVC绑定

  • Released:PV绑定的PVC已经被删,但是PV还没有被集群回收

  • Failed:PV的自动回收失败

PVC与PV的绑定条件

当我们创建一个PVC的时候,kube-controller-manager就会为其寻找一个PV进行绑定。只有符合PVC条件的PV才能被绑定。这里,我们要先介绍一下PV与PVC的yaml文件及字段。

一个PV的yaml文件如下:

一个PVC的yaml文件如下:

  • storage

PV的spec.capacity.storage表示这个持久卷的大小,PVC的spec.resources.requests.storage表示PVC对持久卷的大小的要求。

只有当PVC的`storage`小于等于PV的`Storage`,PVC才能绑定此PV。
  • accessModes

accessModes有三个取值:

  • ReadWriteOnce:远程卷只能以读写模式挂载到一个节点上,注意是主机节点

  • ReadOnlyMany:远程卷只能以只读模式挂载到一个节点上

  • ReadWriteMany:远程卷可以以读写模式挂载到多个节点上

在PV和PVC中该字段是必填的,而且只能填一个值(虽然是List)。

只有当PVC的accessModes与某个PV的一致时,PVC才能绑定这个PV。

并不是所有的卷类型都支持以上三种模式,详情见官网链接

  • volumeMode

该字段有两种取值:FilesystemBlock,默认值为Filesystem

  • Filesystem:远程卷挂载到节点后会被格式化成一个文件系统

  • Block:远程卷只挂载到节点,不会被格式化

并不是所有的卷类型都支持以上两种模式,像hostPathnfscephfs等这些只支持filesystem,像rbdGCEPersistentDisk这些块设备两种都支持

只有PVC的volumeMode与PV的一致时,才能绑定该PV
  • label与selector

该区配条件与Pod类似。

PV的Attach与Mount

容器的持久化要达到的效果是:当在容器的目录中写数据时,能够同步到远程存储服务的磁盘中。那么这个过程是如何实现的呢?

这个“持久化”的过程,我们可以形象地称为“两阶段处理”。接下来我们以一个例子来说明。

当一个Pod调度到一个节点上之后,kubelet就要负责为这个Pod创建它的Volume目录。默认情况下,kubelet为Volume创建的目录是如下所示的一个宿主机上的路径:

/var/lib/kubelet/pods/<PodId>/volumes/kubernetes.io~<VolumeType>/<VolumeName>

接下来,kubelet要做的操作取决于你的Volume类型了。

如果你的Volume类型是远程块存储,比如Google Cloud的Persistent Disk(GCE提供的远程磁盘服务),那么kubelet就需要先调用Google Cloud的API,将Persistent Disk挂载到Pod所在的宿主机上。这相当于执行:

$ gcloud compute instances attach-disk <主机的名字> --disk <远程磁盘名字>

这一步为主机挂载远程磁盘的操作,对应两阶段处理的第一阶段。在kubernetes中,我们把这个阶段称为Attach

Attach阶段完成后,在本机上就可以看到一个新的磁盘(此时该磁盘还未格式化为文件系统及Mount)。为了能够使用这个磁盘,kubelet还要进行第二个操作,即:格式化这个磁盘,然后将它挂载到Volume的目录。这一步相当于执行:

$ lsblk
$ mkfs.ext4 -m 0 -F -E lazy_itable_init=0,lazy_journal_init=0,discard /dev/<DiskId>
$ mount /var/lib/kubelet/pods/<PodID>/volumes/kubernetes.io~<VolumeType>/<VolumeId> /dev/<DiskId>

这个将磁盘设备格式化并挂载到Volume目录的操作,对应的正是“两阶段”处理的第二个阶段,我们一般称为Mount

Mount阶段完成后,这个宿主机目录就是一个持久化的目录了,然后kubelet启动容器,将容器目录挂载到宿主机的这个目录。

如果你的Volume类型是远程文件存储,比如NFS,kubelet的处理过程就会更简单一些。因为在这种情况下,kubelet可以跳过第一阶段的操作,而直接进入第二阶段。

在这一步,kubelet需要作为client,将远程NFS服务器的目录(比如/目录),挂载到宿主机的目录上,这相当于执行:

$ mount -t nfs <NFS-Server-IP>:/ /var/lib/kubelet/pods/<PodID>/volumes/kubernetes.io~<VolumeType>/<VolumeId>

接下来,kubelet就可以调用CRI来启动容器了。

Last updated

Was this helpful?