在上一篇监控问题排查的文章中(传送门),笔者分析了KubeSphere v3.1.0集成KubeEdge中的边缘监控原理和问题排查思路。那篇文章中,在介绍EdgeWatcher组件时提到了”边缘节点的内网IP需要集群内唯一”这样的限制条件。今天我们就来深入分析一下这个问题,并尝试给各位边缘开发者提供一些解决的建议和思路。

正常场景

在边缘节点加入云端集群时,需要指定”Node Name”和”Internal IP”,顾名思义,就是边缘节点的节点名称和内网IP地址。这里的内网IP地址就是这篇文章的主题,该地址需要在集群内唯一。
KubeSphere在EdgeWatcher中提供了用户指定的内网IP是否被占用的验证功能。验证失败(IP已被占用)的情况下,则不会为该边缘节点提供加入集群的命令行输出。下面两张图展示了验证成功和失败的场景。

验证成功:

验证失败:

可以说,KubeSphere在这一点上已经做的非常用心了,给用户提供了UI的”Validate”按钮和后台API,不管是直接使用还是基于KubeSphere的二次开发都会非常便捷。

非法场景

在上一节中展示了内网IP被占用的结果就是不能加入集群,因为该IP已经被注册在了EdgeWatcher中,不能再被其他边缘节点使用。
那么如果一个IP还没有被注册到EdgeWatcher中,也就是边缘节点没有被真正接入集群时,还是可以跳过这一步验证,将相同内网IP的两个边缘节点加入同一个集群中,制造这个非法的使用场景。这个非法场景带来的问题就是:相同IP的”较早加入集群”的边缘节点在logs exec和metrics的功能上都会失效。即下图的运维功能都是没有数据的。

之前,笔者也在KubeSphere的开发者社区提过这个问题(传送门),同时也和负责边缘模块的社区开发者有过交流,确认了在KubeSphere的产品设计上,内网IP需要管理员或者用户自行按需进行规划,保证不重复。

潜在问题

私有部署的场景下,做到IP的统一规划是比较容易的。那么如果基于KubeSphere的边缘解决方案到了公有云,会怎么样呢?
公有云用户不受规划限制同时并发量比较大,出现”相同IP加入集群”这个问题的概率会非常大。最终会导致部分用户的logs exec和metrics功能失效,大量问题工单随之而来,用户黏度下降。所以公有云场景下,这个问题是必须要解决的,下面我们就详细分析一下问题的根本原因和解决思路。

根本原因

解决问题前还是一样要把问题产生的根本原因摸清楚,这样才能有的放矢地去解决和处理问题。
在上一篇文章中,其实也简要介绍了metrics数据获取在KubeEdge边缘场景下的实现原理:kube-apiserver上的iptables转发给云端的Cloudcore,Cloudcore通过和Edgecore之间的WebSocket通道向边缘端进行消息和数据传递。
logs和exec功能的实现原理和metrics是一样的。下面这张图简要的描述了这几项功能在KubeEdge下的工作流程。

结合上面这张图的cloudcore(KubeEdge云端组件)的红色部分,来解释一下为什么内网IP需要集群内唯一。
边缘节点(edgecore,即KubeEdge边缘组件)在连接到云端集群时,和云端之间会建立一个websocket通道。云端为了后续通过该websocket通道和边缘节点通信,需要将这个通道作为session保存在云端。表现在数据结构上就是一个”内网IP”为key,session(websocket通道)为value的map。
看到这里,各位开发者应该就很容易理解了,如果内网IP相同,则会覆盖较早加入集群的边缘节点的session记录。这时云端去查找”被覆盖了session的边缘节点”上POD的监控和运维数据,肯定是找不到的。
问题的根本原因找到了,解决的思路也就比较明确了,下一小节笔者简单阐述下这个问题的解决思路。
下图是在KubeEdge的边缘场景下,logs功能的时序图,感兴趣的开发者可以进一步了解。

解决思路

上一节梳理清楚了根本原因,解决思路也就比较清晰明了。本着非侵入式的改造原则,尽量少改动KubeSphere和KubeEdge,对上层业务逻辑进行增强和扩展是笔者心目中的最佳选择。
既然根本原因是IP冲突导致session被覆盖,那就很自然的想到提供集群内不重复IP的分配服务,也就是常说的IPAM。在云端的业务逻辑层引入IPAM服务,为用户边缘节点提供集群内唯一的IP分配能力。
同时还需要关注一点的是,IPAM服务分配出来的唯一IP属于内部实现,不能当作”Internal IP”展示给用户。用户看到的边缘节点内网IP地址仍然是用户自行规划和填写的IP,只不过改造后的内网IP不再作为session的key,也不再需要进行冲突查验,只在页面上展示方便用户搜索,提高产品的易用性。
下面就是该思路下的节点加入流程图,供各位开发者参考。

根据上面的流程图,笔者也大概罗列一下上述解决方案,需要修改的点:
1.新建集群内IPAM服务,提供分配,回收IP等功能,注意并发处理。
2.新建业务层节点服务,提供节点名称,展示用IP,唯一IP等持久化能力。
3.修改keadm和edgecore,支持node IP可选
4.修改cloudcore,在节点注册时通过节点名称查询唯一IP,作为Internal IP注册节点。
5.在业务层北向接口隐藏唯一IP(k8s上的internal IP),替换成用户输入的展示IP。

后记

通过对现象和原理的分析,我们提出了在公有云环境下基于KubeSphere的边缘节点IP冲突问题的解决方案。限于笔者的技术能力,有可能还存在着更为简单有效的解决办法,欢迎各位开发者提出宝贵意见,让我们一起把基于KubeSphere的边缘解决方案做大做强。

7 天 后

Kubeedge edgecore在安装时有一个配置项nodeIP,如果没配置,edgecore就取宿主机的真实IP,edgecore把这个IP作为k8s节点的internal IP并通过websocket主通道定时上报到cloudcore,cloudcore收到后就更新进k8s里该node的NodeStatus里作为internal IP。
所以上文中的方案还有一点问题,这里做一点补充:显然除了文中步骤外,还得阻止node在k8s里的internal IP被修改,它只能由IPAM分配来初始化。
解决办法:修改cloudcore源码,收到edgecore上报的internal IP后,不要去更新k8s里对应的internal IP,可以作为external IP与从k8s里查询出来的internal IP一起更新进k8s。还可以再进一步修改edgecore源码将nodeIP改作为external IP上报。这样,node的真实IP也可以在k8s里查到。

    sdghchj 这种方案有个优点就是可以不用新建业务层节点服务,节点名称和external IP的对应关系就在k8s的etcd里面持久化,保持组件的精简,挺好的方案