当 Kubernetes 还是 v1.0.0 时,就有卷插件了。 它们需要将系统连接到 Kubernetes 以存储持久(永久)容器数据。 他们的数量很少,最早的存储提供商包括 GCE PD、Ceph、AWS EBS 等。
这些插件与 Kubernetes 一起提供,这就是它们得名的原因 - in-tree。 然而,对于许多人来说,现有的此类插件集是不够的。 工匠们使用补丁向 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
,并且能够实时调整卷大小,您可以熟悉
以下是使用 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 的 pod,本地卷沿着查找 Flexvolume 驱动程序的路径附加到该 pod。 成功创建后,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 脚本示例:
#!/bin/sh
set -o errexit
set -o pipefail
VENDOR=k8s.io
DRIVER=nfs
driver_dir=$VENDOR${VENDOR:+"~"}${DRIVER}
if [ ! -d "/flexmnt/$driver_dir" ]; then
mkdir "/flexmnt/$driver_dir"
fi
cp "/$DRIVER" "/flexmnt/$driver_dir/.$DRIVER"
mv -f "/flexmnt/$driver_dir/.$DRIVER" "/flexmnt/$driver_dir/$DRIVER"
while : ; do
sleep 3600
done
重要的是不要忘记复制操作 不是原子的。 kubelet 很有可能在其配置过程完成之前开始使用驱动程序,从而导致系统崩溃。 正确的方法是首先以不同的名称复制驱动程序文件,然后使用原子重命名操作。
在 Rook Operator 中使用 Ceph 的示意图:图中的 Flexvolume 驱动程序位于 Rook 代理内部
使用 Flexvolume 驱动程序时的下一个问题是对于集群节点上的大多数存储 必须安装必要的软件 (例如,Ceph 的 ceph-common 包)。 最初,Flexvolume 插件并不是为了实现如此复杂的系统而设计的。
这个问题的原始解决方案可以在 Rook 操作符的 Flexvolume 驱动程序实现中看到:
驱动程序本身被设计为 RPC 客户端。 用于通信的IPC套接字与驱动程序本身位于同一目录中。 我们记得,要复制驱动程序文件,最好使用 DaemonSet,它将目录与驱动程序作为卷连接起来。 复制必要的 rook 驱动程序文件后,该 pod 不会消失,而是通过附加卷作为成熟的 RPC 服务器连接到 IPC 套接字。 ceph-common 软件包已安装在 pod 容器内。 IPC 套接字确保 kubelet 将与位于同一节点上的 pod 进行准确通信。 一切巧妙的事情都很简单!...
再见,我们深情的...树内插件!
Kubernetes 开发人员发现核心内用于存储的插件数量为 XNUMX 个。 其中每一项的更改都会以某种方式贯穿整个 Kubernetes 发布周期。
事实证明,要使用新版本的存储插件, 您需要更新整个集群。 除此之外,你可能会感到惊讶的是,新版本的 Kubernetes 会突然与你正在使用的 Linux 内核变得不兼容......所以你擦干眼泪,咬紧牙关,与你的管理层和用户协调时间更新Linux内核和Kubernetes集群。 提供服务可能会出现停机。
这种情况不仅仅是滑稽,你不觉得吗? 整个社区都清楚地意识到这种方法不起作用。 Kubernetes 开发人员故意宣布,内核将不再接受用于处理存储的新插件。 此外,正如我们所知,在 Flexvolume 插件的实施过程中发现了一些缺陷......
Kubernetes 中最新添加的卷插件 CSI 被要求一劳永逸地解决持久数据存储的问题。 它的 alpha 版本,更完整地称为 Out-of-Tree CSI Volume Plugins,在发行版中宣布
容器存储接口,或者CSI 3000旋转杆!
首先,我想指出CSI不仅仅是一个卷插件,而是一个真正的
Kubernetes 中的 CSI 插件的结构是怎样的? CSI 插件与特殊驱动程序配合使用(CSI 驱动程序)由第三方开发人员编写。 Kubernetes 中的 CSI 驱动程序至少应包含两个组件(pod):
- 控制器 — 管理外部持久存储。 它被实现为 gRPC 服务器,并使用原语
StatefulSet
. - Node — 负责将持久存储安装到集群节点。 它也被实现为 gRPC 服务器,但它使用原语
DaemonSet
.
CSI 插件如何在 Kubernetes 中工作
您可以了解 CSI 工作的其他一些细节,例如,从文章“
这种实施方式的优点
- 对于诸如为节点注册驱动程序之类的基本操作,Kubernetes 开发人员实现了一组容器。 您不再需要像 Flexvolume 插件那样自己生成具有功能的 JSON 响应。
- 我们现在将 Pod 上传到集群,而不是将可执行文件“滑动”到节点上。 这是我们最初对 Kubernetes 的期望:所有进程都发生在使用 Kubernetes 原语部署的容器内。
- 您不再需要开发 RPC 服务器和 RPC 客户端来实现复杂的驱动程序。 该客户端是由 Kubernetes 开发人员为我们实现的。
- 通过 gRPC 协议传递参数比通过命令行参数传递参数更加方便、灵活和可靠。 要了解如何通过添加标准化 gRPC 方法来向 CSI 添加对卷使用指标的支持,您可以阅读:
我们的拉取请求 对于 vsphere-csi 驱动程序。 - 通信通过 IPC 套接字进行,以免混淆 kubelet 是否将请求发送到正确的 pod。
这份清单让你想起什么了吗? CSI的优点是 解决同样的问题,开发 Flexvolume 插件时没有考虑到这一点。
发现
CSI 作为实现与数据仓库交互的自定义插件的标准受到了社区的热烈欢迎。 此外,由于其优势和多功能性,甚至为 Ceph 或 AWS EBS 等存储系统创建了 CSI 驱动程序,在 Kubernetes 的第一个版本中添加了用于使用这些系统的插件。
2019年初,树内插件
我们自己已经拥有使用 ceph-csi、vsphere-csi 的经验,并准备将其添加到此列表中! 到目前为止,CSI 正在出色地处理分配给它的任务,但我们将拭目以待。
不要忘记,一切新事物都是对旧事物的良好反思!
PS
另请阅读我们的博客:
来源: habr.com