天天看点

Flexvolume 介绍及使用

Prior to CSI, k8s volume plugins have to be “In-tree”, compiled and shipped with core kubernetes binaries. This means, it will require the storage providers to check-in their into the core k8s codebase if they wish to add the support for a new storage system.

在 CSI 之前,k8s 卷插件必须是“In-tree”,编译并随核心 kubernetes 二进制文件一起提供。这意味着,如果他们希望添加对新存储系统的支持,则需要存储提供商将其签入核心 k8s 代码库。

A plugin-based solution, flex-volume, tried to address this issue by exposing the exec based API for external  plugins. Although it also tried to work on the similar notion of being detached with k8s binary, there were several major problems with that approach. Firstly, it needed the root access to the host and master file system to deploy the driver files. 

基于插件的解决方案 flex-volume 试图通过为外部插件公开基于 exec 的 API 来解决这个问题。尽管它也尝试处理与 k8s 二进制分离的类似概念,但这种方法存在几个主要问题。首先,它需要对主机和主文件系统的 root 访问权限来部署驱动程序文件。 

Secondly, it comes with the huge baggage of prerequisites and OS dependencies which are assumed to be available on the host. CSI implicitly solves all these issues by being containerized and using the k8s storage primitives.

其次,它带来了大量的先决条件和操作系统依赖项,假设它们在主机上可用。CSI 通过容器化和使用 k8s 存储原语隐式地解决了所有这些问题。

Flexvolume 是 Volume Plugins 的一个扩展,主要实现 Attach/Detach/Mount/Unmount 这些接口。

我们知道这些功能本是由 Volume Plugins 实现的,但是对于某些存储类型,我们需要将其扩展到 Volume Plugins 以外,所以我们需要把接口的具体实现放到外面。

在下图中我们可以看到,Volume Plugins 其实包含了一部分 Flexvolume 的实现代码,但这部分代码其实只有一个 “Proxy”的功能。

比如当 AD Controller 调用插件的一个 Attach 时,它首先会调用 Volume Plugins 中 Flexvolume 的 Attach 接口,但这个接口只是把调用转到相应的 Flexvolume 的Out-Of-Tree实现上。

Flexvolume是可被 Kubelet 驱动的可执行文件,每一次调用相当于执行一次 shell 的 ls 这样的脚本,都是可执行文件的命令行调用,因此它不是一个常驻内存的守护进程。

Flexvolume 的 Stdout 作为 Kubelet 调用的返回结果,这个结果需要是 JSON 格式。

Flexvolume默认的存放地址为 "/usr/libexec/kubernetes/kubelet-plugins/volume/exec/alicloud~disk/disk"。

[root@master nodeagent~uds]# pwd
/usr/libexec/kubernetes/kubelet-plugins/volume/exec/nodeagent~uds
[root@master nodeagent~uds]# ls
uds      
Flexvolume 介绍及使用

下面是一个命令格式和调用的实例。

Flexvolume 介绍及使用

Flexvolume 的接口介绍

Flexvolum 包含以下接口:

  • init: 主要做一些初始化的操作,比如部署插件、更新插件的时候做 init 操作,返回的时候会返回刚才我们所说的 DriveCapabilities 类型的数据结构,用来说明我们的 Flexvolume 插件有哪些功能;
  • GetVolumeName: 返回插件名;
  • Attach: 挂载功能的实现。根据 --enable-controller-attach-detach 标签来决定是由 AD Controller 还是 Kubelet 来发起挂载操作;
  • WaitforAttach: Attach 经常是异步操作,因此需要等待挂载完成,才能需要进行下面的操作;
  • MountDevice:它是 mount 的一部分。这里我们将 mount 分为 MountDevice 和 SetUp 两部分,MountDevice 主要做一些简单的预处理工作,比如将设备格式化、挂载到 GlobalMount 目录中等;
  • GetPath:获取每个 Pod 对应的本地挂载目录;
  • Setup:使用 Bind 方式将 GlobalPath 中的设备挂载到 Pod 的本地目录;
  • TearDown、UnmountDevice、Detach实现的是上面一些借口的逆过程;
  • ExpandVolumeDevice:扩容存储卷,由 Expand Controller 发起调用;
  • NodeExpand: 扩容文件系统,由 Kubelet 发起调用。

上面这些接口不一定需要全部实现,如果某个接口没有实现的话,可以将返回结果定义成:

{

"status": "Not supported",

"message": "error message"

}

告诉调用者没有实现这个接口。此外,Volume Plugins 中的 Flexvolume 接口除了作为一个 Proxy 外,它也提供了一些默认实现,比如 Mount 操作。所以如果你的 Flexvolume 中没有定义该接口,该默认实现就会被调用。

在定义 PV 时可以通过 secretRef 字段来定义一些 secret 的功能。比如挂载时所需的用户名和密码,就可以通过 secretRef 传入。

Flexvolume 的挂载分析

从挂载流程和卸载流程两个方向来分析 Flexvolume 的挂载过程。

Flexvolume 介绍及使用

我们首先看 Attach 操作,它调用了一个远端的 API 把我们的 Storage 挂载到目标节点中的某个设备上去。

然后通过 MountDevice 将本地设备挂载到 GlobalPath 中,同时也会做一些格式化这样的操作。

Mount 操作(SetUp),它会把 GlobalPath 挂载 PodPath 中,PodPath 就是 Pod 启动时所映射的一个目录。

下图给出了一个例子,比如我们一个云盘,其 Volume ID 为 d-8vb4fflsonz21h31cmss,在执行完 Attach 和 WaitForAttach 操作之后,就会将其挂载到目标节点上的 /dec/vdc 设备中。执行 MountDevice 之后,就会把上述设备格式化,挂载到一个本地的 GlobalPath 中。而执行完 Mount 之后,就会将 GlobalPath 映射到 Pod 相关的一个子目录中。最后执行 Bind 操作,将我们的本地目录映射到容器中。这样完成一次挂载过程。

Flexvolume 介绍及使用

卸载流程就是一个逆过程。上述过程描述的是一个块设备的挂载过程,对于文件存储类型,就无需 Attach、MountDevice操作,只需要 Mount 操作,因此文件系统的 Flexvolume 实现较为简单,只需要 Mount 和 Unmount 过程即可。

Flexvolume 的代码示例

Flexvolume 介绍及使用

其中主要实现的是 init()、doMount()、doUnmount() 方法。在执行该脚本的时候对传入的参数进行判断来决定执行哪一个命令。

在 Github 上还有很多 Flexvolume 的示例,大家可以自行参考查阅。阿里云提供了一个 Flexvolume 的实现,有兴趣的可以参考一下。(https://github.com/AliyunContainerService/flexvolume)

Flexvolume 的使用

下图给出了一个 Flexvolume 类型的 PV 模板。它和其它模板实际上没有什么区别,只不过类型被定义为 flexVolume 类型。flexVolume 中定义了 driver、fsType、options。

  • driver 定义的是我们实现的某种驱动,比如图中的是 aliclound/disk,也可以是 aliclound/nas 等;
  • fsType 定义的是文件系统类型,比如 "ext4";
  • options 包含了一些具体的参数,比如定义云盘的 id 等。

我们也可以像其它类型一样,通过 selector 中的 matchLabels 定义一些筛选条件。同样也可以定义一些相应的调度信息,比如定义 zone 为 cn-shenzhen-a。