本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
本地存储:存储容量跟踪、分布式制备和通用临时卷进入 Beta 阶段
Kubernetes 中的“通用临时卷”和“存储容量跟踪”功能正在 Kubernetes 1.21 中升级到 Beta 版。结合 CSI external-provisioner 中的分布式供应支持,开发和部署在节点上本地管理存储的容器存储接口 (CSI) 驱动程序变得更加容易。
这篇博客文章解释了这些驱动程序以前的工作方式以及如何利用这些功能来简化驱动程序。
我们正在解决的问题
有一些本地存储驱动程序,例如用于传统磁盘的TopoLVM和用于持久内存的PMEM-CSI。它们在较旧的 Kubernetes 版本上也能正常工作,但实现这一点并不容易。
所需的中央组件
第一个问题是卷供应:它通过 Kubernetes 控制平面进行处理。某些组件必须响应PersistentVolumeClaims (PVC) 并创建卷。通常,这由CSI external-provisioner的中心部署和一个 CSI 驱动程序组件来处理,该组件连接到存储后端。但是对于本地存储,没有这样的后端。
TopoLVM 通过其不同的组件通过 Kubernetes API 服务器创建和响应自定义资源来相互通信。因此,尽管 TopoLVM 基于 CSI(一个独立于特定容器编排器的标准),但 TopoLVM 仅在 Kubernetes 上运行。
PMEM-CSI 使用 gRPC 调用通信创建了自己的存储后端。保护这种通信依赖于 TLS 证书,这使得驱动程序部署更加复杂。
通知 Pod 调度器容量信息
下一个问题是调度。当卷独立于 Pod 创建(“即时绑定”)时,CSI 驱动程序必须选择一个节点,而无需了解任何有关将要使用它的 Pod 的信息。拓扑信息随后强制这些 Pod 在创建卷的节点上运行。如果那里其他资源(如 RAM 或 CPU)耗尽,Pod 将无法启动。可以通过在 StorageClass 中配置卷创建应等待第一个使用卷的 Pod(`volumeBinding: WaitForFirstConsumer`)来避免这种情况。在这种模式下,Kubernetes 调度器根据其他约束试探性地选择一个节点,然后要求 external-provisioner 创建一个卷,使其可以在那里使用。如果本地存储耗尽,provisioner 可以请求另一次调度轮次。但如果没有可用容量的信息,调度器可能总是选择相同的不合适的节点。
TopoLVM 和 PMEM-CSI 都通过调度器扩展器解决了这个问题。这有效,但部署驱动程序时很难配置,因为 kube-scheduler 和驱动程序之间的通信非常依赖于集群的设置方式。
重新调度
本地存储的一个常见用例是临时空间。比持久卷更适合该用例的是临时卷,它为 Pod 创建并随 Pod 一起销毁。支持 CSI 驱动程序临时卷的初始 API(因此称为“CSI 临时卷”)设计用于轻量级卷,其中卷创建不太可能失败。卷创建发生在 Pod 永久调度到节点之后,这与传统的供应方式相反,传统供应方式在将 Pod 调度到节点之前尝试创建卷。必须修改 CSI 驱动程序以支持“CSI 临时卷”,TopoLVM 和 PMEM-CSI 都已完成此操作。但由于 Kubernetes 中该功能的设计,如果节点上的存储容量耗尽,Pod 可能会永久卡住。调度器扩展器试图避免这种情况,但不能100%可靠。
Kubernetes 1.21 中的增强功能
分布式供应
从 Kubernetes 1.20 发布的external-provisioner v2.1.0开始,供应可以由与 CSI 驱动程序一起部署在每个节点上的 external-provisioner 实例处理,然后它们协同工作以供应卷(“分布式供应”)。不再需要中央组件,因此至少对于供应而言,不再需要节点之间的通信。
存储容量跟踪
调度器扩展器仍然需要某种方式来了解每个节点上的容量。当 PMEM-CSI 在 v0.9.0 中切换到分布式供应时,这是通过查询本地驱动程序容器公开的指标数据来完成的。但对于用户来说,完全消除调度器扩展器的需要更好,因为驱动程序部署变得更简单。存储容量跟踪,在 1.19 中引入并在 Kubernetes 1.21 中升级到 Beta 版,实现了这一点。它通过在`CSIStorageCapacity`对象中发布容量信息来工作。调度器本身随后使用该信息来筛选出不合适的节点。由于信息可能不是完全最新的,Pod 仍然可能被分配到存储不足的节点,只是可能性较小,并且一旦信息刷新,Pod 的下一次调度尝试应该会更好。
通用临时卷
因此,CSI 驱动程序仍然需要从错误的调度决策中恢复的能力,而对于“CSI 临时卷”而言,这被证明是不可能实现的。“通用临时卷”是另一个在 1.21 中升级到 Beta 版的功能,它没有这个限制。此功能添加了一个控制器,该控制器将创建和管理具有 Pod 生命周期的 PVC,因此正常的恢复机制也适用于它们。现有的存储驱动程序将能够处理这些 PVC,而无需任何新逻辑来处理这种新情况。
已知限制
通用临时卷和存储容量跟踪都会增加 API 服务器的负载。这是否是一个问题很大程度上取决于工作负载的类型,特别是多少 Pod 拥有卷以及这些卷需要多久创建和销毁一次。
没有尝试对调度决策如何影响存储容量进行建模。这是因为效果可能因存储系统处理存储的方式而异。结果是,多个带有未绑定卷的 Pod 可能会被分配到同一个节点,即使只有足够的容量用于一个 Pod。调度应该会恢复,但如果调度器对存储了解更多,效率会更高。
由于存储容量由正在运行的 CSI 驱动程序发布,而集群自动伸缩器需要有关尚未创建的节点的信息,因此目前它不会为需要卷的 Pod 扩展集群。目前有一个想法来提供这些信息,但该领域还需要更多工作。
目前不支持分布式快照和调整大小。应该可以调整相应的 sidecar,并且 external-snapshotter 和 external-resizer 已经有跟踪问题,只是需要一些志愿者。
对于具有多个卷的 Pod,从错误的调度决策中恢复可能会失败,特别是当这些卷是节点本地卷时:如果可以创建一个卷,然后另一个卷的存储不足,则第一个卷将继续存在并强制调度器将 Pod 放在该卷的节点上。有一个想法是如何处理这个问题,回滚卷的供应,但这仍处于非常早期的头脑风暴阶段,甚至还没有合并到 KEP 中。目前,最好避免创建具有多个持久卷的 Pod。
启用新功能和后续步骤
随着该功能在 1.21 版本中进入 Beta 阶段,无需额外操作即可启用它。通用临时卷也无需更改 CSI 驱动程序即可工作。有关更多信息,请参阅文档和关于它的上一篇博客文章。API 在 Alpha 和 Beta 之间没有发生任何变化。
对于其他两个功能,external-provisioner 文档解释了 CSI 驱动程序开发人员必须如何更改其驱动程序的部署方式以支持存储容量跟踪和分布式供应。这两个功能是独立的,因此只启用其中一个也可以。
SIG Storage 希望听取您使用这些新功能的反馈。您可以通过电子邮件、Slack(频道#sig-storage
)以及定期 SIG 会议与我们联系。您的工作负载描述对于验证设计决策、设置性能测试以及最终将这些功能推广到 GA 将非常有帮助。
致谢
非常感谢为这些功能做出贡献或提供反馈的社区成员,包括 SIG Scheduling、SIG Auth 以及当然还有 SIG Storage 的成员!