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

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

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

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,欢豆在线解答哦~

    推荐阅读
  • 兔子喜欢吃什么饲料好(兔子吃什么长得快)

    苜蓿草可以为兔子提供身体所需的钙质,提摩西草和其他草可以作为兔子平时的主粮。草晒干后水分含量减少,可以避免兔子出现呕吐、腹泻等情况。

  • 2023杭州太子湾公园郁金香花展预约时限一览

    2023杭州太子湾公园郁金香花展预约时限预约时限:最多提前一天预约预约数量:按旅游旺季期间太子湾公园上限4.5万人的总流量,实行分时段预约制入园预约时间:全天按每2小时分设为5个预约时段,其中8:00—10:00,10:00-12:00,12:00-14:00,14:00-16:00四个时间段可预约人数为各1万人,16:00-17:00可预约人数为5千人预约入口:为方便游客入园,游客可以通过“杭州

  • 电子签到技术(创意加持玩转电子签到)

    大象手环签到拥有RFID及二维码两类功能手环,可以现场制作,立等可取,不用拉起长队一个个排。这里有作为当下应用十分广泛的社交软件——微信,不仅普及率高也操作简单。由微信作为基础的微信签到相比于前面两种签到方式,用户的参与度更加强,工作人员的签到压力也更加小。与网络媒体类公司相比,选择微信签到往往更能与公司性质相契合。还可与3Dlogo墙串联,扫码签到后,微信头像实时飞入屏幕中组成logo,创意无限。

  • 经常做噩梦的原因和解决方法(经常做噩梦的原因以及解决方法)

    根据国际睡梦研究协会的一项研究,称:重大手术或疾病、痛失爱人的悲伤、遭遇或者目击到袭击、事故等,都会导致噩梦和梦魇。创伤后压力症候群通常是梦魇复发的普遍原因。脂肪含量高的食品。饮酒过量,还会导致梦魇和睡眠不佳,对于那些处于戒酒中的人,梦魇也会时常光顾。此外抽烟也容易使人兴奋,因此一定要改掉睡觉之前抽烟的习惯。

  • 路遥知马力的下一句是什么(关于路遥知马力的下一句介绍)

    路遥知马力,日久见人心本身是一句完整的说辞,意思是走路走得远了,才知道马匹到底怎么样时间长了,才了解一个人的品格,接下来我们就来聊聊关于路遥知马力的下一句是什么?路遥知马力的下一句是什么路遥知马力,日久见人心。

  • 有哪些比较虐的电视剧或电影(这几部真的超推荐)

    有哪些比较虐的电视剧或电影刘恺威、颖儿《千山暮雪》莫绍谦,这个让人又爱又恨的角色。《阿信》为了生计,年仅7岁的阿信被送到木材店当童工。辛苦做工之余,阿信不放过任何一点学习的机会。在“偷钱事件”发生后,阿信逃出木材店,又进入加贺屋米店,在老板娘的严厉督导和训练之下,她逐渐成为米店的得力助手。

  • 达拉非吃5mg对身体会不会有害(想摆脱抬头困难)

    因此,正常适度的夫妻生活,也是避免ED的良策。治疗时夫妻暂时分居以减少刺激,在ED的康复中,妻子对丈夫的理解、关心、鼓励,十分重要。由于全身性疾病所致ED者,应积极治疗原发病。

  • 英文学术论文写作标题(探讨学术论文英文标题的写作原则及修辞策略)

    英文标题的写作虽然可以不拘一格,但应突出主题,服从英语的表达习惯,避免使用中式的英语表达形式。例如,汉语论文主标题与副标题之间一般用破折号,而英文的主标题与副标题之间通常用冒号表示。名词化结构较多地使用抽象名词表达动作和状态,这也是英语表达和汉语表达上的主要差别之一。

  • 仔猪价格高位抬升外购养殖总成本 外购仔猪成本计算

    今日生猪均价较昨日小幅上扬。目前全国范围内生猪均价以四川、浙江等地最高,局部地区甚至达到了20元/公斤。新疆、东北、广东等地是价格低洼地带。近日屠宰企业逐渐增量,市场上生猪供应依然短缺,预计后市猪价将稳定在高位,近期猪价集体保持相对稳定,或浮现短期内价格小幅归升。鉴于成本方面的考虑,仔猪高价位严重抑制了补栏踊跃性。另外二元母猪销售有小幅增添的倾向,预计3月份补栏小高峰或浮现仔猪价格与二元价格的上涨。

  • 明史董应举(申时行状元宰辅)

    仅凭这一点也说明,这位申时行非同一般。但可惜的是,我虽藏有申时行的著作,但对他的藏书事迹却未曾留意,这也正是我未将其列入寻访名单的原因。此墓园占地二百亩,而李根源认为申时行墓园之大,可排在苏州第一;他甚至觉得此墓的规模放在全国范围内,也少有大臣之墓有如此规模者。李根源说苏州一地著名墓园所摆放的石翁仲都是文官像,而唯有申时行墓前是两位武士。