容器網路
本文學習總結自 極客時間 深入剖析Kubernetes 。
單宿主機容器網路互通
容器通過Veth Pair連線到docker0網橋上,實現了容器與容器之間,容器與宿主機之間的網路互通。
- Veth: virtual Ethernet devices
- Veth Pair: 一對虛擬乙太網裝置,可以看作現實生活中的網線,能在不同namespace下傳輸流量
YouTube視訊: Linux VETH Pair - Virtual Ethernet Pair
2個容器之間直接通過Veth Pair可以實現網路互通,但如果有n個容器之間需要互通的話,就可能需要建立n(n-1)/2個Veth Pair,就跟現實生活中需要把很多臺計算機實現網路互通一樣。
在現實生活中,通常是採用網橋,只需要將每臺計算機通過一根網線連線在網橋上,那麼計算機之間就可以實現網路互通了。
所以可以通過在作業系統上虛擬出一個網橋裝置,將容器通過Veth Pair連線到網橋上,實現容器之間網路互通。
YouTube視訊: Docker Advanced Networking
使用bridge網路的容器,路由表類似這樣子:
DestinationGatewayGenmaskFlags Metric RefUse Iface default172.17.0.10.0.0.0UG000 eth0 172.17.0.00.0.0.0255.255.0.0U000 eth0
對於172.17.0.0/16網段的路由是一條直連規則,凡是匹配到這條規則的IP包,應該經過eth0網絡卡,通過二層網路直接發往目的主機,因為當前主機和目的主機連線在同一個網橋上。而對於其他IP包,則需要發給閘道器,閘道器會根據自己的路由資訊對資料包進行轉發。
跨宿主機容器網路互通
Overlay Network(覆蓋網路):通過軟體構建一個覆蓋宿主機網路之上的、可以把所有容器連通在一起的虛擬網路。
Flannel UDP
flannel0:Tunnel裝置,一種工作在三層的虛擬網路裝置,在作業系統核心和使用者應用程式之間傳遞IP包。
每臺宿主機上的所有容器會被分配到一個子網中。
flanneld程序在處理fannel0傳入的IP包時,就可以根據目的IP地址,匹配到對應的子網,找到這個子網對應的宿主機的IP地址,將IP包直接封裝在UDP包裡,發給對應的宿主機。
該模式的效能問題在於多了4次使用者態和核心態之間的資料拷貝:
Flannel VXLAN
VXLAN:Virtual Extensible LAN(虛擬可擴充套件區域網),是 Linux 核心本身就支援的一種網路虛似化技術。VXLAN 可以完全在核心態實現UDP模式的封裝和解封裝的工作。
VTEP: VXLAN Tunnel End Point(虛擬隧道端點),在核心態進行封裝和解封裝,物件是二層資料幀。
VXLAN 模式組建的覆蓋網路,其實就是一個由不同宿主機上的 VTEP 裝置,也就是 flannel.1 裝置組成的虛擬二層網路。對於 VTEP 裝置來說,它發出的“內部資料幀”就彷彿是一直在這個虛擬的二層網路上流動。這,也正是覆蓋網路的含義。
Flannel host-gw
在宿主機路由表裡,將每個 Flannel 子網的“下一跳”,設定成了該子網對應的宿主機的 IP 地址。該模式要求叢集宿主機之間是二層連通的。
Calico
不同於 Flannel 通過 Etcd 和宿主機上的 flanneld 來維護路由資訊的做法,Calico 專案使用了BGP來自動地在整個叢集中分發路由資訊。
BGP 的全稱是 Border Gateway Protocol,即:邊界閘道器協議。它是一個 Linux 核心原生就支援的、專門用在大規模資料中心裡維護不同的“自治系統”之間路由資訊的、無中心的路由協議。
自治系統,指的是一個組織管轄下的所有 IP 網路和路由器的全體。兩個自治系統裡的主機,要通過 IP 地址直接進行通訊,我們就必須使用路由器把這兩個自治系統連線起來。
邊界閘道器:把自治系統連線在一起的路由器。它跟普通路由器的不同之處在於,它的路由表裡擁有其他自治系統裡的主機路由資訊。
在使用了 BGP 之後,你可以認為,在每個邊界閘道器上都會執行著一個小程式,它們會將各自的路由表資訊,通過 TCP 傳輸給其他的邊界閘道器。而其他邊界閘道器上的這個小程式,則會對收到的這些資料進行分析,然後將需要的資訊新增到自己的路由表裡。
除了對路由資訊的維護方式之外,Calico 專案與 Flannel 的 host-gw 模式的另一個不同之處,就是它不會在宿主機上建立任何網橋裝置。
Calico 維護的網路在預設配置下,是一個被稱為“Node-to-Node Mesh”的模式。這時候,每臺宿主機上的 BGP Client 都需要跟其他所有節點的 BGP Client 進行通訊以便交換路由資訊。但是,隨著節點數量 N 的增加,這些連線的數量就會以 N²的規模快速增長,從而給叢集本身的網路帶來巨大的壓力。
所以,Node-to-Node Mesh 模式一般推薦用在少於 100 個節點的叢集裡。而在更大規模的叢集中,你需要用到的是一個叫作 Route Reflector 的模式。
在這種模式下,Calico 會指定一個或者幾個專門的節點,來負責跟所有節點建立 BGP 連線從而學習到全域性的路由規則。而其他節點,只需要跟這幾個專門的節點交換路由資訊,就可以獲得整個叢集的路由規則資訊了。
這些專門的節點,就是所謂的 Route Reflector 節點,它們實際上扮演了“中間代理”的角色,從而把 BGP 連線的規模控制在 N 的數量級上。
Calico 要求叢集宿主機之間是二層連通的,如果要實現三層連通的宿主機之間的容器網路互聯,就需要開啟Calico IPIP模式。
Calico 使用的這個 tunl0 裝置,是一個 IP 隧道(IP tunnel)裝置。
在上面的例子中,IP 包進入 IP 隧道裝置之後,就會被 Linux 核心的 IPIP 驅動接管。IPIP 驅動會將這個 IP 包直接封裝在一個宿主機網路的 IP 包中,如下所示:
當 Calico 使用 IPIP 模式的時候,叢集的網路效能會因為額外的封包和解包工作而下降。在實際測試中,Calico IPIP 模式與 Flannel VXLAN 模式的效能大致相當。所以,在實際使用時,如非硬性需求,建議將所有宿主機節點放在一個子網裡,避免使用 IPIP。
避免使用 Calico IPIP 模式的方案:
- 所有宿主機都跟宿主機閘道器建立 BGP Peer 關係,要求宿主機閘道器必須支援一種叫作 Dynamic Neighbors 的 BGP 配置方式。這是因為,在常規的路由器 BGP 配置裡,運維人員必須明確給出所有 BGP Peer 的 IP 地址。考慮到 Kubernetes 叢集可能會有成百上千個宿主機,而且還會動態地新增和刪除節點,這時候再手動管理路由器的 BGP 配置就非常麻煩了。而 Dynamic Neighbors 則允許你給路由器配置一個網段,然後路由器就會自動跟該網段裡的主機建立起 BGP Peer 關係。
- 使用一個或多個獨立元件負責蒐集整個叢集裡的所有路由資訊,然後通過 BGP 協議同步給閘道器。在大規模叢集中,Calico 本身就推薦使用 Route Reflector 節點的方式進行組網。所以,這裡負責跟宿主機閘道器進行溝通的獨立元件,直接由 Route Reflector 兼任即可。這種情況下閘道器的 BGP Peer 個數是有限並且固定的。所以我們就可以直接把這些獨立元件配置成路由器的 BGP Peer,而無需 Dynamic Neighbors 的支援。這些獨立元件的工作原理也很簡單:它們只需要 WATCH Etcd 裡的宿主機和對應網段的變化資訊,然後把這些資訊通過 BGP 協議分發給閘道器即可。
三層網路方案和”隧道模式”方案的異同
- 相同:都實現了跨宿主機容器的三層連通。
- 不同:三層網路方案通過配置下一跳主機的路由規則來實現連通,”隧道模式”方案通過在IP包外再封裝一層UDP包來實現連通。
- 三層網路方案:Flannel host-gw、Calico
- 優點:少了封包和解包的過程,效能高
- 缺點:需要想辦法維護路由規則
- “隧道模式”方案:Flannel UDP、Flannel VXLAN、Calico IPIP
- 優點:簡單,大部分工作可以由Linux 核心的模組實現
- 缺點:效能低