那天早上刚到公司,就收到监控系统告警:K8S集群中某个节点的Calico Pod一直处于CrashLoopBackOff状态。这可不是小事,Calico作为集群的网络插件,它的异常会直接导致整个节点的网络功能瘫痪。我立刻登录集群查看具体情况:
bash复制kubectl get pods -n kube-system -o wide
果然发现node1节点上的calico-node-jv2qv容器不断重启。查看日志时发现了关键报错:
bash复制kubectl logs -f calico-node-jv2qv -n kube-system
日志显示Calico无法连接Kubernetes API Server,具体错误是访问10.233.64.1:443时出现i/o timeout。这个IP地址引起了我的注意——它是Kubernetes默认Service的ClusterIP:
bash复制kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.233.64.1 <none> 443/TCP 45h
这里出现第一个矛盾点:Master节点的Calico运行正常,只有Node节点出现问题。更奇怪的是,这个ClusterIP在Master节点可以正常访问,在Node节点却出现超时。这排除了API Server本身的问题,将矛头指向了节点间的网络通信。
我首先在问题节点上执行了最基础的网络测试:
bash复制ping 10.233.64.1
出乎意料的是ping居然通了!但当我测试端口连通性时:
bash复制telnet 10.233.64.1 443
却得到了连接超时的结果。这种"能ping通但端口不通"的现象非常反常,因为通常网络设备要么全通要么全不通。这提示我们可能遇到了特殊的网络转发问题。
考虑到集群使用的是IPVS模式,我检查了节点的IPVS规则:
bash复制ipvsadm -Ln
输出显示10.233.64.1:443确实有转发规则,指向Master节点的真实IP 180.64.10.127:6443:
code复制TCP 10.233.64.1:443 rr
-> 180.64.10.127:6443 Masq 1 2 0
手动测试这个真实端点:
bash复制telnet 180.64.10.127 6443
发现连接完全正常。这说明:
进一步检查IPVS的连接状态:
bash复制ipvsadm -lnc
发现了大量SYN_RECV状态的连接:
code复制TCP 00:51 SYN_RECV 10.233.64.1:35336 10.233.64.1:443 180.64.10.127:6443
SYN_RECV表示IPVS收到了SYN包并回复了SYN-ACK,但没有收到客户端的ACK确认。这通常意味着:
在IPVS模式下,kube-proxy会:
bash复制ip addr show kube-ipvs0
这个设计使得ClusterIP可以像真实IP一样响应ping请求(因此之前ping通是正常的),但实际服务访问依赖IPVS的转发规则。
经过大量测试和资料查阅,我总结了几个可能导致IPVS转发失败的原因:
通过逐一排查:
在无法立即定位根本原因的情况下,我决定先将kube-proxy切换为IPTables模式:
bash复制kubectl edit cm kube-proxy -n kube-system
将mode: ipvs改为mode: ""(空值表示使用IPTables)
bash复制kubectl delete pod -l k8s-app=kube-proxy -n kube-system
bash复制ipvsadm --clear
等待组件重建完成后,验证结果:
bash复制telnet 10.233.64.1 443
现在可以正常连接了!不过有趣的是:
bash复制ping 10.233.64.1
这次ping不通了——这正是IPTables模式与IPVS模式的区别特征。
在IPTables模式下:
检查iptables规则可以看到详细的转发链:
bash复制iptables-save | grep KUBE-SVC
这次故障排查经历让我总结出一个K8S网络问题的通用排查思路:
虽然这次我们暂时切换到了IPTables模式,但并不意味着IPVS不好。事实上,IPVS在大规模集群中有明显优势:
而IPTables的优势在于:
虽然问题暂时解决,但留下了几个待办事项:
这次排查也提醒我,在生产环境使用较新的网络特性时,一定要:
网络问题往往是最难排查的,但每次解决都能带来宝贵的经验。记录下整个过程,希望能帮助到遇到类似问题的同行。