Caicloud 助力 K8S 新版本发布,存储数据保护持续升级

2018-03-13


背景介绍


背景

在现有的 Kubernetes 集群 (1.9 之前) 中,用户可以随时删除 PersistentVolumeClaim(PVC),即使这个 PVC 还在被 Pod 使用。同样的,集群管理员也可以随时删除 PersistentVolume (PV),不管这个 PV 有没有被一个 PVC 所绑定。这样的情况很危险,会导致数据丢失。设想一下: 一个 PV正绑定到一个 PVC 上面,而且这个 PVC 正在被一个 active 的 Pod 所使用,如果此时用户在不管是误操作还是其他什么原因的情况下删除了这个 PVC, 或者是管理员删除了这个 PV,Pod 是感知不到的,应用还是像以前一样,一直在写数据,这些数据都会丢失。


现状

在 Kubernetes 1.9 中,我们引入了 Alpha 版本的 PVC Protection feature,用来防止正在被使用的PVC 被用户删除。在 Kubernetes 1.10 中,这个 PVC Protection feature 将会升级到 Beta 版本,同时我们才云科技 (Caicloud) 设计并实现了 PV Protection feature,将直接以 Beta 版本发布。 PV Protection 这个 feature 将会阻止管理员删除正绑定到 PVC 上面的 PV ,防止数据丢失。同时,为了优化和缩减代码,我们把两个 feature 合并,统称为 StorageObjectInUseProtectionfeature。


目标

保护正在被其他资源使用的 PV 或者 PVC 不能删除,防止数据丢失。


方案


设计和实现方案涉及多个模块,下面将从三个主要的模块来详细说明。


Admission Plugin

Admission Plugin 主要做一些准入控制等操作,在这里,我们将会新建一个 Admission Controller。 如果这个新的 Admission 被 enable 的话,将会为新建的 PVC 和 PV 添加 finalizer,用于防止PVC 和 PV 被误删。


Protection Controller

同时我们也会新建两个 Controller,分别为 PVC Protection Controller 和 PV ProtectionController,这两个 Controller 将会具体负责 PVC 和 PV 的监控和检查,同步 finalizer 情况,控制PVC 和 PV 能不能被删除。


下面分别说下 PVC Protection Controller 和 PV Protection Controller 的工作流程:


PVC Protection Controller

PVC Protection Controller 将会监控(watch)PVC 和 Pod 的 Add/Update/Delete 操作,并作出相应的响应。具体如下:


PVC 的 Add/Update/Delete 操作事件:

  • 如果 PVC 的 deletionTimeStamp 和 finalizer 都没有被设置,那么,此 PVC 将会被加入到 PVCProtection Controller 的工作队列中,等待被添加 finalizer;
  • 如果 PVC 的 deletionTimeStamp 和 finalizer 都被设置了,那么, 此 PVC 也将被加入到 PVCProtection Controller 的工作队列中,将会尝试移除 finalizer;

PS: finalizer 被加入到 Kubernetes object 中,将会阻止 object 被直接删除,直到 finalizer 被去掉, object 才能被删除。


Pod 的 Add/Update/Delete 操作:

  • 如果 Pod 的状态是 Terminated 或者从非 Terminated 变为 Terminated,或者是被删除了,那么这个 Pod 所引用的所有的 PVC 都将会被加入到 PVC Protection Controller 的工作队列中,等待被处理;


PVC Protection Controller 对他所缓存的 PVC 队列的处理逻辑如下:

  • 如果队列里没数据,跳过;
  • 如果 PVC 的 deletionTimeStamp 和 finalizer 都没有被设置,那么为它添加 finalizer;
  • 如果 PVC 的 deletionTimeStamp 和 finalizer 都被设置了,检查 PVC 是不是正在被 Pod 使用,如果不是,移除 finalizer,如果是,跳过;如果操作失败,会把 PVC 重新入队列;


PV Protection Controller

PV Protection Controller 将会监控 PV 的 Add/Update/Delete 操作,并作出相应的响应。本来这个Controller 也应该监控 PVC 的相应事件的,但是由于我们已经有了 PV Controller,负责同步 PV 和PVC 的相关状态,所以这里我们可以选择相信 PV Controller,只监控 PV 的相关操作。具体如下:


PV 的 Add/Update/Delete 操作事件:

  • 如果 PV 的 deletionTimeStamp 和 finalizer 都没有被设置,那么,此 PV 将会被加入到 PVProtection Controller 的工作队列中,等待被添加 finalizer;
  • 如果 PV 的 deletionTimeStamp 和 finalizer 都被设置了,那么, 此 PV 也将被加入到 PVProtection Controller 的工作队列中,将会尝试移除 finalizer;


PV Protection Controller 对他所缓存的 PV 队列的处理逻辑如下:

  • 如果队列里没数据,跳过;
  • 如果 PV 的 deletionTimeStamp 和 finalizer 都没有被设置,那么为它添加 finalizer;
  • 如果 PV 的 deletionTimeStamp 和 finalizer 都被设置了,检查 PV 是不是正在被 PVC 使用,如果不是,移除 finalizer,如果是,跳过;如果操作失败,会把 PV 重新入队列;


CLI 部分

为了像 Pod 那样,可以显示出 Pod 的 Terminating 状态,我们也为 PV 和 PVC 添加了相应的Terminating 状态,用户使用 kubectl get pv/pvc 的时候可以看到 PV/PVC 是不是处于 Terminating状态,同时可以使用 kubectl describe pv pv-name/ kubectl describe pvc pvc-name 来看到具体的PV/PVC 处于 Terminating 状态的时间。比较直观的显示如下:



当然,具体的设计和实现不止这几部分,还有其他部分如: Scheduler, Kubelet, PV Controller等的相应的修改,用以支撑这个 feature 的功能实现,大家可以自行参考具体的 Proposal(见文章底部)。



用例


unexpected PVC deletion

Pod A 引用了 PVC B, 用户误删除了 B,如果这个 PVC 是引用了 StorageClass 来动态创建 PV,而且 Reclaim Policy 是 Delete , 这样 A 的数据写入功能将会导致数据丢失;


unexpected PV deletion

Pod A 引用 PVC B, PVC B 绑定到 PV C 上面,管理员删除了 C, 这样 A 的数据写入将会导致数据丢失;


示例


删除正在被使用的 PVC

创建 PV、PVC、Pod



删除 PVC



PVC 没有被删除,状态变为 Terminating,

删除 Pod



Pod 被删除后,PVC 也被删除了。


删除正在被使用的 PV

创建 PV 和 PVC



删除 PV



PV 没有被立即删除,但是状态变为 Terminating

删除 PVC



删除 PVC 后, PV 也被删除了。


由上面的示例可以看出,新的 StorageProtection feature 出来之后,我们可以有效的防止用户或者是管理员的误删除操作,从而达到保护数据,防止数据丢失的目的。


将来


这个 feature 后面会做相应的修改,可能会有小部分的代码改动,之后会升级为稳定版本,大家放心使用,有问题可以联系才云科技(Caicloud),后面我们才云科技会继续开发维护这个 feature。


相关的 Proposal:

https://github.com/kubernetes/community/pull/1608

https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/postpone-pvc-deletion-if-used-in-a-pod.md

点击体验,开启谷歌级数字化之旅
立即体验
立即咨询