1.问题说明
今天早上发现,k8s其中有一个服务映射的 nodePort ,在k8s集群外的同内网服务器中,两次连接该服务时,一次可连接,一次不能连接,即50%的几率可以正常连接,使用telnet测试如下:
// 可正常连接
# telnet 192.168.21.202 30001
Trying 192.168.21.202...
Connected to 192.168.21.202.
Escape character is '^]'.
//不可连接
# telnet 192.168.21.202 30001
Trying 192.168.21.202...
telnet: connect to address 192.168.21.202: Connection refused
2.问题分析
可通过以下方式,将问题分层,缩小排查范围:
-
k8s集群外部服务器不可连接,k8s集群内部服务器可连接:此问题不属于k8s集群问题,应该是服务器之间网络连接问题,需要检查防火墙及安全组问题
-
k8s集群内部服务器不可连接,服务的pod容器内可连接:此问题可能为k8s集群内问题,需要检查各组件状态是否健康,尤其是kube-proxy服务(此服务作用为将svc的请求转发到pod容器内),同时还有iptables防火墙问题,同时也存在着服务问题,有可能此服务有两个pod容器,其中一个服务存在问题
-
服务的pod容器内也不可连接:此问题应该是服务本身问题,可查看服务启动状态是否启动,查看服务日志是否异常
3.问题排查
通过以上问题分析环节,可得出: k8s集群内部服务器不可连接,服务的pod容器内可连接,于是进行了以下排查步骤:
- 查看存在问题的服务是否存在两个pod容器及存活状态
// 问题服务svc状态
# kubectl get svc -o wide -n fabric-auto |grep fabric-auto-api
fabric-auto-api NodePort 10.1.102.29 <none> 8088:30001/TCP 3h10m app=fabric-auto,role=fabric-auto-api
// 问题服务pod状态
# kubectl get pod -o wide -n fabric-auto |grep fabric-auto-api
fabric-auto-api-5955b9f9cc-x5mgz 1/1 Running 0 3h10m 10.2.3.175 192.168.21.202 <none> <none>
可通过以上命令查看到pod容器的状态,目前该服务仅一个pod容器,且正常启动
- 查看master节点各组件是否正常
以下结果表示无问题
# kubectl get cs
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-1 Healthy {"health":"true"}
etcd-2 Healthy {"health":"true"}
etcd-0 Healthy {"health":"true"}
- 查看node节点kubelet组件是否正常
可看到kubelet组件的服务状态为running,服务无问题
//node节点中执行
# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: active (running) since Wed 2021-04-14 11:08:32 CST; 3h 10min ago
Docs: https://kubernetes.io/docs/
Main PID: 1208 (kubelet)
......
- 查看node节点kube-proxy服务是否正常
因为此k8s集群环境使用kubeadm安装,所以kube-proxy使用容器启动,查看kube-proxy日志时,发现以下报警:
can’t set sysctl net/ipv4/vs/conn_reuse_mode, kernel version must be at least 4.1
//node节点中执行
# docker ps|grep kube-proxy
# docker logs -f k8s_kube-proxy_kube-proxy-qn8gg_kube-system_c189d6f0-b9ab-485b-b31e-bf3fd8f9f32d_0
......
E0203 12:34:19.189547 1 proxier.go:381] can't set sysctl net/ipv4/vs/conn_reuse_mode, kernel version must be at least 4.1
W0203 12:34:19.189665 1 proxier.go:434] IPVS scheduler not specified, use rr by default
......
去 Kubernetes Github 查看相关 issues,发现有人遇见了相同的问题,经过 issue 中 Kubernetes 维护人员讨论,分析出原因可能为新版 Kubernetes 使用的 IPVS 模块是比较新的,需要系统内核版本支持,本人使用的是 CentOS 系统,内核版本为 3.10,里面的 IPVS 模块比较老旧,缺少新版 Kubernetes IPVS 所需的依赖。
根据该 issue 讨论结果,解决该问题的办法是,更新内核为新的版本。
centos7 服务器升级内核版本方法使用此链接:https://blog.csdn.net/cljdsc/article/details/115698143
注意:因升级服务器内核版本需要重启服务器生效,此操作之前,应确定服务器可暂时停机,重启前需要检查服务器启动的服务项,重启后再进行检查服务是否都已经启动!!!
内核版本升级后,kube-proxy容器已经不再打印如上报警,但此时依然无法解决端口连接不通问题
再次对kube-proxy容器重启后,依然未能解决,看来最后的绝招,重启已经无法解决问题了。。。。。
- 观察k8s集群内端口转发情况
命令:ipvsadm -Ln
作用:查看当前ipvs模块中记录的连接(可用于观察转发情况)
# ipvsadm -ln
TCP 172.17.0.1:30001 rr
-> 10.2.3.161:8088 Masq 1 0 0
-> 10.2.3.172:8088 Masq 1 0 0
TCP 192.168.21.202:30336 rr
-> 10.2.3.161:3306 Masq 1 0 0
-> 10.2.3.172:3306 Masq 1 0 0
TCP 172.17.0.1:30303 rr
-> 10.2.3.163:8081 Masq 1 0 0
可以看到nodePort 端口:30001、30336转发规则下有两个pod容器,难道这两个端口各自存在两个服务吗,可使用以下命令进行查看:
//30001端口:仅一个pod容器
# kubectl get svc -o wide --all-namespaces |grep 30001
fabric-auto fabric-auto-api NodePort 10.1.102.29 <none> 8088:30001/TCP 3h19m app=fabric-auto,role=fabric-auto-api
# kubectl get pod -o wide --all-namespaces |grep fabric-auto-api
fabric-auto fabric-auto-api-5955b9f9cc-x5mgz 1/1 Running 0 3h19m 10.2.3.175 192.168.21.202 <none> <none>
//30336端口:仅一个pod容器
# kubectl get svc -o wide --all-namespaces |grep 30336
fabric-auto fabric-auto-mysql NodePort 10.1.76.55 <none> 3306:30336/TCP 3h23m app=fabric-auto,role=fabric-auto-mysql
# kubectl get pod -o wide --all-namespaces |grep fabric-auto-mysql
fabric-auto fabric-auto-mysql-7f7dc8b46b-jfsmt 1/1 Running 0 3h23m 10.2.3.174 192.168.21.202 <none> <none>
这两个服务一定有问题!!!
- 查看已有的Pod容器为YAML格式
# kubectl get svc -n fabric-auto fabric-auto-mysql -o yaml
# kubectl get deployment -n fabric-auto fabric-auto-mysql -o yaml
使用如上命令,查看两pod容器的deployment及svc的yaml文件有一段是相同的:
labels:
app: fabric-auto
role: fabric-auto-control
labels 参数用来定义此当前服务的标签,以便对pod容器进行管理
4.问题结论
由于两个服务中的svc及pod的yaml文件中标签定义一致,kube-proxy在进行流量分发时,发现有两组同样标签的pod,于是都进行了转发,因此出现:一次可连接,一次不可连接的情况。
5.问题解决
删除两个服务的pod容器及svc
修改两个服务的deployment及svc的yaml文件中的labels标签项,使其不一致即可
重新创建服务的svc及pod,问题解决