百摩网
当前位置: 首页 生活百科

kubernetes最大支持多少节点(记一次kubernetes集群异常)

时间:2023-06-28 作者: 小编 阅读量: 3 栏目名: 生活百科

masternode中最重要的当属apiserver组件,它负责处理所有请求,并持久化状态到etcd。官方建议在多个apiserver前面部署一个LB进行负载均衡,当其中一台apiserver发生故障之后,LB自动将流量切换到其他实例上面。所以当LB发生故障时,集群中所有的node都会变为notReady状态,进而导致大规模的pod驱逐。定位问题集群恢复之后,发现有故障通报LB发生了故障,联系了相关同学发现时间点刚好相符,怀疑是因为LB异常导致kubelet无法连接apiserver。

kubernetes最大支持多少节点?来源:小米云技术ID:mi-cloud-tech,我来为大家科普一下关于kubernetes最大支持多少节点?以下内容希望对你有帮助!

kubernetes最大支持多少节点

来源:小米云技术

ID:mi-cloud-tech

作者:高荣

背 景

kubernetes是master-slave结构,master node是集群的大脑,当master node发生故障时整个集群都"out of control"。master node中最重要的当属apiserver组件,它负责处理所有请求,并持久化状态到etcd。一般我们会部署多份apiserver实现高可用。官方建议在多个apiserver前面部署一个LB进行负载均衡,当其中一台apiserver发生故障之后,LB自动将流量切换到其他实例上面。这样虽然简单,但是也引入了额外的依赖,如果LB发生故障将会导致全部apiserver不可用。我们知道在kubernetes中node节点上kubelet与apiserver心跳超时后,controller-manager会将该node状态置为notReady,随后驱逐其上的pod,使这些pod在其他地方重建。所以当LB发生故障时,集群中所有的node都会变为notReady状态,进而导致大规模的pod驱逐。

故 障 发 生

无独有偶,这样的事情偏偏被我们碰到了,接到线上大量node not ready的报警后,立刻上线查看,发现所有的node kubelet都报如下错误:

E0415 17:03:11.351872 16624 kubelet_node_status.go:374] Error updating node status, will retry: error getting node "k8s-slave88": Get https://10.13.10.12:6443/api/v1/nodes/k8s-slave88?resourceVersion=0&timeout=5s: net/http: request canceled (Client.Timeout exceeded while awaiting headers)E0415 17:03:16.352108 16624 kubelet_node_status.go:374] Error updating node status, will retry: error getting node "k8s-slave88": Get https://10.13.10.12:6443/api/v1/nodes/k8s-slave88?timeout=5s: net/http: request canceled (Client.Timeout exceeded while awaiting headers)E0415 17:03:21.352335 16624 kubelet_node_status.go:374] Error updating node status, will retry: error getting node "k8s-slave88": Get https://10.13.10.12:6443/api/v1/nodes/k8s-slave88?timeout=5s: net/http: request canceled (Client.Timeout exceeded while awaiting headers)E0415 17:03:26.352548 16624 kubelet_node_status.go:374] Error updating node status, will retry: error getting node "k8s-slave88": Get https://10.13.10.12:6443/api/v1/nodes/k8s-slave88?timeout=5s: net/http: request canceled (Client.Timeout exceeded while awaiting headers)E0415 17:03:31.352790 16624 kubelet_node_status.go:374] Error updating node status, will retry: error getting node "k8s-slave88": Get https://10.13.10.12:6443/api/v1/nodes/k8s-slave88?timeout=5s: net/http: request canceled (Client.Timeout exceeded while awaiting headers)E0415 17:03:31.352810 16624 kubelet_node_status.go:366] Unable to update node status: update node status exceeds retry count

日志中显示的10.13.10.12是LB的地址。通过这个日志判断是kubelet连接apiserver失败,初步怀疑是网络故障,手动telnet 10.13.10.12 6443后发现一切正常,这就比较奇怪了,明明网络通信正常,kubelet为什么连不上apiserver?

赶紧用tcpdump抓包分析了一下,发现kubelet不断地给apiservre发送包却没有收到对端的ACK,登录master查看apiserver服务也一切正常。后来同事发现重启kubelet就好了,为了尽快解决问题只能把kubelet全部重启了,后面再慢慢定位问题。

定 位 问 题

集群恢复之后,发现有故障通报LB发生了故障,联系了相关同学发现时间点刚好相符,怀疑是因为LB异常导致kubelet无法连接apiserver。

经过沟通后发现:LB会为其转发的每一个connection维护一些数据结构,当新的一台LB server上线之后会均摊一部分原来的流量,但是在其维护的数据结构中找不到该connection的记录就会认为这个请求非法,直接DROP掉。类似的事确实还发生不少,在kubernetes的isuse里有不少这样的案例,甚至需要公有云的的LB也会有这样的问题。例如:kubernetes#41916,kubernetes#48638,kubernetes-incubator/kube-aws#598

大概明白原因之后,push LB的同学改进的同时,kubelet也应该做一些改进:当kubelet连接apiserver超时之后,应该reset掉连接,进行重试。简单做了一个测试,使用iptables规则drop掉kubelet发出的流量来模拟网络异常。

首先确保kubelet与apiserver连接正常,执行netstat -antpl | grep 6443可以看到kubelet与apiserver 10.132.106.115:6443连接正常:

[root@c4-jm-i1-k8stest03 ~]# netstat -antpl |grep kubelettcp 0 0 127.0.0.1:10248 0.0.0.0:* LISTEN 23665/./kubelet tcp 0 0 10.162.1.26:63876 10.132.106.115:6443 ESTABLISHED 23665/./kubelet tcp6 0 0 :::4194 :::* LISTEN 23665/./kubelet tcp6 0 0 :::10250 :::* LISTEN 23665/./kubelet tcp6 0 0 :::10255 :::* LISTEN 23665/./kubelet tcp6 0 0 10.162.1.26:10250 10.132.1.30:61218 ESTABLISHED 23665/./kubelet

此时执行

iptables -I OUTPUT -p tcp --sport 63876 -j DROP

将kubelet发出的包丢掉,模拟网络故障,此时可以看到netstat的输出中该连接的Send-Q正在逐步增加,并且kubelet也打印出日志显示无法连接:

[root@c4-jm-i1-k8stest03 ~]# netstat -antpl |grep kubelettcp 0 0 127.0.0.1:10248 0.0.0.0:* LISTEN 23665/./kubelet tcp 0 928 10.162.1.26:63876 10.132.106.115:6443 ESTABLISHED 23665/./kubelet

连接被hang住了,重启kubelet之后,一切又恢复了。

这个现象和当时发生故障的情况一模一样:连接异常导致kubelet心跳超时,重启kubelet后会新建连接,恢复正常心跳。因为我们当前采用的kubernetes版本是v1.10.2,下载master分支的代码编译试了下,也是有这个问题的,感觉这个问题一直存在。

艰 难 修 复

接下来就是怎么修复这个问题了。网上找了一下相关的issue,首先找到的是kubernetes/client-go#374这个issue,上面描述的情况和我们碰到的很相似,有人说是因为使用了HTTP/2.0协议(以下简称h2),查找了一下kubelet的源码,发现kubelet默认是使用h2协议,具体的代码实现在SetTransportDefaults这个函数中。

可以通过设置环境变量DISABLE_HTTP2来禁用h2,简单验证了一下,显式设置该环境变量禁用h2后,让连接使用http1.1确实没有这个问题了。

查阅文档发现这是http1.1与http2.0的差异:在http1.1中,默认采用keep-alive复用网络连接,发起新的请求时,如果当前有闲置的连接就会复用该连接,如果没有则新建一个连接。当kubelet连接异常时,老的连接被占用,一直hang在等待对端响应,kubelet在下一次心跳周期,因为没有可用连接就会新建一个,只要新连接正常通信,心跳包就可以正常发送。

在h2中,为了提高网络性能,一个主机只建立一个连接,所有的请求都通过该连接进行,默认情况下,即使网络异常,他还是重用这个连接,直到操作系统将连接关闭,而操作系统关闭僵尸连接的时间默认是十几分钟,具体的时间可以调整系统参数:

net.ipv4.tcp_retries2, net.ipv4.tcp_keepalive_time, net.ipv4.tcp_keepalive_probes, net.ipv4.tcp_keepalive_intvl

通过调整操作系统断开异常连接的时间实现快速恢复。

h2主动探测连接故障是通过发送Ping frame来实现,这是一个优先级比较高并且payload很少的包,网络正常时是可以快速返回,该frame默认不会发送,需要显式设置才会发送。在一些gRPC等要求可靠性比较高的通信框架中都实现了Ping frame,在gRPC On HTTP/2: Engineering A Robust, High Performance Protocol中谈到:

The less clean version is where the endpoint dies or hangs without informing the client. In this case,TCP might undergo retry for as long as 10 minutes before the connection is considered failed.Of course, failing to recognize that the connection is dead for 10 minutes is unacceptable.

gRPC solves this problem using HTTP/2 semantics:when configured using KeepAlive,gRPC will periodically send HTTP/2 PING frames.These frames bypass flow control and are used to establish whether the connection is alive.

If a PING response does not return within a timely fashion,gRPC will consider the connection failed,close the connection,and begin reconnecting (as described above)

可以看到gRPC同样存在这样的问题,为了快速识别故障连接并恢复采用了Ping frame。但是目前kubernetes所建立的连接中并没有实现Ping frame,导致了无法及时发现连接异常并自愈。

社区那个issue已经开了很长时间好像并没有解决的痕迹,还得自己想办法。我们知道一个http.Client本身其实只做了一些http协议的处理,底层的通信是交给Transport来实现,Transport决定如何根据一个request返回对应的response。在kubernetes client-go中关于Transporth2的设置只有这一个函数。

// SetTransportDefaults applies the defaults from http.DefaultTransport// for the Proxy, Dial, and TLSHandshakeTimeout fields if unsetfunc SetTransportDefaults(t *http.Transport) *http.Transport { t = SetOldTransportDefaults(t) // Allow clients to disable http2 if needed. if s := os.Getenv("DISABLE_HTTP2"); len(s) > 0 { klog.Infof("HTTP2 has been explicitly disabled") } else { if err := http2.ConfigureTransport(t); err != nil { klog.Warningf("Transport failed http2 configuration: %v", err) } } return t}

只是调用了http2.ConfigureTransport来设置transport支持h2。这一句代码似乎太过简单,并没有任何Ping frame相关的处理逻辑。查了下golang标准库中Transport与Pingframe相关的方法。

令人遗憾的是,当前golang对于一个tcp连接的抽象ClientConn已经支持发送Ping frame,但是连接是交由连接池clientConnPool管理的,该结构是个内部的私有结构体,我们没法直接操作,封装连接池的Transport也没有暴露任何的接口来实现设置连接池中的所有连接定期发送Ping frame。如果我们想实现这个功能就必须自定义一个Transport并实现一个连接池,要实现一个稳定可靠的Transport似乎并不容易。只能求助golang社区看有没有解决方案,提交了一个issue后,很快就有人回复并提交了PR,查看了一下,实现还是比较简单的,于是基于这个PR实现了clinet-go的Ping frame的探测。

峰 回 路 转

开发完毕准备上线的时候,想趁这次修复升级一下kubernetes版本到v1.10.11,一般patch release是保证兼容的。在测试v1.10.11的时候惊奇的发现,即使不改任何代码,这个问题也没办法复现了。说明在v1.10.2中是有问题的,在v1.10.11中恢复了,接着在master中又引入了这个问题,看来还得需要仔细阅读一下这部分代码了,到底是发生了什么。

经过阅读代码,发现这个逻辑曾经被修复过,参考下方链接:

https://github.com/kubernetes/kubernetes/pull/63492

并且backport到1.10.3的代码中,当连接异常时会会调用closeAllConns强制关闭掉所有的连接使其重建。

随后又引入了regression,将closeAllConns置为nil,导致连接无法正常关闭。

明白了这个逻辑之后修改就简单了,将closeAllConns再置为正确的值即可,给官方提交了一个pr,官方很乐意就接受了,并backport到了1.14版本中。至此这个就算完全修复了,当然可以通过上文提到的给h2增加Ping frame的方式解决该问题,这是这种方案可能比较复杂,修复时间比较长。

参考链接

1、https://github.com/kubernetes/kubernetes/issues/41916

2、https://github.com/kubernetes/kubernetes/issues/48638

3、https://github.com/kubernetes-incubator/kube-aws/issues/598

4、https://github.com/kubernetes/client-go/issues/374

5、https://github.com/kubernetes/apimachinery/blob/b874eabb9a4eb99cef27db5c8d06f16542580cec/pkg/util/net/http.go#L109-L120

6、https://www.cncf.io/blog/2018/08/31/grpc-on-http-2-engineering-a-robust-high-performance-protocol/

7、https://github.com/kubernetes/kubernetes/pull/63492

8、https://github.com/kubernetes/kubernetes/pull/71174

9、https://github.com/golang/go/issues/31643

10、https://github.com/kubernetes/kubernetes/pull/78016

我们整理了一个学习知识库,可以了解看一下:

【超全整理】《Linux云计算从入门到精通》系列实战笔记全放送 | Linux运维部落​

www.magedu.com

希望大家有所帮助,祝愿大家学有所成。获取更多技术知识点 v156 5219 9186,欢豆在线解答哦~

    推荐阅读
  • 乐理音阶符号(乐理知识变音记号)

    用来表示升高或者降低基本音级的记号叫做变音记号,这些记号都记在音符符头的左边。表示其所在的线或间上面的音,以及其相同音名的音。②用作临时升降记号,表示临时改变某个音的具体音高,如果该小节不再强调变化,变音记号标记过的音都要保持临时变化。为了提醒废除前面所用的临时记号,有时在小节线后面加上另外的临时记号。

  • q版情侣头像超萌一对(你的头像换了吗)

    大家好,我是颖子。我一来到这里,就亲手在打造这里的环境,以前是废墟一片,如今让我建成一个家的感觉,这里有树,有花,有草,我还自己挖了一个大澡堂,是天然的那种。就像这里是我锻炼身体的好去处。38张可爱卡通Q萌情侣签名头像,你喜欢吗?喜欢本期头像可点我,定制设计哦!

  • 红色的对比色(红色的对比色介绍)

    我们一起去了解并探讨一下这个问题吧!红色的对比色红色的对比色是绿色。对比色的标准一般是根据24色相环得出的,24色相环指的是一个标注了24种颜色的圆环,在24色相环中,相距120度至180度之间的两种颜色称之为对比色。对比色是人体的视觉感官所产生的一种生理现象,对比色具有对抗性,一般看到对比色距离很近的时候一般会容易给人一种强烈的排斥感。

  • 诺基亚ta1099是什么型号(诺基亚ta1009是什么型号)

    诺基亚ta1099的手机型号为诺基亚X6,在千元机中还是有着不错的性价比。诺基亚ta1099是什么型号诺基亚ta1099的型号是诺基亚X6。诺基亚X6搭载骁龙636处理器,预装Android8.1.0系统和拥有6GB内存,配有5.8英寸FHD+分辨率的19:9刘海屏。上述就是关于诺基亚ta1099是什么型号的内容介绍了,希望能对小伙伴们有所帮助。

  • 金针菇番茄做法大全家常(金针菇炒番茄好吃不怕胖)

    金针菇炒番茄好吃不怕胖番茄和金针菇可以算的上是一对十分优秀的搭档了番茄酸甜,金针菇鲜嫩,这两样炒一盘,鲜美开胃,我家经常这样炒,儿子十分爱吃昨天在菜场顺手买了一张豆皮,把它切成细条,放入锅中和金针菇、番茄一起炒,真是太美味。

  • 手机电池使用小妙招(手机电池使用小常识)

    跟着小编一起来看一看吧!通常手机电池充电1000次,就会造成电池严重不耐用。12V锂电池充电次数和衰减的关系说明12V锂电池应用及其普遍,手机及数码产品、平板电脑及笔记本、电动工具、电动自行车、电动汽车、后倍电源及储能等各个领域。锂电池的类型也多种多样。

  • 轮毂熏黑能过年检吗 轮毂烤漆影响年检吗

    一般来说,只改变汽车轮毂的颜色,不改变其型号,就可以通过年检。对于变色规定,只要不超过整车的30%,就是合法的。如果不合格,则必须修复并重新检测。

  • 天舞纪电视剧免费完整版西瓜影院(天舞纪免费手机全集)

    李玄将再次迎来严峻的考验;萧凤鸣被龙皇精魂控制导致黑化,与云杉公主的感情也开始由甜转虐;李玄、苏犹怜、御风穆的三角关系降至冰点,酥梨CP究竟何去何从。情场失意的李玄买醉后与苏犹怜冷言对抗,身负家国重任的苏犹怜利用李玄,却未能解除龙皇封印。而李玄在父亲去世后大闹皇宫被抓,甚至失手打伤苏犹怜,暴虐桥段即将上演,李玄和苏犹怜能否打破隔阂原谅彼此,令人期待。

  • 小企业在快手怎么推广(有什么优势)

    进入快手界面,选择左上角符号弹框中选择“设置”,我来为大家讲解一下关于小企业在快手怎么推广?跟着小编一起来看一看吧!弹框中选择“设置”。阅读相关提示,点击“继续”。了解功能用法,点击“确定”。确认用户协议,选择想要上头条热门的视频。选择所需要的服务,点击“支付”。跳转到支付界面后,点击“立即支付”即可快速上头条热门。

  • 怀孕以后都需要啥准备(怀孕需要做好哪些方面的准备)

    怀孕前的准备工作1:补充叶酸即使日常饮食均衡,也很难保证你从中能获得所有必需的营养物质。中国育龄妇女体内叶酸缺乏的现象比较普遍,这一点应该引起充分的重视。大量研究显示,吸烟和毒品会导致流产、早产和低体重出生儿。此外,研究还表明,吸烟可能会影响生殖能力和男性精子数量。怀孕前的准备工作3:拒绝咖啡因研究显示,摄入过多的咖啡因会阻碍铁的吸收,同时,也会增加胎死宫内的风险。