问题起因
近段时间,在工作中,遇到了一个问题:有一套K8S集群在做可靠性验证,在重启上下电之后,发现这个节点上的Pod状态异常。通过kubectl describe查看Pod情况,都是挂卷出错,而kubelet日志中也报了某个CSI插件没有找到。但问题是CSI插件对应的Pod是正常Running状态。那么为什么CSI会找不到呢?于是带着这个问题,研究起了k8s的代码。
代码分析
CSI没有找到,那意味着肯定是有地方储存CSI的数据,相应的有地方去创建/更新CSI的数据。这个咨询CSI业务的开发了解到,CSI注册后会更新csiNode资源,同时node资源上也会有csi的拓扑信息。
另外根据kubelet的日志报错信息:Error calling CSI NodeGetInfo()
找到了CSI注册流程的代码。
CSI注册流程的代码入口在pkg/kubelet/pluginmanager/plugin_manager.go:108 (v1.25.3版本)
首先是Run
方法,这里主要处理了两件事
- 开启了kubelet对
/var/lib/kubelet/plugins_registry
目录的监听,如果有文件更新,会同步更新dsw的缓存 - 开启了reconciler主循环,对比asw和dsw的差异,然后去触发CSI的卸载和注册
reconciler主循环
- 卸载:遍历asw缓存中的插件信息,和dsw做比对。如果出现dsw没有的插件或者信息不一致的插件,则会将该插件卸载
- 注册:遍历dsw缓存中的插件信息,如果asw没有,则会触发注册流程。通过proto文件定义双方的接口,kubelet作为客户端调用CSI Pod服务端实现的接口GetInfo、NodeGetInfo获取插件信息,然后向apiserver注册CSINode、Node信息,并在最后通过NotifyRegistrationStatus通知CSI Pod。
根据个人对代码的理解,绘制了下面的流程图。
文章来源:https://www.toymoban.com/news/detail-487985.html
问题分析
由于kubelet日志中出现了Error calling CSI NodeGetInfo()
的报错日志,那么说明CSI Pod实现的NodeGetInfo方法出现了错误。通过CSI开发分析,是由于需要发请求,而节点刚重启,受网络配置的影响,请求超时了,导致方法报错。
那么又出了一个问题,为什么没有恢复呢?
原因在于在kubelet调用NodeGetInfo方法时,已经将asw缓存更新了,此时dsw和asw缓存一致,kubelet不会再触发卸载、注册流程。
这不合理呀,这里没有真正注册成功啊。
再次走读代码,终于识别到了一个点:kubelet是有通知事件发给CSI Pod的。在校验CSI信息和注册过程中,如果出现异常,kubelet会发一个注册失败的通知给CSI Pod。而在官方的CSI范例中,CSI是会清理自己在/var/lib/kubelet/plugins_registry
目录创建的文件,并退出。因为CSI是一个Daemonset类型部署的Pod,那么在主进程退出之后,K8S会再次部署这个Pod。那么CSI Pod会再次进入CSI注册的主流程,而那个时候,网络就绪了,CSI注册也就会成功。
根据这个信息,向CSI开发确认,他们忽略了通知注册失败的处理,导致注册失败后没有自动恢复。
OK,问题定位清楚了,也趁着这个机会学习了CSI的注册流程。文章来源地址https://www.toymoban.com/news/detail-487985.html
到了这里,关于Kubernetes CSI注册流程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!