前言
网络底层经常为了要连接两个不同的namespace连通,经常的做法就是使用veth pair。如在虚机对应到宿主机上,容器对于宿主机等。或是自己创建一个namespace,要与它的网络连通等。
关于veth pair
首先要理解底层原理
- 安装ethtool
yum install ethtool
- 找到相应的容器
[root@node1 ~]# kubectl -n kube-system get po coredns-79c6f6447f-6f9xp -o yaml | grep -i id ... - containerID: docker://b79eb8591d3e671c0a97354e1d778a16a4380dffbd2cd58bac5c7ffb4b77917a imageID: docker-pullable://coredns/coredns@sha256:263d03f2b889a75a0b91e035c2a14d45d7c1559c53444c5f7abf3a76014b779d ...
- 去容器所在的node
[root@node1 ~]# kubectl -n kube-system get po coredns-79c6f6447f-6f9xp -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES coredns-79c6f6447f-6f9xp 1/1 Running 0 41h 10.233.74.65 node4 <none> <none>
- 查看容器的pid
[root@node4 ~]# docker inspect b79eb8591d3e671c0a97354e1d778a16a4380dffbd2cd58bac5c7ffb4b77917a | grep -i pid "Pid": 20880,
- 确认下这个网卡是veth
[root@node4 ~]# nsenter -n -t 20880 ip -d link show eth0 4: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1440 qdisc noqueue state UP mode DEFAULT group default link/ether b6:0b:be:96:5c:86 brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 0 veth addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
- 查看该 eth0的对端
[root@node4 ~]# nsenter -n -t 20880 ethtool -S eth0 NIC statistics: peer_ifindex: 8
- 在宿主机上查看序号为8 的网卡
[root@node4 ~]# ip link | less 8: cali9a8d0827254@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1440 qdisc noqueue state UP mode DEFAULT group default link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 0
- 因此,去往这个pod的路由,其实就是把数据发到这个网卡。这个ip就是Pod的IP
[root@node4 ~]# ip r | grep cali9a8d0827254 10.233.74.65 dev cali9a8d0827254 scope link
了解了这个,那么对于ping pod IP不通的网络问题的排查方法,自然而然就清晰了。
无法ping通pod ip的故障排查
思路:
-
首先在客户端长ping
- 在pod所在的主机上抓包
tcpdump -i any arp or icmp -nn
- 如果包进入到了这个host上,接着在抓pod上的包
实战
- 首先看 nginx controller pod的日志,看到有如下报错:
127.0.0.1 - [127.0.0.1] - - [22/Jun/2020:06:10:51 +0000] “GET / HTTP/1.1” 499 0 “-” “curl/7.61.1” 297 1.676 [test-productpage-9080] 10.233.75.9:9080 0 1.676 - ec4ba69a-2e7f-9278-b4af-5fc2bee8e387 127.0.0.1 - [127.0.0.1] - - [22/Jun/2020:06:11:25 +0000] “GET / HTTP/1.1" 503 91 “-” “curl/7.61.1" 297 30.047 [test-productpage-9080] 10.233.75.9:9080 91 30.048 503 7ac4e901-967b-415c-9be5-0a619219e13a 127.0.0.1 - [127.0.0.1] - - [22/Jun/2020:06:11:50 +0000] “GET / HTTP/1.1” 499 0 “-” “curl/7.58.0” 297 1.399 [test-productpage-9080] 10.233.75.9:9080 0 1.396 - f1a23193-6cb1-452f-a215-f43e353f7ac
-
看返回码是 499 503,503 容易理解是后端挂了或是网络不通。499 上网 google 后是说客户端手动终止导致的 http 终断。
-
这个时候要查下从 controller pod 来 ping 这个 ip,发现确实 ping 不通。
-
查了下这个 ip 是目标 pod ip。
-
ipvsadm -Sn grep 看了下它的 service ip, 然后从这个 pod 里面 ping 这个 service ip 发现能通,但其实没有什么用,不要受它的干扰,致于为什么能通,原因还不是很清楚。 -
从源宿主机上 ping 这个 pod ip 也不通,此时就是不正常的。注意一般来讲 node 能 ping 通所有的 pod 的IP。
-
从目标宿主机上 ping 这个 pod 的 ip 能 ping 通。注意所有的 pod 所在的 宿主机都能 ping 通它上面的 pod。
- 在源宿主机上一直 ping 目标 ip,现在包的走向应该是 源宿主机 → 目标宿主机 → 目标 pod,现在的问题是源宿主机到目标宿主机能通,目标宿主机到目标 pod 能通,但是源宿主机到目标 pod 不通。此时需要抓包来看:
#在目标宿主机上: # tcpdump -qenc 4 -i any arp or icmp # 此时能收到包 # ip r get 10.233.71.54 10.233.71.54 dev califefebb442cd src 192.168.0.7 uid 0 # 找到网卡 # tcpdump -qenc 4 -i califefebb442cd icmp or arp # 抓下这张网卡的包,发现丢包了。 # iptables -t filter -F # 清空下iptabels filter 表中的所有规则,发现通了,但是过一会儿又全部加上了。
-
此时问题就明朗了,说明是可能是有网络策略。查下 ws project 下的 network policy,发现确实有,把它关闭就好了。
- 为什么有网络策略问题呢?
原因是 ingress contrller 是在默认的 system-workspace 下面,而test 这个 Project 是在 demo 的 workspace 下面,网络策略开启后,只允许出不允许进,因此从 ingress controller 这个 pod 上面无法 ping 通到该 pod。#其实在目标主机上把包过滤掉了,可以直接 iptables 看包,可以看到 root@node3:~# watch -n 0.5 -d "iptables -t filter -vS | grep califefebb442cd"
注意: 如果一直 Ping 着包是通的,然后把网络隔离打开后,Ping 包不会断,因为已经建立着的连接不会跟你断掉,但是断开一下,然后再 ping 就会把你的包拒绝。