Calico簡介
Calico組件是Tigera公司以Apache 2.0開源協議開源的網絡和網絡解決方案組件,可用於容器、虛擬機、原生宿主機側負載。Calico CNI插件在 CNI(Container Network Interface) 框架內封裝了Calico的功能,以對k8s環境做支持。
雖然Flannel被公認爲是最簡單的選擇,但Calico以其性能、靈活性而聞名。Calico的功能更爲全面,不僅提供主機和pod之間的網絡連接,還涉及網絡安全和管理。從Calico 3.x開始,默認配置使用的是IPIP模式這種Overlay的傳輸方案而非BGP。
Calico架構
Calico組件主要架構由Felix、Confd、BIRD組成:
- Felix是負責Calico Node運行並作爲每個節點Endpoint端點的守護程序,它負責管理當前主機中的Pod信息,與集羣etcd服務交換集羣Pod信息,並組合路由信息和ACL策略。
- Confd是負責存儲集羣etcd生成的Calico配置信息,提供給BIRD層運行時使用。
- BIRD(BIRD Internet Routing Daemon)是核心組件,Calico中的BIRD特指BIRD Client和BIRD Route Reflector,負責主動讀取Felix在本機上設置的路由信息,並通過BGP廣播協議在數據中心中進行分發路由。
此外,etcd組件是Calico組件運行的依賴組件,需事先在集羣中部署etcd服務,或複用Kubernetes的etcd;Calico官方也提供了calicoctl管理工具,用於與Calico Node進行狀態確認、狀態配置等操作。
Calico之IPIP模式
IPIP模式基於linux kernel的ipip隧道技術實現,即IP報文外面又封裝了一層IP報文。內層的IP報文爲原報文,外層報文的源IP和目的IP,即是隧道兩端的IP。也就是說,應用想要通過隧道在源IP報文外再封裝一層IP報文,從而使得原報文能夠通過隧道路由到對端。對端的IPIP隧道模塊,把原來的外層IP拆解掉,從而還原出原來的IP報文。
IPIP主要做的就是封包,解包的過程。通過IPIP封解包,原始IP報文能夠在外層IP的託運下,通過路由穿過隧道,抵達隧道的對端,並且還原出原來的IP報文。這就是IPIP隧道的核心思想。
在使用ipip模式之後,每個node上會自動添加一個tunl0網卡,用於IPIP協議的支持。
IPIP協議格式
pod跨node通信
pod和node網絡狀況
我們使用兩個處於不同node的pod:
# kubectl get pods -o wide
pod1 1/1 Running 17 12d 10.101.26.40 work4 <none> <none>
pod2 1/1 Running 17 12d 10.99.1.167 work1 <none> <none>
登陸work1和work4查看pod的ip和node物理網絡的關係,我們可以發現pod內部的網卡在node上會有映射一個虛擬網卡,這一對網卡是一個虛擬機網卡對。一對虛擬網卡就像一跟數據線一遍發送數據另一邊就能接收到且數據流向相同:
[root@work1 ~]# route -n|grep 10.99.1.167
10.99.1.167 0.0.0.0 255.255.255.255 UH 0 0 0 cali2703ae2f129
[root@work1 ~]# ifconfig cali2703ae2f129
cali2703ae2f129: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1440
inet6 fe80::ecee:eeff:feee:eeee prefixlen 64 scopeid 0x20<link>
ether ee:ee:ee:ee:ee:ee txqueuelen 0 (Ethernet)
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
[root@work4 ~]# route -n|grep 10.101.26.40
10.101.26.40 0.0.0.0 255.255.255.255 UH 0 0 0 cali8a0d30f1f5a
[root@work4 ~]# ifconfig cali8a0d30f1f5a
cali8a0d30f1f5a: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1440
inet6 fe80::ecee:eeff:feee:eeee prefixlen 64 scopeid 0x20<link>
ether ee:ee:ee:ee:ee:ee txqueuelen 0 (Ethernet)
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
通信
- 在pod1上ping pod2的ip 10.99.1.167
- 數據包通過pod1的eth0網卡傳輸到node work4上虛擬網卡cali8a0d30f1f5a,然後通過查詢node work4上的路由,發現目的ip 10.99.1.167匹配到如下路由,故把數據包傳輸到tunl0網卡,此時IP數據報中Inner IP Header的IP:10.101.26.40 --> 10.99.1.167:
# route -n|grep tunl0 Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 10.99.1.128 172.18.2.186 255.255.255.192 UG 0 0 0 tunl0
- ipip隧道是雙向的,創建的時候會指定發送端local和接收端remote ip。tunl0收到數據包之後會按照ipip協議規範對進來的IP數據包封裝一層外層IP頭,外層IP的目的ip地址根據2步驟中的路由設置目的ip爲網關172.18.2.186,外層IP的源ip地址根據創建remote ip爲172.18.2.186這個隧道時的local ip地址設置爲172.18.2.184。此時IP數據報變爲: Outer IP Header的IP:172.18.2.184 --> 172.18.2.186; Inner IP Header的IP:10.101.26.40 --> 10.99.1.167。tunl0把接收到的數據包封裝成ipip報文直接發給tcp/ip協議棧。
- tcp/ip協議棧根據ipip報文的目的地址和系統路由表,知道目的地址爲172.18.2.186的數據報需要通過node work4的eth0發送。
# route -n|grep eth0 0.0.0.0 172.18.2.1 0.0.0.0 UG 100 0 0 eth0 172.18.2.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0
- 此ipip數據報經過網關172.18.2.1並最終發送到了node work1的eth0網卡。node work1的tcp/ip協議棧發現是ipip協議,對外層IP數據報解封裝並轉發給tunl0。tunl0根據內層IP數據包的目的ip地址和本地的路由協議,把數據包再轉發到對應的cali2703ae2f129網卡,完成單向通信。
# route -n|grep cali2703ae2f129 10.99.1.167 0.0.0.0 255.255.255.255 UH 0 0 0 cali2703ae2f129
- pod2回覆pod1的響應同理
pod node內通信
如果是同一個node內的pod通信,由於本地已經有對應pod的路由信息了,故直接在本地node路由轉發數據報就可以完成互相通信,不需要使用ipip封裝。
總結
1,calico IP in IP模式,跨node通信需要封裝和解封裝,node內通信不需要
2,calico IP in IP模式也是一種overlay的方案
3,通過封裝IP數據報實現,屬於L3層網絡通信方案
4,對IP隧道封包/解封包技術有一定了解,但是不夠深入,有問題歡迎指正