虽然惊天地,但不是人人都会哭泣 ——再论Kubernetes惊天地泣鬼神之大Bug


前几天,朋友圈里疯转了一篇知乎上的帖子,《 Kubernetes 惊天地泣鬼神之大Bug》。很多朋友看到了帖子,纷纷转发给我以表慰问。看到该bug会影响到所有的Kubernetes集群,吓得我赶紧吃根辣条冷静一下。

在线上的巡检邮件梳理了一遍,貌似没发现异常。冷静下来再想想,以我们的集群规模,如果真有这个bug,那么早就该发现了,为何到现在没有爆出来。按照作者的触发方式,我进行了反复的实验,怎么也触发不了。我感觉又不淡定了,啥情况,不是说所有的都会影响么?为啥触发不了?我决定追根溯源,来找找到底为啥会出现这样的问题。
此bug,按照作者的描述,基本上是这样的,对于Kubernetes的某一种资源(不仅是service,其他的资源一样应该也是如此),如果先创建一个最早的对象a,然后再执行一些创建对象的操作,最后再删除那个最早的对象a,此时watch到的删除event中的对象a的resourceVersion不是期待的一个最新最大的resourceVersion,而是最早创建这个对象a时的创建event中的那个老的resourceVersion,从而导致controller-manager的一些回放event的行为。对应到资源service上就是作者描述的service的删除创建被回放,导致其所属的endpoint的消失和重建,从而造成服务的不稳定性。
看完我们立刻在自己的环境上验证,看是否可以重现,结果是未能重现,实验结果如下,所有event的object的resourceVersion都是递增的。

这与作者描述的完全不符合啊。算了,我们还是去源码里找答案吧。
delete时间的resourceVersion是在这里, 在我们的主力版本(1.6)上,该代码是这样的。

这里的入参 watchCacheEvent的event是从etcd中获取的。我们使用命令行从etcd中把这些事件抓取出来。

其中kv对应的是event中的Object,prev_kv对应的是event中的PrevObject。红线圈出的Delete情况的event.preObject的resourceVersion是此对象上一次event的mod_revision,因此会小于Object的resourceVersion。这样我们就可以理解了,在1.6版本中,始终是以当前的Object的resourceVersion作为watch event的resourceVersion,这样所有的event中的resourceVersion都是递增的。这个是没有问题的。
而在1.7+的版本中,该代码是这样的。

这个时候,watch event的resourceVersion变为了PreObject的,这样就必然存在在watch的event的resourceVersion不是严格递增的,当遇到delete事件时,会返回到前面某个event的resourceVersion上去的问题。
之后社区的修复#58547后的代码是这样的。

这里可以看到,watch event的resourceVersion被更新为了event的ResouceVersion,重新保证了event的resourceVersion始终是递增的。
在对比了GitHub上的commit记录,可以看到,此bug是在#46223这个pr中引入的。该pr被合入到 1.7.0之后的版本,可以参见https://github.com/kubernetes/kubernetes/commit/e9e69356e4907fa4d0f45ea7e7768357ba71aba9#diff-dc17590f6b960d2fea2b44de5c0fbc10
而社区在#58547这个pr中修复此问题,也就是说可以对比https://github.com/kubernetes/kubernetes/commit/57998d247df74cc96547158a0b39e5d7bffa271b#diff-dc17590f6b960d2fea2b44de5c0fbc10中之后的版本得以修复。因此受影响的版本主要是介于两个pr之间的版本。
这里我们介绍一下复现的方法,大家可以参照来自检下自己的集群是否需要修复。

Kubernetes版本不断向前发展,这其中会有老的bug被修复,也可能会有新的bug被引入。这些对于社区都是很正常的。但是对于生产环境来说,又是存在着较大的风险的。在实际生产过程中,我们开发了一系列的周边工具和运营监控系统,用以保证集群的稳定。毕竟稳定可靠对于生产环境来说,才是最基本的原则。
本文转载自公众号:TIGCHAT, 点击查看原文


Kubernetes入门与进阶实战培训


本次培训内容包括:Docker基础、容器技术、Docker镜像、数据共享与持久化、Docker三驾马车、Docker实践、Kubernetes基础、Pod基础与进阶、常用对象操作、服务发现、Helm、Kubernetes核心组件原理分析、Kubernetes服务质量保证、调度详解与应用场景、网络、基于Kubernetes的CI/CD、基于Kubernetes的配置管理等, 点击了解具体培训内容

6月22日正式上课,点击阅读原文链接即可报名。

猜你喜欢

转载自blog.csdn.net/m2l0zgssvc7r69efdtj/article/details/80561966