flannel vxlan工作基本原理及常見排障方法

xinkun發表於2019-06-11

寫在前面

最近用kubeadm鼓搗了幾個cluster叢集測試用,網路用的flannel。因為這些機器都不是純淨的環境(以前部署過其他的k8s或者有一些特別的設定),所以部署起來遇到了很多問題。看了下相關的文章,梳理了flannel的vxlan的工作原理,成功對這幾個環境進行了排障。本文主要是相關流程的筆記記錄。

容器間通訊

本文以兩個節點上的兩個容器間通訊為例,介紹網路報文的流轉過程以及可能出現的問題。

flannel使用的映象為quay.io/coreos/flannel:v0.11.0-amd64

我現在部署有兩個node節點,節點ip為10.10.10.21610.10.10.217。本文將以這兩個節點上的容器為例。介紹兩個容器是如何通訊的。

節點 容器IP段 容器IP
10.10.10.216 10.244.0.0/24 10.244.0.6
10.10.10.217 10.244.1.0/24 10.244.1.2

首先講下 10.244.0.6 和 10.244.1.2 兩個容器間的通訊流程。我們這裡以從10.244.0.6向10.244.1.2 傳送資料包為例。

flannel

10.244.0.6容器在節點10.10.10.216。我們可以通過ip add命令檢視到容器在物理機上的veth卡。

[root@node-64-216 ~]# ip add
2: em1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether e0:db:55:13:7a:74 brd ff:ff:ff:ff:ff:ff
    inet 10.10.10.216/24 brd 10.10.10.255 scope global em1
       valid_lft forever preferred_lft forever
23: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default 
    link/ether 8a:28:fa:8e:8c:4b brd ff:ff:ff:ff:ff:ff
    inet 10.244.0.0/32 scope global flannel.1
       valid_lft forever preferred_lft forever
24: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
    link/ether ee:b2:9e:95:af:9d brd ff:ff:ff:ff:ff:ff
    inet 10.244.0.1/24 scope global cni0
       valid_lft forever preferred_lft forever
29: vethb547248d@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP group default 
    link/ether 8e:f6:51:f5:9b:a3 brd ff:ff:ff:ff:ff:ff link-netnsid 2

因為這裡使用了cni介面標準,這個veth卡會橋接在cni0的網橋上。這個我們可以通過brctl show進行檢視。

[root@node-64-216 ~]# brctl show
bridge name bridge id       STP enabled interfaces
cni0        8000.eeb29e95af9d   no      vethb547248d
                            vethe527455b
                            vetheb3a1d6b

資料包走到了cni0的網橋後,根據已經的目標ip,10.244.1.2,可以查詢路由表,根據路由和掩碼,選擇對應的iface,也就是flannel.1。且下一跳,也就是10.244.1.0。

[root@node-64-216 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.10.10.1       0.0.0.0         UG    0      0        0 em1
10.10.10.0       0.0.0.0         255.255.255.0   U     0      0        0 em1
10.244.0.0      0.0.0.0         255.255.255.0   U     0      0        0 cni0
10.244.1.0      10.244.1.0      255.255.255.0   UG    0      0        0 flannel.1

進入到flannel.1如何知道應該發向哪個物理機呢。這個時候,其實是通過arp來獲取。可以通過arp命令檢視到對應的mac地址。

[root@node-64-216 ~]# arp -e
Address                  HWtype  HWaddress           Flags Mask            Iface
10.244.1.0               ether   3e:01:ed:47:de:7f   CM                    flannel.1

這個mac地址在vxlan中,可以通過bridge fdb show來進行檢視。可以看到,如果是發向3e:01:ed:47:de:7f的地址,則目標機器在10.10.10.217機器上。則資料就會流轉到10.10.10.217上了。經過vxlan封包後的資料包就會經過em1裝置發向到10.10.10.217上。

[root@node-64-216 ~]# bridge fdb show
3e:01:ed:47:de:7f dev flannel.1 dst 10.10.10.217 self permanent

在10.10.10.217上,首先經過了iptables鏈,而後在flannel.1的Iface上則接收到該資料包。這裡我們可以看到,flannel.1的mac地址就是3e:01:ed:47:de:7f

這裡我曾經就是遇到過被iptables的forward鏈攔住的情況。如果資料包在216的flannel.1上可以監測到,但是217的flannel.1中斷了,則可以檢查216到217之間的路由情況以及217的iptables鏈的情況。

[root@node-64-217 ~]# ip add
2: em1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 90:b1:1c:33:b4:b1 brd ff:ff:ff:ff:ff:ff
    inet 10.10.10.217/24 brd 10.10.10.255 scope global em1
       valid_lft forever preferred_lft forever
152: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default 
    link/ether 3e:01:ed:47:de:7f brd ff:ff:ff:ff:ff:ff
    inet 10.244.1.0/32 scope global flannel.1
       valid_lft forever preferred_lft forever
153: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
    link/ether 36:11:ab:93:2f:6f brd ff:ff:ff:ff:ff:ff
    inet 10.244.1.1/24 scope global cni0
       valid_lft forever preferred_lft forever
154: veth7f8b8e9e@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP group default 
    link/ether 06:2f:35:74:cd:de brd ff:ff:ff:ff:ff:ff link-netnsid 0

到達flannel.1後,根據路由表,檢視10.244.1.2的路由應送到217的cni0的網橋上。

[root@node-64-217 ~]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.10.10.1       0.0.0.0         UG    0      0        0 em1
10.10.10.0       0.0.0.0         255.255.255.0   U     0      0        0 em1
10.244.0.0      10.244.0.0      255.255.255.0   UG    0      0        0 flannel.1
10.244.1.0      0.0.0.0         255.255.255.0   U     0      0        0 cni0

這裡我們檢視cni0的網橋資訊。

[root@node-64-217 ~]# brctl show 
bridge name bridge id       STP enabled interfaces
cni0        8000.3611ab932f6f   no      veth5a89e906
                            veth7f8b8e9e

到達網橋後,就可以根據地址將資料送到10.244.1.2的對應的veth上,進而在容器中收到對應的資料包了。

以上就是兩個處於不同物理機上的容器間傳送資料包的流程。相比較來說,從容器到物理機的ping就簡單多了。這個流程就是veth->cni0->em1->對端物理機ip。這裡就不詳細敘述了。

同一臺物理機上不同容器的ping只需要經過cni0的網橋就可以了。

排障的主要思路

在梳理了資料包的正常流轉過程後,就可以用tcpdump來進行問題的定位,進而排查出哪個環節出現了問題,進而檢視問題產生的原因。

還是以兩個物理機上的兩個容器之間的通訊為例,可以從一個容器向另一個容器進行ping,然後使用tcpdump分別在發起ping的容器的物理機上抓cni0,flannel.1,以及目標容器的物理機上抓flannel.1,cni0上進行抓包。看看是在哪個環節丟失的資料包。

比如在發起ping的物理機的cni0上有資料包,但是發起ping的物理機的flannel.1上沒有,則可能路由發生了問題,需要檢視路由表。

又比如前文中提到過的在發起ping的容器的物理機上flannel.1上可以抓到資料包,但是在目標容器的物理機的flannel.1上抓不到,則可能是二者之間的路由問題或者iptables導致的。

參考資料

  • vxlan 協議原理簡介 https://cizixs.com/2017/09/25/vxlan-protocol-introduction/
  • VXLAN技術研究 https://blog.csdn.net/sinat_31828101/article/details/50504656
  • Flannel中vxlan backend的原理和實現 http://dockone.io/article/2216

相關文章