我們這里假設flannel使用VXLAN協議。每台主機都安裝有flannel。k8s定義的flannel網絡為10.0.0.0/16,各主機的flannel從這個網絡申請一個子網。pod1所在的主機的flannel子網為10.0.14.1/24,pod2所在主機的flannel子網為10.0.5.1/24。每台主機有cni0和flannel.1虛擬網卡。cni0為在同一主機pod共用的網橋,當kubelet創建容器時,將為此容器創建虛擬網卡vethxxx,並橋接到cni0網橋。flannel.1是一個tun虛擬網卡,接收不在同一主機的POD的數據,然后將收到的數據轉發給flanneld進程。原理圖:

pod1到pod2的網絡
pod1路由表:
ip route show
default via 10.0.14.1 dev eth0 10.0.0.0/16 via 10.0.14.1 dev eth0 10.0.14.0/24 dev eth0 proto kernel scope link src 10.0.14.15
host1路由表:
default via 192.168.93.254 dev eno16777984 proto static metric 100 10.0.0.0/16 dev flannel.1 10.0.14.0/24 dev cni0 proto kernel scope link src 10.0.14.1 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 192.168.93.0/24 dev eno16777984 proto kernel scope link src 192.168.93.212 metric 100
pod1 IP地址:10.0.14.15
pod2 IP地址:10.0.5.150
備注:舉例路由注釋
[root@k8s-master-15-81 ~]# ip route show default via 192.168.15.1 dev ens160 proto static metric 100 10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1 #訪問本機直接在本機直接轉發,而不需要其他接口,這就是directrouting 10.244.1.0/24 via 192.168.15.82 dev ens160 #看到現在訪問10.244.1.0,通過本地物理網卡ens160上的192.168.15.82送出去,即通過物理網卡通信了,而不再通過隧道flannel通信。
pod1與pod2不在同一台主機
下面是從pod1 ping pod2的數據包流向
1. pod1(10.0.14.15)向pod2(10.0.5.150)發送ping,查找pod1路由表,把數據包發送到cni0(10.0.14.1)
2. cni0查找host1路由,把數據包轉發到flannel.1
3. flannel.1虛擬網卡再把數據包轉發到它的驅動程序flannel
4. flannel程序使用VXLAN協議封裝這個數據包,向api-server查詢目的IP所在的主機IP,稱為host2(不清楚什么時候查詢)
5. flannel向查找到的host2 IP的UDP端口8472傳輸數據包
6. host2的flannel收到數據包后,解包,然后轉發給flannel.1虛擬網卡
7. flannel.1虛擬網卡查找host2路由表,把數據包轉發給cni0網橋,cni0網橋再把數據包轉發給pod2
8. pod2響應給pod1的數據包與1-7步類似
下面是這次ping數據包的wireshark解析出的協議數據:
pod1 ping請求:

pod2響應:

pod1與pod2在同一台主機
pod1和pod2在同一台主機的話,由cni0網橋直接轉發請求到pod2,不需要經過flannel。
pod到service的網絡
創建一個service時,相應會創建一個指向這個service的域名,域名規則為{服務名}.{namespace}.svc.{集群名稱}。之前service ip的轉發由iptables和kube-proxy負責,目前基於性能考慮,全部為iptables維護和轉發。iptables則由kubelet維護。service僅支持udp和tcp協議,所以像ping的icmp協議是用不了的,所以無法ping通service ip。
現在我們嘗試看看在pod1向kube-dns的service ip 10.16.0.10:53發送udp請求是如何轉發的。
我們先找出與此IP相關的iptables規則:
【PREROUTING鏈】 -m comment --comment "kubernetes service portals" -j KUBE-SERVICES 【KUBE-SERVICES鏈】 -d 10.16.0.10/32 -p udp -m comment --comment "kube-system/kube-dns:dns cluster IP" -m udp --dport 53 -j KUBE-SVC-TCOU7JCQXEZGVUNU 【KUBE-SVC-TCOU7JCQXEZGVUNU鏈】 -m comment --comment "kube-system/kube-dns:dns" -j KUBE-SEP-L5MHPWJPDKD7XIFG 【KUBE-SEP-L5MHPWJPDKD7XIFG鏈】 -p udp -m comment --comment "kube-system/kube-dns:dns" -m udp -j DNAT --to-destination 10.0.0.46:53
- pod1向service ip 10.16.0.10:53發送udp請求,查找路由表,把數據包轉發給網橋cni0(10.0.14.1)
- 在數據包進入cnio網橋時,數據包經過PREROUTING鏈,然后跳至KUBE-SERVICES鏈
- KUBE-SERVICES鏈中一條匹配此數據包的規則,跳至KUBE-SVC-TCOU7JCQXEZGVUNU鏈
- KUBE-SVC-TCOU7JCQXEZGVUNU不做任何操作,跳至KUBE-SEP-L5MHPWJPDKD7XIFG鏈
- KUBE-SEP-L5MHPWJPDKD7XIFG里對此數據包作了DNAT到10.0.0.46:53,其中10.0.0.46即為kube-dns的pod ip
- 查找與10.0.0.46匹配的路由,轉發數據包到flannel.1
- 之后的數據包流向就與上面的pod1到pod2的網絡一樣了
pod到外網
- pod向qq.com發送請求
- 查找路由表,轉發數據包到宿主的網卡
- 宿主網卡完成qq.com路由選擇后,iptables執行MASQUERADE,把源IP更改為宿主網卡的IP
- 向qq.com服務器發送請求
tun虛擬網卡介紹
虛擬網卡Tun/tap驅動是一個開源項目,支持很多的類UNIX平台,OpenVPN和Vtun都是基於它實現隧道包封裝。本文將介紹tun/tap驅動的使用並分析虛擬網卡tun/tap驅動程序在linux環境下的設計思路。
tun/tap 驅動程序實現了虛擬網卡的功能,tun表示虛擬的是點對點設備,tap表示虛擬的是以太網設備,這兩種設備針對網絡包實施不同的封裝。利用tun/tap 驅動,可以將tcp/ip協議棧處理好的網絡分包傳給任何一個使用tun/tap驅動的進程,由進程重新處理后再發到物理鏈路中。開源項目 openvpn( http://openvpn.sourceforge.net)和Vtun( http://vtun.sourceforge.net)都是利用tun/tap驅動實現的隧道封裝。
https://www.cnblogs.com/woshiweige/p/4534660.html
參考:
https://www.centos.bz/2017/06/k8s-flannel-network/#pod%E5%88%B0service%E7%9A%84%E7%BD%91%E7%BB%9C
