天天看点

k8s集群中nodePort端口不可连接问题排查

文章目录

    • 1.问题说明
    • 2.问题分析
    • 3.问题排查
    • 4.问题结论
    • 5.问题解决

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,问题解决

继续阅读