解决pod健康检查问题
很早以前,环境中的pod有时候会遇到健康检查失败的问题,但并没有什么明显表征,且几乎是立马就会恢复。由于这种情况很少发生,且不会对业务造成影响,因此起初并没有人关注该问题。
第1步:查看日志
- Kubernetes worker的系统日志 -- 无异常
- kubelet 日志 -- 无异常
- Containerd 日志 -- 无异常
- CNI 日志 -- 无异常
- 检查最近失败的pod日志 -- 无异常
通过检查相关日志,并没有发现什么异常
第2步:tcpdump
为以防万一,我们检查了TCP中的seq和ack序列号,并没有发现问题。
第3步:ss
每秒调用一次"ss -natp"来查看kubelet进程连接,此时发现失败的连接卡在了SYN-SENT阶段,说明kubelet并没有接收到pod发来的SYN-ACK报文。
第4步:conntrack
在我们的环境中,设定了一个较大的源端口可选范围:
net.ipv4.ip_local_port_range=12000 65001
出现问题的源端口为30XXX或31XXX,非常类似。
第5步:ipvs
根因分析
至此,问题已经明了。当Kubelet初始化一条TCP连接时,会随机选择一个源端口号,例如31055。当TCP SYN到达pod之后,pod会向31055端口号回复一个TCP SYN-ACK报文。当该报文到达IPVS之后,由于已经存在一个端口号为31055的nodeport(Kubernetes loadbalance service,此时会将TCP SYN-ACK报文转发到对应的后端(其他pod,这样就导致Kubelet无法接收到回复的报文,无法建立连接。
解决办法
net.ipv4.ip_local_reserved_ports="30000–32768"
Kubernetes的nodeport保留端口为30000-32767,因此设置的
net.ipv4.ip_local_reserved_ports
为30000–32768
TIPs
net.ipv4.ip_local_port_range
的默认值为32768 60999
,正好和Kubernetes的nodeport保留端口错开,本文中描述的问题的源头也是因为修改了该内核参数,因此非必要不要修改内核参数!