在上期 《云存储硬核技术内幕——(30) 七位数年终奖背后的故事》中,我们讲了一个“找到抓手,洞悉痛点,抽离底层逻辑,选择赛道,拉通资源,有效对焦,形成闭环,复刻商业模式”的故事。
当然,我们还给大家展示了在kubernetes的源代码中,第三方存储驱动的位置。由于这种写在kubernetes源代码中的驱动是在代码树中的,因此,我们管这种驱动叫做in-tree。
在上期的末尾,我们遗留的问题是,如果子虚期望把腾讯云的CBS (Cloud Block Storage)接入到kubernetes,又不想在github上提交对kubernetes源码的侵入式修改,有没有好的方案呢?
Kubernetes 从2018年的1.9版本起,就提供了这一机制,到2019年的1.13版本正式GA。这种机制叫做CSI (Container Storage Interface)。
在Kubernetes的文档
https://kubernetes.io/blog/2019/01/15/container-storage-interface-ga/
中指出,通过CSI机制,第三方存储可以为kubernetes提供一个插件,就能让kubernetes在PV或StorageClass中,调用第三方存储的接口,进行持久化卷的分配。
那么,CSI需要实现哪些功能呢?
让我们回到程序员们的根据地——Github,分析一份CSI插件的代码。
以我们学习过的Ceph为例,Ceph的Kubernetes存储驱动虽然在Kubernetes中以intree方式提供了,但考虑到长远演进,Ceph也为Kubernetes提供了CSI方式的驱动插件:
https://github.com/ceph/ceph-csi/
我们可以通过分析它来看一看,CSI需要做些什么。
在小说中,英雄豪杰会面首先要报上姓名,如长坂桥头的张飞:
“燕人张飞在此,手下不斩无名之将!”
类似地,Kubernetes的CSI插件也需要提供这么一个功能,叫做Identity Service。
在这里可以找到它的实现:
https://github.com/ceph/ceph-csi/blob/devel/internal/csi-common/identityserver-default.go
Indentity Service实现了三个接口:GetPluginInfo, GetPluginCapabilities和Probe,实现了“报上名来”的功能。
当然,CSI的核心功能实际上是Controller Service和Node Service。
我们在前文提到,无论是PV还是StorageClass,需要使用外部持久化存储,首先需要创建一个卷。
创建卷的动作,在CSI中叫做CreateVolume;
与其对应地,销毁一个卷为DeleteVolume;
存储中常见的卷扩容、快照、擦除、列出所有卷、获取可用空间大小等功能,都是在Controller Service中实现。
Ceph的Controller Service在这里实现:
https://github.com/ceph/ceph-csi/blob/devel/internal/csi-common/controllerserver-default.go
我们发现,在这个文件中,ListVolumes, GetCapacity, CreateSnapshot, DeleteSnapshot和 ListSnapshots等函数,返回的都是
return nil, status.Error(codes.Unimplemented, "")
这实际上是因为Ceph的CSI插件尚不完善,暂时没有支持这些方法。
而Node Service实现的则是Pod侧对CSI提供的卷的操作。
例如这里实现的:
https://github.com/ceph/ceph-csi/blob/devel/internal/csi-common/nodeserver-default.go
NodeGetInfo: Node上获取卷的信息;
NodeGetCapabilities:Node上获取存储池总容量;
NodeGetVolumeStats:Node上获取卷状态;
……
果然,在分析了Github上的代码之后,我们才明白CSI到底实现了什么。
那么,CSI的这些函数,或者说,方法,是如何被kubernetes调用的呢?
请看下回分解。
这期我们再接着上期的段子讲一个段子:
X老师的夫人问X老师:你这么晚回来干什么去了?
X老师:我晚上去与周边对等主体共同对审美客体进行审美产生生理快感并升华成为精神上的愉悦感。
夫人拿出鸡毛掸:说人话!
X老师:我跟朋友们喝酒去喝得很开心。
同学们,你们看懂了吗?