k8s容器互聯-flannel host-gw原理篇

2023-03-16 15:05:15

k8s容器互聯-flannel host-gw原理篇

容器系列文章

容器系列視訊

簡析host-gw

前面分析了flannel vxlan模式進行容器跨主機通訊的原理,但是vxlan模式需要對封包進行額外的封包解包處理,帶來的開銷較大。

所以flannel提供了另外一種純3層轉發的通訊模式,叫做host-gw,顧明思議,這種模式是將主機作為閘道器在用了。

先來看下閘道器在ip通訊中的作用,例如,一個tcp包有源ip和目的ip,如果目的ip匹配不到路由資訊,那麼就會將包轉發到閘道器,在一個發往目的ip的過程中,可能會經過多個閘道器。

閘道器的本質是作為ip通訊的中轉站,網路包在傳輸過程中,目的ip是不會變的,一直在變化的是mac地址,每到達一臺主機,那麼目的mac地址就會發生變化,變成下一個閘道器的mac地址,封包需要到達的下一臺主機被稱作」下一跳「(next hop)。

瞭解了閘道器的作用,再來看看flannel host-gw模式在k8s節點上做了哪些改動。

叢集基本資訊

這裡我同樣是啟動了一個3節點的叢集,cni外掛就是用flannel,模式是host-gw模式。

net-conf.json: |
    {
      "Network": "10.10.0.0/16",
      "Backend": {
        "Type": "host-gw"
      }
    }

叢集節點資訊

parallels@master:~/k8s$ kubectl get nodes -o wide
NAME      STATUS   ROLES                  AGE   VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE           KERNEL-VERSION      CONTAINER-RUNTIME
master    Ready    control-plane,master   13d   v1.23.3   192.168.2.17   <none>        Ubuntu 22.04 LTS   5.15.0-58-generic   docker://20.10.12
worker1   Ready    <none>                 13d   v1.23.3   192.168.2.16   <none>        Ubuntu 22.04 LTS   5.15.0-60-generic   docker://20.10.12
worker2   Ready    <none>                 13d   v1.23.3   192.168.2.15   <none>        Ubuntu 22.04 LTS   5.15.0-60-generic   docker://20.10.12

然後用busybox映象啟動了4個pod

parallels@master:~/k8s$ kubectl  get pods -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP          NODE      NOMINATED NODE   READINESS GATES
busybox-8647b8666c-jpnb6   1/1     Running   0          21m   10.10.1.6   worker1   <none>           <none>
busybox-8647b8666c-pg7ps   1/1     Running   0          21m   10.10.2.4   worker2   <none>           <none>
busybox-8647b8666c-sgf8v   1/1     Running   0          21m   10.10.1.5   worker1   <none>           <none>
busybox-8647b8666c-zlxmm   1/1     Running   0          21m   10.10.2.3   worker2   <none>           <none>

我們的目的就是看看worker1節點上的ip為10.10.1.6 的pod 是如何ping通 worker2節點上的ip為 10.10.2.4 的pod的。

分析叢集內部網路流動方向

為了接下來的分析更加形象化,這裡我先貼上一張叢集內部的網路拓撲圖。後續的分析都可以隨時回顧下這張圖。

先從10.10.1.6的pod看起,進入10.10.1.6的pod檢視路由資訊。

worker1節點上的ip為10.10.1.6的pod路由資訊

parallels@master:~/k8s$ kubectl exec -it busybox-8647b8666c-jpnb6 /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ #
/ # ip route
default via 10.10.1.1 dev eth0
10.10.0.0/16 via 10.10.1.1 dev eth0
10.10.1.0/24 dev eth0 scope link  src 10.10.1.6

預設閘道器是10.10.1.1 ,這個ip地址其實就是worker1節點上cni0網橋的ip地址

可以查到worker1節點上cni0的ip地址

parallels@worker1:~$ ifconfig
cni0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.10.1.1  netmask 255.255.255.0  broadcast 10.10.1.255

所以在ip為10.10.1.6的pod內部去ping上worker2節點的pod ip 10.10.2.4 會匹配上第二條路由資訊,然後由eth0網路卡出去,閘道器地址是10.10.1.1,所以網路包就從pod內部傳送到了worker1的cni0網橋上。

cni0網橋會將mac地址為其自身mac地址的封包轉發到主機的3層網路中,而具體要怎麼路由,則是需要看worker1主機上的路由規則。

parallels@worker1:~$ ip route
default via 192.168.2.1 dev enp0s5 proto dhcp src 192.168.2.16 metric 100
10.10.0.0/24 via 192.168.2.17 dev enp0s5
10.10.1.0/24 dev cni0 proto kernel scope link src 10.10.1.1
10.10.2.0/24 via 192.168.2.15 dev enp0s5
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
192.168.2.0/24 dev enp0s5 proto kernel scope link src 192.168.2.16 metric 100
192.168.2.1 dev enp0s5 proto dhcp scope link src 192.168.2.16 metric 100

這些節點上路由的設定是由flannel 在每個節點上啟動的flanneld程序去進行的設定的,設定資訊來源是k8s叢集內部的etcd叢集

我們傳送的封包目的ip是10.10.2.4 ,它會匹配上worker1主機的第二條路由資訊,第二條路由資訊是在說存取10.10.0.0/24 網段的封包都將由enp0s5網路卡發出,並且閘道器地址也就是下一跳的ip地址是192.168.2.17,而192.168.2.17 就是worker2的ip地址。

為了看的更加清晰,我們再來回顧下開局的圖。

這樣封包就到達到worker2節點了,到了worker2節點後,封包的如何流動是看worker2節點上的路由規則,所以我們再來看下節點2上面的路由規則。記住封包的目的ip是10.10.2.4。

parallels@worker2:~$ ip route
default via 192.168.2.1 dev enp0s5 proto dhcp src 192.168.2.15 metric 100
10.10.0.0/24 via 192.168.2.17 dev enp0s5
10.10.1.0/24 via 192.168.2.16 dev enp0s5
10.10.2.0/24 dev cni0 proto kernel scope link src 10.10.2.1
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
192.168.2.0/24 dev enp0s5 proto kernel scope link src 192.168.2.15 metric 100
192.168.2.1 dev enp0s5 proto dhcp scope link src 192.168.2.15 metric 100

匹配上了第4條路由規則,發往 10.10.2.0/24 的網段的封包是要被cni0網橋處理的,所以封包來到了worker2節點上的cni0網橋上,cni0是如何找到要傳送的目的ip的veth埠的呢?

pod內部的eth0 網路卡其實就是個veth裝置,veth裝置一端連線在pod的網路名稱空間中,一端連線在網橋上,從veth的一端發出去的網路包一定能夠被另一端接收。

網橋收到主機發來的封包後,首先看自身有沒有封包的目的ip的埠記錄,如果有,那麼就從該埠傳送封包,因為連線的veth裝置,所以從埠傳送出去後,一定能到達pod的內部,veth裝置就像是網線一樣。

如果沒有記錄,那麼網橋會向通過arp協定廣播幀,得到迴應後便能知道埠與ip的對映關係。從而將封包發往正確的埠。

這樣一個封包就完全的從一臺主機通過路由規則到達到了另外一臺主機,而主機ip實際上是被當成閘道器,作為原ip地址的下一跳地址了。

host-gw的優缺點

相比於vxlan模式,因為少了封包解包的操作,會提升資料傳輸的效能。但由於這是一個純3層轉發的方案,要想主機作為的閘道器的前提,必須是叢集中的兩臺主機是一個二層連通的環境中。