
在Kubernetes仍为v1.0.0的时代,存在大量插件。 需要它们连接到Kubernetes系统以存储持久(永久)容器数据。 它们的数量很小,并且在最早的存储提供商中有GCE PD,Ceph,AWS EBS等。
插件与Kubernetes一起交付,因此得名于它们。 但是,许多现有的此类插件集还不够。 工匠使用补丁将简单的插件添加到Kubernetes的核心中,然后他们构建了自己的Kubernetes并将其放置在服务器上。 但是随着时间的流逝,Kubernetes开发人员意识到
鱼无法解决。 人们需要一根
钓鱼竿 。 在Kubernetes v1.2.0发行版中,它似乎...
Flexvolume插件:最小的钓鱼竿
Kubernetes的开发人员创建了FlexVolume插件,该插件是用于与第三方Flexvolume驱动程序一起使用的变量和方法的逻辑绑定。
让我们停下来仔细看看FlexVolume驱动程序是什么。 这是一个特定的
可执行文件 (二进制文件,Python脚本,Bash脚本等),在执行时,将使用命令行参数并以JSON格式返回包含先前已知字段的消息。 按照约定,第一个命令行参数始终是方法,其余参数是其参数。
OpenShift中的CIFS共享连接方案。 Flexvolume驱动程序-居中最少的方法集如下所示:
flexvolume_driver mount # pod' # : { "status": "Success"/"Failure"/"Not supported", "message": " ", } flexvolume_driver unmount # pod' # : { "status": "Success"/"Failure"/"Not supported", "message": " ", } flexvolume_driver init # # : { "status": "Success"/"Failure"/"Not supported", "message": " ", // , attach/deatach "capabilities":{"attach": True/False} }
使用
attach
和
detach
方法将确定方案,根据该方案,将来在调用驱动程序时kubelet将起作用。 还有一些特殊的
expandvolume
和
expandfs
负责动态调整卷的大小。
作为
expandvolume
方法
expandvolume
的更改的示例,并具有实时执行体积调整大小的功能,您可以在Rook Ceph Operator中检查
我们的拉取请求 。
这是用于NFS的Flexvolume驱动程序的示例实现:
usage() { err "Invalid usage. Usage: " err "\t$0 init" err "\t$0 mount <mount dir> <json params>" err "\t$0 unmount <mount dir>" exit 1 } err() { echo -ne $* 1>&2 } log() { echo -ne $* >&1 } ismounted() { MOUNT=`findmnt -n ${MNTPATH} 2>/dev/null | cut -d' ' -f1` if [ "${MOUNT}" == "${MNTPATH}" ]; then echo "1" else echo "0" fi } domount() { MNTPATH=$1 NFS_SERVER=$(echo $2 | jq -r '.server') SHARE=$(echo $2 | jq -r '.share') if [ $(ismounted) -eq 1 ] ; then log '{"status": "Success"}' exit 0 fi mkdir -p ${MNTPATH} &> /dev/null mount -t nfs ${NFS_SERVER}:/${SHARE} ${MNTPATH} &> /dev/null if [ $? -ne 0 ]; then err "{ \"status\": \"Failure\", \"message\": \"Failed to mount ${NFS_SERVER}:${SHARE} at ${MNTPATH}\"}" exit 1 fi log '{"status": "Success"}' exit 0 } unmount() { MNTPATH=$1 if [ $(ismounted) -eq 0 ] ; then log '{"status": "Success"}' exit 0 fi umount ${MNTPATH} &> /dev/null if [ $? -ne 0 ]; then err "{ \"status\": \"Failed\", \"message\": \"Failed to unmount volume at ${MNTPATH}\"}" exit 1 fi log '{"status": "Success"}' exit 0 } op=$1 if [ "$op" = "init" ]; then log '{"status": "Success", "capabilities": {"attach": false}}' exit 0 fi if [ $# -lt 2 ]; then usage fi shift case "$op" in mount) domount $* ;; unmount) unmount $* ;; *) log '{"status": "Not supported"}' exit 0 esac exit 1
因此,在准备好实际的可执行文件之后,您需要
在Kubernetes集群中布置驱动程序 。 驱动程序必须根据预定义的路径位于群集的每个节点上。 默认情况下已选择:
/usr/libexec/kubernetes/kubelet-plugins/volume/exec/__~_/
...但是使用不同的Kubernetes发行版(OpenShift,Rancher ...)的路径可能不同。
Flexvolume问题:如何投下钓鱼竿?
事实证明,将Flexvolume驱动程序放在群集节点上并非易事。 手动完成一次操作后,很容易遇到集群中出现新节点的情况:由于添加了新节点,自动水平缩放,或者更糟糕的是,由于故障而替换了该节点。 在这种情况下,除非您以相同的方式将Flexvolume驱动程序手动添加到这些节点上,否则
无法使用这些节点上的存储。
解决该问题的方法是Kubernetes-
DaemonSet
的原始方法之一。 当新节点出现在群集中时,它将自动从我们的DaemonSet中获取一个容器,在该容器中附加了本地卷以查找Flexvolume驱动程序。 成功创建后,pod复制驱动程序在磁盘上工作所需的文件。
这是用于布置Flexvolume插件的此类DaemonSet的示例:
apiVersion: extensions/v1beta1 kind: DaemonSet metadata: name: flex-set spec: template: metadata: name: flex-deploy labels: app: flex-deploy spec: containers: - image: <deployment_image> name: flex-deploy securityContext: privileged: true volumeMounts: - mountPath: /flexmnt name: flexvolume-mount volumes: - name: flexvolume-mount hostPath: path: <host_driver_directory>
...以及用于布置Flexvolume驱动程序的Bash脚本示例:
重要的是不要忘记复制操作
不是原子的 。 kubelet极有可能在其准备过程完成之前就开始使用驱动程序,这将导致系统错误。 正确的方法是首先以不同的名称复制驱动程序文件,然后使用原子重命名操作。
在Rook语句中使用Ceph的方案:图上的Flexvolume驱动程序在Rook代理内部使用Flexvolume驱动程序时的下一个问题是,对于大多数存储而言
,为此必需的软件应安装在群集节点上(例如,用于Ceph的ceph-common软件包)。 最初,Flexvolume插件并非旨在实现这种复杂的系统。
在Rook运算符的Flexvolume驱动程序的实现中可以看到该问题的原始解决方案:
驱动程序本身被设计为RPC客户端。 用于通信的IPC套接字与驱动程序本身位于同一目录中。 我们记得要复制驱动程序文件,最好使用DaemonSet,它将目录与驱动程序连接为一个卷。 复制所需的rook驱动程序文件后,此pod不会消失,而是通过连接的卷作为完整的RPC服务器连接到IPC套接字。 ceph-common软件包已经安装在pod容器中。 IPC套接字使人们确信kubelet将与位于同一节点上的特定pod通信。 一切巧妙的方法都很简单!
再见了,我们深情的... in-tree插件!
Kubernetes开发人员发现内核中的存储插件数量为20。 它们中的每一个都以某种方式经历了整个Kubernetes的发布周期。
事实证明,要使用新版本的插件进行存储,
您需要更新整个集群 。 除此之外,您可能会惊讶于新版本的Kubernetes突然变得与所使用的Linux内核不兼容...因此,您擦干了眼泪并磨砺了牙齿,并与当局和用户协调了更新Linux内核和Kubernetes集群的时间。 在提供服务时可能会停机。
这种情况不只是可笑的,不是吗? 整个社区都清楚这种方法行不通。 经过强烈的决定,Kubernetes开发人员宣布新的存储插件将不再被内核接受。 正如我们已经知道的,在其他所有方面,在Flexvolume插件的实现中都发现了许多缺点...
一劳永逸,最后一个为Kubernetes中的卷添加的插件CSI被调用,以解决持久数据仓库的问题。
Kubernetes 1.9中宣布了其Alpha版本,通常称为树外CSI卷插件。
容器存储接口,或CSI 3000旋转!
首先,我想指出的是,CSI不仅是一个卷插件,而且是
创建用于与数据仓库一起使用的自定义组件的真实
标准 。 假定诸如Kubernetes和Mesos之类的容器编排系统应“学习”如何使用根据此标准实现的组件。 现在,Kubernetes已经了解了。
Kubernetes中CSI插件的设备是什么? CSI插件可与第三方开发人员编写的特殊驱动程序(
CSI驱动程序 )一起使用。 Kubernetes中的CSI驱动程序至少应包含两个组件(荚):
- 控制器 -管理外部永久性存储。 它被实现为使用
StatefulSet
原语的gRPC服务器。 - 节点 -负责将持久性存储安装到群集节点。 它也被实现为gRPC服务器,但是使用了
DaemonSet
原语。
Kubernetes CSI插件工作流程例如,您可以从文章“
了解CSI ”中
了解CSI的其他一些详细信息,该文章
是我们一年前发布的
译文 。
这种实现的优点
- 对于基本的事情-例如,为节点注册驱动程序-Kubernetes开发人员实现了一组容器。 您不再需要像使用Flexvolume插件一样自行创建具有功能的JSON响应。
- 现在,我们不再“滑动”可执行文件的节点,而是在集群中布置窗格。 这就是我们最初对Kubernetes的期望:所有进程都发生在使用Kubernetes原语部署的容器内。
- 要实现复杂的驱动程序,您不再需要开发RPC服务器和RPC客户端。 我们的客户是由Kubernetes开发人员实现的。
- 与通过命令行参数传递参数相比,传递参数以与gRPC协议一起使用要方便,灵活且可靠得多。 要了解如何通过添加标准化的gRPC方法向CSI添加对卷使用量指标的支持,您可以查看我们对vsphere-csi驱动程序的拉取请求 。
- 通信是通过IPC套接字进行的,因此无论kubelet pod是否发送请求,都不会感到困惑。
此列表会让您想起什么吗? CSI的优点是
解决了在开发Flexvolume插件时没有考虑到的
问题 。
结论
CSI作为实现用于与数据仓库交互的自定义插件的标准,已经被社区广泛接受。 此外,由于其优势和多功能性,甚至为Ceph或AWS EBS之类的存储库也创建了CSI驱动程序,在第一个Kubernetes版本中添加了用于工作的插件。
在2019年初,
不推荐使用树内插件。 计划继续支持Flexvolume插件,但是不会为其开发新功能。
我们自己已经有使用ceph-csi,vsphere-csi的经验,并准备添加到此列表中! 到目前为止,CSI爆炸式地处理分配给它的任务,在那里我们拭目以待。
不要忘记,所有新事物都是经过深思熟虑的!
聚苯乙烯
另请参阅我们的博客: