繼上篇文章:[Kubernetes]淺談容器網絡,自己給自己挖的坑,這篇文章來談談容器跨主機網絡.
要理解容器"跨主通信"的原理,就要來談談 Flannel 這個項目.
Flannel 項目是 CoreOS 公司主推的容器網絡方案.提供容器網絡功能的,分別是: VXLAN , host-gw , UDP .
這三種不同的實現,代表了三種容器跨主機網絡的主流實現方法.這里主要講 VXLAN 和 UDP 模式.
先從 UDP 模式講起.
- 宿主機 Node 1 上有一個容器 container-1 ,它的 IP 地址是 100.96.1.2 ,對應的 docker0 網橋的地址是: 100.96.1.1/24
- 宿主機 Node 2 上有一個 container-2 , 它的 IP 地址是 100.96.2.3 ,對應的 docker0 網橋的地址是: 100.96.2.1/24
我們現在的任務,就是讓 container-1 訪問 container-2 .
這種情況下, container-1 容器里的進程發起的 IP 包,其源地址就是 100.96.1.2 , 目的地址就是 100.96.2.3 .由於目的地址 100.96.2.3 並不在 Node 1 的 docker0 網橋的網段里,所以這個 IP 包會被交給默認路由規則,通過容器的網關進入 docker0 網橋,從而出現在宿主機上.
這時候,這個 IP 包的下一個目的地,就取決於宿主機上的路由規則了.此時, Flannel 已經在宿主機上創建出一系列的路由規則,以 Node1 為例,來看一下:
# 在 Node 1 上
$ ip route
default via 10.168.0.1 dev eth0
100.96.0.0/16 dev flannel0 proto kernel scope link src 100.96.1.0
100.96.1.0/24 dev docker0 proto kernel scope link src 100.96.1.1
10.168.0.0/24 dev eth0 proto kernel scope link src 10.168.0.2
我們能夠看到,由於 IP 包的目的地址是 100.96.2.3 ,它現在匹配不到本機 docker0 網橋對應的 100.96.1.0/24 網段,只能匹配到第二條,也就是 100.96.0.0/16 對應的這條路由規則,從而進入到一個叫作 flannel0 的設備中.這個 flannel0 設備是一個 TUN 設備( Tunnel 設備)
在 Linux 中, TUN 設備是一種工作在三層( Network Layer )的虛擬網絡設備. TUN 設備的功能非常簡單,就是:在操作系統內核和用戶應用程序之間傳遞 IP 包.
此時, IP 包根據路由表進入 flannel0 設備后,宿主機上的 flanneld進程,就會收到這個 IP 包,然后根據目的地址將它發送給 Node2 宿主機.
那么, flanneld 是如何知道這個 IP 地址對應的容器,是運行在 Node2 上面的呢?
在由 Flannel 管理的容器網絡中,一台宿主機上的所有容器,都屬於該宿主機被分配的一個"子網",在上面舉的例子中, Node1 的子網是 100.96.1.0/24 , container-1 的 IP 地址是 100.96.1.2 . Node2 的子網是 100.96.2.0/24 , container-2 的 IP 地址是 100.96.2.3
而這些子網與宿主機的對應關系,保存在 Etcd 中.所以, flanneld 進程在處理 IP 包時,可以根據目的 IP 的地址,匹配到對應的子網,在 Etcd 中找到這個子網對應的宿主機的 IP 地址即可.
當然,這個請求得以完成的原因是,每台宿主機上的 flanneld ,都監聽着一個 8285 端口,所以 flanneld 只要把 UDP 包發往 Node2 的 8285 端口即可.接下來就是 flanneld 會直接把這個 IP 包發送給它所管理的 TUN 設備,即 flannel0 設備.,此時 Linux 內核網絡棧就會負責處理這個 IP 包,根據相關規則,把這個 IP 包轉發給 docker0 網橋.接下來的流程大家就清楚了(如果忘記了,可以再回去看看:[Kubernetes]淺談容器網絡), docker0 網橋會扮演二層交換機的角色,將數據包發送給正確的端口,進而通過 Veth Pair 設備到 container-2 的 Network Namespace 中.
以上就是大概的一個流程.
來一張圖,看看會不會理解的更好一些:
我們能夠看到, Flannel UDP 模式提供的其實是一個三層的 Overlay 網絡,即:它首先對發出端的 IP 包進行 UDP 封裝,然后在接收端進行解封裝拿到原始的 IP 包,進而把這個 IP 包轉發給目標容器.
但是UDP模式有嚴重的性能問題,相比於兩台宿主機之間的直接通信,基於 Flannel UDP 模式的容器通信多了一個額外的步驟,即 flanneld 的處理過程.因為這個過程中,由於使用到了 flannel0 這個 TUN 設備,所以僅僅在發出 IP 包的這個過程中,就需要經過用戶態與內核態之間的數據拷貝,具體如下所示:
但是我們在進行系統級編程時,有一個非常重要的優化原則,就是要減少用戶態到內核態的切換次數,並且把核心的處理邏輯都放在內核態進行.
基於這個問題,咱們來看看 VXLAN 模式.
VXLAN(即 Virtual Extensible LAN 虛擬可擴展局域網),是 Linux 內核本身就支持的一種網絡虛擬化技術,因此 VXLAN 完全可以在內核態上實現上述封裝和解封裝的工作,從而通過與前面類似的"隧道"機制,構建出覆蓋網絡( Overlay Network ).
VXLAN 的覆蓋網絡的設計思想是:在現有的三層網絡上,“覆蓋"一層虛擬的,由內核 VXLAN 模塊負責維護的二級網絡,使得連接在這個 VXLAN 二層網絡上的"主機”(虛擬機或者容器都可以)之間,可以像在同一個局域網( LAN )里那樣自由通信,當然,實際上這些"主機"可能分布在不同的宿主機上,甚至是分布在不同的物理機房里.而為了能夠在二層網絡上打通"隧道", VXLAN 會在宿主機上設置一個特殊的網絡設備作為"隧道"的兩端,這個設備就叫作 VTEP(即: VXLAN Tunnel End Point 虛擬隧道端點). VTEP 設備的作用,和 flanneld 進程非常相似,只是它進行封裝和解封裝的對象,是二層數據幀,並且這個工作的執行流程,是在內核中完成的.來看一下示意圖:
圖中每台宿主機上名叫 flannel.1 的設備,就是 VXLAN 所需的 VTEP 設備,它既有 IP 地址,也有 MAC 地址.而接下來 Flannel VXLAN 模式的具體工作方式,就和實際網絡中工作的方式差不多了.
VXLAN 模式組建的覆蓋網絡,其實就是一個由不同宿主機上的 VTEP 設備,也就是 flannel.1 設備組成的虛擬二層網絡,對於 VTEP 設備來說,它發出的"內部數據幀"就仿佛是一直在這個虛擬的二層網絡上流動一樣,而這也正是「覆蓋網絡」的含義.
以上內容來自我學習<深入剖析Kubernetes>專欄文章之后的一些見解,有偏頗之處,還望指出.
感謝您的閱讀~