K8S | Kubernetes 1.7 本地数据卷管理


本期文章来自才云科技(Caicloud)CTO 邓德源的技术原创。node

1
Overviewgit

Kubernetes 1.7 不会引入过多新功能,比较重要的几个特性包括 Priority API、CRI 的加强以及 Federation 的部分功能。此外,计划中还将提供本地存储管理,主要分为两个层面:github

本地系统容量的管理。Kubernetes 的主分区主要包含 Kubelet 的根目录(/var/lib/kubelet),/var/log 目录等。此外,容器镜像,容器读写层,容器日志,Kubernetes 空数据卷(emptyDir)等都须要消耗该空间(默认状况下)。在 Kubernetes 1.7 中,社区将尝试把此类资源集中管理起来,并做为调度资源。数据库

本地数据卷管理。本地数据卷管理的主要内容是将非主分区的其余分区所有做为本地持久化数据卷供 Kubernetes 调度使用,遵循 Kubernetes 的 PV/PVC 模型。分布式

2
Local Volume API性能

在本文中,咱们集中介绍本地数据卷管理,一块儿思考如何设计本地持久化数据卷,后续再介绍 Kubernetes 准备如何进行容量管理。spa

首先,在设计之初,咱们须要思考本地数据卷的场景和用例,社区认为的两个主要应用场景是分布式文件系统和数据库,由于二者都须要高性能和可靠性,好比在云的环境里,本地 SSD 比挂载的数据盘性能高出许多;另外,本地磁盘在多数状况下成本更低,适合数据量大的场景。插件

了解场景以后,开始进入 API 设计阶段。本地数据卷的管理是一个比较复杂的工程,须要支持文件系统和块存储。不一样的文件系统具备不一样的特性(好比 xfs 支持 quota,而目前 ext4 并不支持 quota),挂载选项也截然不同。设计

而且,本地存储卷是目前为止惟一一个涉及到同时支持文件系统和块存储的插件方案(ceph 能够算一个,可是 cephfs 和 RBD 目前是两个插件)。为了兼容各类可能的状况,通过长时间讨论,目前 API 已经基本定型:localstorage

clipboard.png

有了上述定义,咱们能够建立相对应的 Persistent Volume:

clipboard.png

这里有几个注意事项:

spec.local.path 能够是任意的路径,可是 Kubernetes 推荐把一块磁盘或者分区挂载到该分区。使用一块磁盘除了能够作到容量隔离以外,还能够作到性能隔离;若是性能隔离对应用场景不重要,那么能够把磁盘划分为多个分区,所以能够建立多个 PV。Kubernetes 的这种方式将控制权所有交给了用户,用户能够更加灵活的配置系统。

spec.local.path 目前只能是路径,后续 Kubernetes 会支持块设备,这样一来 spec.local.path 会被重用,即当 PV 是一个挂载点时,path 是一个路径;当 PV 是一个块设备时,path 表明设备路径。另外一种方案是采用更深层次的键值,例如 spec.local.fs.path, spec.local.block.path,这样的好处是能够支持多重属性,好比 spec.local.fs.fsType,可是社区目前并无这么去作,主要缘由是考虑适配 CSI (container storage interface)。

spec.capacity 目前是 informational。若是咱们采用的是磁盘或者分区的方式,那么该值是磁盘或分区的大小,也就作到了容量隔离。但若是咱们采用的是任意的目录,目前 Kubernetes 并不会限制该目录可使用的大小。

上述 API 仅仅定义了 local PV 的 path 属性,可是不一样于其余存储插件,local PV 的一大特色就是它必定会与本地所绑定,所以,咱们须要给 PV 再加一个属性,告知系统 PV 属于哪一个节点。咱们能够简简单单地在 PV 内加上 NodeName 的属性,以下所示:

clipboard.png

这里最大的问题在于,咱们将 PV 的拓扑结构限定在节点层面,可是“本地”的含义并非说存储必定是分配在某台机器上,咱们能够说:这个存储是属于该 rack 的本地存储。那么对于 rack 内的机器而言,该存储就是他们的本地存储。鉴于此,local volume 的 API 须要设计得更加通用:

clipboard.png

上述 Yaml 与最开始介绍的配置表达的相同的内容,可是提供了更加灵活的表达方式,同时也复用了 Kubernetes 中已经存在的 node affinity 的概念。

3
Local Volume Scheduling

Kubernetes PV/PVC 在设计时,忽略了与调度器的交互部分,致使 PV/PVC 的绑定与 Pod 调度毫无关系。在 “remote volume“ 的状况下问题并不大,由于 Pod 被调度后,能够动态挂载数据卷,可是在本地数据卷的状况下,问题已经凸显出来。当用户建立 PV 和 PVC 以后,因为本地数据卷的特性,任何要求某个特定 PVC 的 Pod 实际上已经被调度了。

例如,管理员建立一个名为 super-pv 的数据卷,该数据卷存在于节点 Kube-node-1 上;当用户建立一个名为 claim-it 的 PVC 并被 Kubernetes 绑定在 super-pv 上以后,任何使用 PVC 的 Pod 实际上已经被调度到了 Kube-node-1 上。

假设此时,Kube-node-1 的资源没法知足 Pod 的需求(例如 CPU 足够),那么 Pod 会一直处于 Pending 状态,即便另一台机器 Kube-node-2 有足够的资源,也有知足需求的本地数据卷。

在 Kubernetes 1.7 中,本地数据卷管理暂时不会处理该问题(会设计一个外部控制器来按期查询该错误状态,并根据必定的策略从新调度)。后续的解决方案暂无定论,其中一个可行的方案是将绑定逻辑放在调度器中:

PV/PVC 的绑定被延迟到调度时刻,即当真有 Pod 使用某个 PVC 时再进行绑定
调度器经过 PVC.storageclass 找到可使用的 PV,并拿到每一个 PV 的 affinity
调度器综合考虑 Pod 的调度需求和 PV 的 affinity 进行调度
若是没有知足需求的 Node,调度器经过和 PV provisioner 交互,动态建立 PV

若是咱们从总体的设计上来看,该问题并不是只会出如今本地存储上,任何须要调度器和 PV/PVC 绑定控制器交互的地方都会有问题。

例如,在多 zone 的状况下,PV/PVC 控制器并不会考虑一个 PV 须要建立在哪一个 zone 里面;所以,颇有可能控制器选择了一个 zone,可是该 zone 并不知足 Pod 的需求(例如 affinity 需求,或者全部节点资源都不够)。

因为一个 zone 可能包含多个机器,所以问题被缩小,但仍然存在。若是咱们仔细思考能够看出,实际上 node 就是一个 ”tiny zone“,问题的本质其实是同样的。

4
Local Volume Static Provisioner

本地数据卷的建立由新的 Kubernetes 组件处理(local volume provisioner addon),该组件将以 DaemonSet 的方式部署。

Provisioner 有两个核心组件:

Discovery: discovery 组件的功能是接收用户配置的信息,而后建立 PV。例如,当用户将 “/var/lib/kubelet/localstorages” 做为本地数据卷的目录后,provisioner 会为该目录下的每个目录建立一个新的 PV,并添加正确的拓扑信息。

Deleter: deleter 负责处理 PV 状态改变。当 deleter 发现其管理的 PV 进入了 Released 状态,deleter 会清理数据并将 PV 从 Kubernetes API 中删除。此时,Discovery 发现 PV 被删除,会从新建立新的 PV,从而达到回收的效果。

Provisioner 后续还能够完成各类错误汇报,容量检查等功能,在 kubernetes 1.7 中会提供 alpha 版本。

5
Future

尽管 Kubernetes 1.7 中本地存储卷只能说处于基本能够试一试的状态,社区后续会为这个功能投入大量精力,具体实现内容已经涉及到 1.八、1.9 版,包括 dynamic provisioner, fsGroup support, SELinux support, taints/toleration, local PV monitoring, block storage support 等,相信后续会有更多进展。

相关阅读:
https://github.com/kubernetes...

https://github.com/kubernetes...

相关文章
相关标签/搜索