举个例子
容器A访问不了容器B,也就是容器A ping 不通容器B
排查思路:
正向
1 容器A的内容是否发送到容器A所在的node上
2 容器A所在的节点node是否发送出去
3 容器B所在的节点node是否接收到容器A所在的节点node发送的报文
4 容器B所在的节点node是否把报文发送到容器B中
1 容器B的内容是否发送到容器B所在的node上
2 容器B所在的节点node是否发送出去
3 容器A所在的节点node是否接收到容器B所在的节点node发送的报文
4 容器A所在的节点node是否把报文发送到容器A中
具体实践
[root@dev-master-105 ~]# kubectl get pods -owide -n qateam
NAME READY STATUS RESTARTS AGE IP NODE
asa-532345087-td4wp 1/1 Running 0 1d 192.168.123.209 dev-master-105
aws-3789938515-mkfs5 1/1 Running 1 30d 192.168.123.254 dev-master-105
demo-0 2/2 Running 0 37d 192.168.4.36 dev-slave-110
demo-1-0 2/2 Running 0 37d 192.168.19.20 dev-slave-108
demo22-0 2/2 Running 0 37d 192.168.4.35 dev-slave-110
erfasd-842565593-h94fh 1/1 Running 1 30d 192.168.123.249 dev-master-105
sas-3732401954-fmq45 1/1 Running 1 30d 192.168.123.247 dev-master-105
先用calicoctl查看容器A的workloadEndpoint:
[root@dev-master-105 ~]# calicoctl get workloadendpoint --workload=qateam.asa-532345087-td4wp -oyaml
- apiVersion: v1
kind: workloadEndpoint
metadata:
labels:
ClusterID: CID-f794208bc85f
UserID: "45"
calico/k8s_ns: qateam
name: asa
pod-template-hash: "532345087"
name: eth0
node: dev-master-105
orchestrator: k8s
workload: qateam.asa-532345087-td4wp
spec:
interfaceName: calicc354b946ce
ipNetworks:
- 192.168.123.209/32
mac: f6:77:d3:29:1a:50
profiles:
- k8s_ns.qateam
1 容器A的绑定的网卡 calicc354b946ce
2 容器A的mac地址f6:77:d3:29:1a:50
3 容器的IP地址192.168.123.209/32 所在的节点dev-master-105
查看容器A内的网卡是否正确,ip和mac是否与从calico中查询到的一致:
[root@dev-master-105 ~]# kubectl exec -it asa-532345087-td4wp -n qateam sh
sh-4.2# ifconfig
eth0: flags=4163 mtu 1500
inet 192.168.123.209 netmask 255.255.255.255 broadcast 0.0.0.0
inet6 fe80::f477:d3ff:fe29:1a50 prefixlen 64 scopeid 0x20
ether f6:77:d3:29:1a:50 txqueuelen 0 (Ethernet)
RX packets 5041 bytes 13366685 (12.7 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3953 bytes 263623 (257.4 KiB)
TX errors 0 dropped 1 overruns 0 carrier 0 collisions 0
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 1 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
可以看到mac地址以及ip地址 跟通过calicoctl 取到的是一致的
查看容器A的默认路由是否是169.254.1.1,且没有额外的路由:
sh-4.2# ip route
default via 169.254.1.1 dev eth0
169.254.1.1 dev eth0 scope link
在node上执行,查看calicc354b946ce的网卡的mac地址是否跟之前通过calicoctl查询得到的结果一致
[root@dev-master-105 ~]# ip link show calicc354b946ce
18: calicc354b946ce@if4: mtu 1500 qdisc noqueue state UP mode DEFAULT
link/ether 22:49:04:09:0b:cd brd ff:ff:ff:ff:ff:ff link-netnsid 3
查看容器A内记录的169.254.1.1的mac地址是否是node上的calico网卡的mac
sh-4.2# ip neigh
169.254.1.1 dev eth0 lladdr 22:49:04:09:0b:cd STALE
这里需要一点说明,使用calico后,在容器内只有一条默认路由,所有的报文都通过169.254.1.1送出。但是这个IP是RFC约定保留的无效IP,报文怎么还能送出去呢?
秘密就是容器内的arp记录,在容器A内记录的169.254.1.1的mac地址是:
node上的caliXX网卡的mac。
node上的caliXX网卡和容器内的eth0网卡,是一对veth设备。veth网卡的特性是,向eth0写入的报文,会通过caliXX流出。
在容器A中向eth0写入的报文,它目的mac是caliXX网卡的mac,当报文经caliXX流出时,就 进入到了node的协议栈中,开始在node的网络空间中流转。
在容器A所在的node上用tcpdump监听calicc354b946ce网卡,查看是否能够收到容器A发出的报文:
[root@dev-master-105 ~]# tcpdump -i calicc354b946ce
tcpdump: WARNING: calicc354b946ce: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on calicc354b946ce, link-type EN10MB (Ethernet), capture size 65535 bytes
检查发送端node上的路由,目标IP的下一跳地址是否正确,目标IP是容器的地址,检查下一跳是否对应了正确的node ip:
...
192.168.19.0/26 via 10.39.0.105 dev tunl0 proto bird onlink
...
这条路由是通过BGP协议得知的,它的意思是说192.168.19.0/26这个网段可以通过10.39.0.105到达。
然后还需要检查发送端node上的iptables规则,看一下iptable是否拒绝了这个报文。
很多组件都会设置iptables规则,有可能是别的组件,譬如docker,设置的规则导致不通。
从calico中获取接收端容器B的信息:
[root@dev-master-105 ~]# calicoctl get workloadendpoint --workload=qateam.dev-3629875698-b58t6 -oyaml
- apiVersion: v1
kind: workloadEndpoint
metadata:
labels:
ClusterID: CID-f794208bc85f
UserID: "45"
calico/k8s_ns: qateam
name: dev
pod-template-hash: "3629875698"
tenxcloud.com/appName: dev
tenxcloud.com/svcName: dev
name: eth0
node: dev-master-105
orchestrator: k8s
workload: qateam.dev-3629875698-b58t6
spec:
interfaceName: cali9ee0bd99a15
ipNetworks:
- 192.168.123.248/32
mac: 56:eb:69:42:68:d9
profiles:
- k8s_ns.qateam
可以得到容器B的以下信息:
1.容器的网络接口(网卡)cali9ee0bd99a15
2.容器的节点dev-master-105
监听容器B所在node的网卡,检查是否收到了容器A所在的node发送来的报文:
[root@dev-master-105 ~]# tcpdump -i cali9ee0bd99a15
tcpdump: WARNING: cali9ee0bd99a15: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on cali9ee0bd99a15, link-type EN10MB (Ethernet), capture size 65535 bytes
检查容器B所在node上的路由,检查目标IP是否对应了正确的calico网卡:
[root@dev-master-105 ~]# ip route
...
192.168.123.248 dev cali9ee0bd99a15 scope link
...
前面我们说明了报文如何从容器A到达容器A所在的node,那么还有一个问题是, 报文又是怎样从node到达容器内部的呢?
答案是node上的路由。
上面那条路由的意思是,192.168.60.173这个IP对应的网卡是caliXXX,报文会被写入到这个网卡中。 这个网卡和容器内的网卡是一对veth设备,写入caliXX的报文会通过容器内的eth0流出,从而进入到容器的网络空间中。
这里同样需要检查接收端node上的iptables规则,看一下报文是否被iptables拒绝。
参考:
http://mp.weixin.qq.com/s/MZIj_cvvtTiAfNf_0lpfTg