天天看点

kubernetes calico网络不通的排查思路

网络不通通俗一点就是报文不可达 在这里就不多说了

举个例子

容器A访问不了容器B,也就是容器A ping 不通容器B

排查思路:

正向

容器A的内容是否发送到容器A所在的node上
 容器A所在的节点node是否发送出去
 容器B所在的节点node是否接收到容器A所在的节点node发送的报文
 容器B所在的节点node是否把报文发送到容器B中
           

反向

容器B的内容是否发送到容器B所在的node上
 容器B所在的节点node是否发送出去
 容器A所在的节点node是否接收到容器B所在的节点node发送的报文
 容器A所在的节点node是否把报文发送到容器A中
           

具体实践

[root@dev-master- ~]# kubectl get pods -owide -n qateam
NAME                     READY     STATUS             RESTARTS   AGE       IP                NODE
asa--td4wp      /       Running                      d        .   dev-master-
aws--mkfs5     /       Running                      d       .   dev-master-
demo-                   /       Running                      d       .      dev-slave-
demo--                 /       Running                      d       .     dev-slave-
demo22-                 /       Running                      d       .      dev-slave-
erfasd--h94fh   /       Running                      d       .   dev-master-
sas--fmq45     /       Running                      d       .   dev-master-
           

先用calicoctl查看容器A的workloadEndpoint:

[[email protected] ~]# 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:
    - ./
    mac: f6:77:d3:29:1a:50
    profiles:
    - k8s_ns.qateam

           

可以看到容器A的相关网路的信息

容器A的绑定的网卡 calicc354b946ce
 容器A的mac地址f6::d3::a: 
 容器的IP地址./ 所在的节点dev-master-
           

查看容器A内的网卡是否正确,ip和mac是否与从calico中查询到的一致:

[root@dev-master- ~]# kubectl exec -it asa-532345087-td4wp -n qateam sh
sh-# ifconfig 
eth0: flags=<UP,BROADCAST,RUNNING,MULTICAST>  mtu 
        inet .  netmask .  broadcast ...
        inet6 fe80::f477:d3ff:fe29:a5  prefixlen   scopeid <link>
        ether f6::d3::a:  txqueuelen   (Ethernet)
        RX packets   bytes  ( MiB)
        RX errors   dropped   overruns   frame 
        TX packets   bytes  ( KiB)
        TX errors   dropped  overruns   carrier   collisions 

lo: flags=<UP,LOOPBACK,RUNNING>  mtu 
        inet ..  netmask ..
        inet6 ::  prefixlen   scopeid <host>
        loop  txqueuelen   (Local Loopback)
        RX packets   bytes  (. B)
        RX errors   dropped   overruns   frame 
        TX packets   bytes  (. B)
        TX errors   dropped  overruns   carrier   collisions 

           

可以看到mac地址以及ip地址 跟通过calicoctl 取到的是一致的

查看容器A的默认路由是否是169.254.1.1,且没有额外的路由:

sh-# ip route
default via  dev eth0 
 dev eth0 scope link 
           

在node上执行,查看calicc354b946ce的网卡的mac地址是否跟之前通过calicoctl查询得到的结果一致

[root@dev-master- ~]# ip link show calicc354b946ce
: calicc354b946ce@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu  qdisc noqueue state UP mode DEFAULT 
    link/ether :::09:0b:cd brd ff:ff:ff:ff:ff:ff link-netnsid 
           

查看容器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- ~]# 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  bytes
           

检查发送端node上的路由,目标IP的下一跳地址是否正确,目标IP是容器的地址,检查下一跳是否对应了正确的node ip:

...
/ via  dev tunl0  proto bird onlink 
...
           

这条路由是通过BGP协议得知的,它的意思是说192.168.19.0/26这个网段可以通过10.39.0.105到达。

然后还需要检查发送端node上的iptables规则,看一下iptable是否拒绝了这个报文。

很多组件都会设置iptables规则,有可能是别的组件,譬如docker,设置的规则导致不通。

从calico中获取接收端容器B的信息:

[[email protected] ~]# 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-
    orchestrator: k8s
    workload: qateam.dev--b58t6
  spec:
    interfaceName: cali9ee0bd99a15
    ipNetworks:
    - /
    mac: :eb::::d9
    profiles:
    - k8s_ns.qateam
           

可以得到容器B的以下信息:

容器的网络接口(网卡)cali9ee0bd99a15
容器的节点dev-master-
           

监听容器B所在node的网卡,检查是否收到了容器A所在的node发送来的报文:

[root@dev-master- ~]# 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  bytes
           

检查容器B所在node上的路由,检查目标IP是否对应了正确的calico网卡:

[[email protected] ~]# ip route
...
 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

继续阅读