前言
k8s 非常厉害的地方就在于可扩展性,而存储领域,支持flexvolume 和 csi 两种方式来进行扩展。今天主要讲下flexvolume。FlexVolume 是 Kubernetes v1.8+ 支持的一种存储插件扩展方式。类似于 CNI 插件,它需要外部插件将二进制文件放到预先配置的路径中(如 /usr/libexec/kubernetes/kubelet-plugins/volume/exec/),并需要在系统中安装好所有需要的依赖。可以想到,这是一种out-tree的扩展方式,不需要新增加一种存储插件,去更改k8s的源码。
FlexVolume 接口
官方提供了一些接口,在我们实现自定义存储插件的时候,需要实现部分接口,之所以说部分,主要是看自己的需求。比如我在实现动态hostpath(主机路径包含podid)的时候,就只实现了init和mount和unmount三个接口而已。
FlexVolume 的接口包括
- init:kubelet/kube-controller-manager 初始化存储插件时调用,插件需要返回是否需要要 attach 和 detach 操作
- attach:将存储卷挂载到 Node 上
- detach:将存储卷从 Node 上卸载
- waitforattach: 等待 attach 操作成功(超时时间为 10 分钟)
- isattached:检查存储卷是否已经挂载
- mountdevice:将设备挂载到指定目录中以便后续 bind mount 使用
- unmountdevice:将设备取消挂载
- mount:将存储卷挂载到指定目录中
- umount:将存储卷取消挂载
Driver output
Flexvolume希望驱动程序以下列格式回复操作状态
{
"status": "<Success/Failure/Not supported>",
"message": "<Reason for success/failure>",
"device": "<Path to the device attached. This field is valid only for attach & waitforattach call-outs>"
"volumeName": "<Cluster wide unique name of the volume. Valid only for getvolumename call-out>"
"attached": <True/False (Return true if volume is attached on the node. Valid only for isattached call-out)>
"capabilities": <Only included as part of the Init response>
{
"attach": <True/False (Return true if the driver implements attach and detach)>
}
}
与kubelet 的关系
前面讲到自定义的存储插件是放到/usr/libexec/kubernetes/kubelet-plugins/volume/exec/下,具体目录是/usr/libexec/kubernetes/kubelet-plugins/volume/exec/<vendor~driver>/<driver>。
在pod的spec中申明用到了你自定义的插件后,格式为 <vendor~driver>/<driver>,实际上是kubelet 按照接口规范去调用对应插件。
所以需要注意以下几点:
- 在debug的过程中,FlexVolume的日志需要在kubelet.log中查看
- 部署方式一般都是daemonset。这样可以保证每台node 都会存在自定义插件。
从k8s1.8 开始支持了动态插件发现,flexvolume支持动态检测驱动程序的功能。系统运行时,可以安装,升级/降级和卸载驱动程序,而不是在系统初始化时要求驱动程序存在或必须重新启动kubelet或控制器管理器。
官方demo
官方提供一些demo,大家可以参考一下。
如何解决kubelet 经常发生找不到flexvolume 的bug
在实战的过程中,我们的经常在使用自定义插件的时候,出现诸如一下报警:
Unable to mount volumes for pod "hermes-devices-push-myd-79f4577cc9-dqx9v_cbs(a0bc2b86-d140-11e9-9a8e-fa163e4660a0)": timeout expired waiting for volumes to attach or mount for pod "cbs"/"hermes-devices-push-myd-79f4577cc9-dqx9v". list of unmounted volumes=[log-dir]. list of unattached volumes=[log-dir default-token-kf6sr shareit-aksk-aws-conf shareit-aksk-huawei-conf]
其中的log-dir 正是用到了我们的自定义插件。
经过查看kubelet日志,发现,kubelet出现了很多 no volume plugin matched 的错误信息。结合k8s的相关issue和分析kubelet代码发现,这其实是kubelet的一个bug。可惜的是,这个bug一直没有被解决。
当然可以每次发生找不到对应插件的时候,重启kubelet即可。
但终究不是长久之计,通过研究代码,其实动态发现插件的机制是通过inotify实现的,监听了/usr/libexec/kubernetes/kubelet-plugins/volume/exec/目录下的文件变化事件,做对应的处理。所以在有时候我们没法去更改kubelet代码的时候,我们可以在实现自定义插件的时候增加定时refresh的功能。比如我们更改一下对应驱动文件的最后访问时间和修改时间。
有疑问加站长微信联系(非本文作者)