Kubernetes 集羣中的Calico網絡插件有幾種網絡模式,例如BGP, IPIP, VXLAN (Calico v3.7以後支持此模式),本文主要介紹IPIP模式。node
Calico IPIP模式實際上是利用了Linux 的tun/tap設備,對IP層的報文再加了一層IP層的封裝實現的一種overlay模式。由於IPIP模式比BGP模式多了一層封包與拆包,因此性能會有所損耗。既然如此,爲何不直接使用BGP模式就好了呢?由於BGP模式是須要經過路由廣播交換容器網絡的路由信息,而路由廣播只能在局域網中進行,在BGP模式下,若是kubernetes集羣中的工做節點不在同一個子網,則跨子網的工做節點上的POD沒法正常通訊。docker
下面經過一些例子來詳細瞭解Calico IPIP模式是如何工做的。api
咱們使用的集羣中加上管理節點總共有兩個工做節點網絡
[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網絡插件tcp
[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/16ide
- 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上。ui
而master01節點本機上的POD IP,則會直接被路由到對應的calico網卡。spa
[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層報文。