Calico IPIP模式详解

Kubernetes 集群中的Calico网络插件有几种网络模式,例如BGP, IPIP, VXLAN (Calico v3.7之后支持此模式),本文主要介绍IPIP模式。

 

Calico IPIP模式其实是利用了Linux 的tun/tap设备,对IP层的报文再加了一层IP层的封装实现的一种overlay模式。因为IPIP模式比BGP模式多了一层封包与拆包,所以性能会有所损耗。既然如此,为什么不直接使用BGP模式就行了呢?因为BGP模式是需要通过路由广播交换容器网络的路由信息,而路由广播只能在局域网中进行,在BGP模式下,如果kubernetes集群中的工作节点不在同一个子网,则跨子网的工作节点上的POD无法正常通信。

 

下面通过一些例子来详细了解Calico IPIP模式是如何工作的。

 

我们使用的集群中加上管理节点总共有两个工作节点

[root@master01 /]# kubectl get node
NAME       STATUS   ROLES    AGE   VERSION
master01   Ready    master   57d   v1.15.12
node01     Ready    <none>   62m   v1.15.12

 

部署了calico网络插件

[root@master01 /]# kubectl -n kube-system get po -owide | grep calico-node
calico-node-9shgc                          1/1     Running   0          11m   192.168.92.128   master01   <none>           <none>
calico-node-c2scz                          1/1     Running   0          11m   192.168.92.129   node01     <none>           <none>

 

容器网段为172.16.0.0/16

        - name: CALICO_IPV4POOL_CIDR
          value: 172.16.0.0/16

 

kubectl get ipamblocks可以看到有两个容器网段分别分配给了master01和node01。

[root@master01 ~]# kubectl get ipamblocks
NAME                AGE
172-16-196-128-26   59m
172-16-241-64-26    60m
[root@master01 ~]# kubectl get ipamblocks 172-16-196-128-26 -oyaml
apiVersion: crd.projectcalico.org/v1
kind: IPAMBlock
metadata:
  annotations:
    projectcalico.org/metadata: '{"creationTimestamp":null}'
  creationTimestamp: "2021-03-30T04:17:26Z"
  generation: 6
  name: 172-16-196-128-26
  resourceVersion: "2380"
  selfLink: /apis/crd.projectcalico.org/v1/ipamblocks/172-16-196-128-26
  uid: f10cf88f-f999-49c6-bd7f-17670ed0e173
spec:
  Deleted: false
  affinity: host:node01
[root@master01 ~]# kubectl get ipamblocks 172-16-241-64-26 -oyaml
apiVersion: crd.projectcalico.org/v1
kind: IPAMBlock
metadata:
  annotations:
    projectcalico.org/metadata: '{"creationTimestamp":null}'
  creationTimestamp: "2021-03-30T04:16:40Z"
  generation: 6
  name: 172-16-241-64-26
  resourceVersion: "983"
  selfLink: /apis/crd.projectcalico.org/v1/ipamblocks/172-16-241-64-26
  uid: 97e63164-1f4b-4621-9c08-2b1fdb766cb1
spec:
  Deleted: false
  affinity: host:master01

 

查看主机master01上的路由表,可以看到目标地址为172.26.196.128/26的请求会被通过网卡tunl0转发到192.168.92.129,也就是node01上。

而master01节点本机上的POD IP,则会直接被路由到对应的calico网卡。

[root@master01 /]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.92.2    0.0.0.0         UG    100    0        0 ens33
172.16.196.128  192.168.92.129  255.255.255.192 UG    0      0        0 tunl0 
172.16.241.64   0.0.0.0         255.255.255.192 U     0      0        0 *
172.16.241.69   0.0.0.0         255.255.255.255 UH    0      0        0 cali68d0bd52ca7
172.16.241.70   0.0.0.0         255.255.255.255 UH    0      0        0 cali55ce5618d78
172.16.241.71   0.0.0.0         255.255.255.255 UH    0      0        0 cali6156df79841
172.16.241.72   0.0.0.0         255.255.255.255 UH    0      0        0 cali81d206a1716
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.92.0    0.0.0.0         255.255.255.0   U     100    0        0 ens33
192.168.241.64  0.0.0.0         255.255.255.192 U     0      0        0 *

 

同样,在node01上也可以看到类似的路由条目。

[root@node01 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.92.2    0.0.0.0         UG    100    0        0 ens33
172.16.196.128  0.0.0.0         255.255.255.192 U     0      0        0 *
172.16.196.129  0.0.0.0         255.255.255.255 UH    0      0        0 cali6321cd990f9
172.16.196.131  0.0.0.0         255.255.255.255 UH    0      0        0 cali63b1569e518
172.16.241.64   192.168.92.128  255.255.255.192 UG    0      0        0 tunl0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.92.0    0.0.0.0         255.255.255.0   U     100    0        0 ens33

 

现在我们在每个工作节点上分别部署一个busybox POD,然后再详细看看跨节点的POD之间是怎么通信的。

[root@master01 ~]# kubectl -n kube-system get po -owide | grep busybox
busybox-b8ffb94c4-2ltgw                    1/1     Running            0          17s     172.16.196.132   node01     <none>           <none>
busybox-b8ffb94c4-c84gp                    1/1     Running            0          17s     172.16.241.69    master01   <none>           <none>

 

在其中一个busybox POD上访问另一个节点上的busybox。

[root@master01 ~]# kubectl -n kube-system exec -it busybox-b8ffb94c4-c84gp sh
/ # ping 172.16.196.132
PING 172.16.196.132 (172.16.196.132): 56 data bytes
64 bytes from 172.16.196.132: seq=0 ttl=62 time=0.580 ms

 

在另一台主机上抓包。

[root@node01 ~]# tcpdump -i any -nn -vvvv host \(192.168.92.128 or 172.16.241.69\) -w /tmp/busybox.cap

 

使用wireshark打开抓包文件,可以看到报文在POD A (172.16.241.69) 和POD B (172.16.196.132)之间,经过了两层的IP封装。

 

因为跨节点的POD之间通信时,报文需要通过宿主机的网络发送到另一个节点,但宿主机网络无法识别容器IP,所以,报文从POA A发送到宿主机A的tunl0网卡时,内核自动在报文基础上封装了一层IP头,之后再转发给主机B(192.168.92.129)。主机B拆开IP报文之后,根据本机的路由表匹配到目标POD的网卡,最终把报文转发给了POD B。

 

 

 这里有一个问题,主机192.168.92.128和192.168.92.129是在同一个子网的,他们之间其实是可以通过BGP路由信息交换,使到POD之间可以直接路由可达,而不需要通过IPIP协议,毕竟IPIP协议还是有损耗的。

 

在Calico IPIP模式下,其实有一个配置项(CALICO_IPV4POOL_IPIP),可以让calico只有在跨子网的情况下才使用IPIP协议,同一子网中的POD直接通过路由信息直连。该参数为如下,添加到calico-node的环境变量中即可。

 

        - name: CALICO_IPV4POOL_IPIP
          value: CrossSubnet

 

如果是已经部署了calico之后再修改这个参数,还需要修改ippool中的ipipMode参数。

[root@master01 ~]# kubectl get ippool default-ipv4-ippool -oyaml
apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
  annotations:
    projectcalico.org/metadata: '{"uid":"3797d863-3b04-45cd-b9ba-ac1980a21520","creationTimestamp":"2021-03-30T04:16:40Z"}'
  creationTimestamp: "2021-03-30T04:16:40Z"
  generation: 1
  name: default-ipv4-ippool
  resourceVersion: "732"
  selfLink: /apis/crd.projectcalico.org/v1/ippools/default-ipv4-ippool
  uid: 4c7acedb-0026-4062-994d-e82d261f29cc
spec:
  blockSize: 26
  cidr: 172.16.0.0/16
  ipipMode: CrossSubnet

 

修改完以上参数之后,我们再看看主机上的路由表,可以看到容器网段172.16.196.128/26的路由条目,出口的网卡变成了ens33,也就是不再通过tunl0进行IPIP协议的封装,而是直接根据路由信息转发。

[root@master01 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.92.2    0.0.0.0         UG    100    0        0 ens33
172.16.196.128  192.168.92.129  255.255.255.192 UG    0      0        0 ens33
172.16.241.64   0.0.0.0         255.255.255.192 U     0      0        0 *
172.16.241.65   0.0.0.0         255.255.255.255 UH    0      0        0 cali99ba0e1a1c8
172.16.241.66   0.0.0.0         255.255.255.255 UH    0      0        0 cali3941b92be17
172.16.241.67   0.0.0.0         255.255.255.255 UH    0      0        0 cali0fd794bcf81
172.16.241.68   0.0.0.0         255.255.255.255 UH    0      0        0 cali291c708c629
172.16.241.69   0.0.0.0         255.255.255.255 UH    0      0        0 cali67beaa0e9f4
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.92.0    0.0.0.0         255.255.255.0   U     100    0        0 ens33

 

同样的在POD A ping POD B并抓包看看,我们可以看到这次只有一个IP层报文。

 

posted @ 2021-03-30 17:05  雨后彩虹,如此绚烂  阅读(5876)  评论(1编辑  收藏  举报