聊聊 Ulti-Network Ns 在Underlay下的應用-本手篇
大家好,我是二哥。
對容器而言,multiple namespace 這個技術的重要性怎么強調都不過分。因為 namespace 的出現,使得容器所用到的諸如 Hostname、Network、Mount Points 等資源被隔離起來,由公用變成獨享。
技術的進步是一把雙刃劍,基于 multi namespace 的容器在幾乎重塑了云計算市場的形態和云計算機基礎設施棧的同時,也給我們帶來了陡峭的學習曲線。
Network namespace 就是這樣一個例子。
今年全國新高考 Ⅰ 卷的作文題看了吧?“本手、妙手、俗手”是圍棋的三個術語。本手是指合乎棋理的正規下法;妙手是指出人意料的精妙下法;俗手是指貌似合理,而從全局看通常會受損的下法。對于初學者而言,應該從本手開始,本手的功夫扎實了,棋力才會提高。一些初學者熱衷于追求妙手,而忽視更為常用的本手。本手是基礎,妙手是創造。一般來說,對本手理解深刻,才可能出現妙手;否則,難免下出俗手,水平也不易提升。
來吧,這篇讓我們從“本手”開始。下篇我們看“妙手”部分:將本文所聊內容稍作變形看看 multi network namespace 在 Underlay 下面是如何玩的。
multi network namespace
我們先就著下圖來看看 multi network namespace 的典型使用方式。后文統一將 network namespace 寫成 network ns 。
圖 1:一個包含 multi network ns 的環境
這是一個包含 multi network ns 的環境。分為三大部分:最上層為 OS ,中間是一個網卡(物理的或者虛擬的),最下面是網卡所連接的外部(物理)網絡。
OS 部分包含了 root network ns 以及被 Pod 使用的其它 network ns 。
OS 部分還包含了 eth 和 bridge 這樣的網絡設備(struct net_device)。雖然圖中不同的 network ns 中的 eth 都叫 eth0 ,但 root network ns 中的 eth0 和其它網絡設備有著本質的區別:
- root network ns 中的 eth0 是對網卡的軟件抽象,也就是說它對應的是一個外部設備,如果這個網卡是物理的話,eth0 還包含控制該設備的一系列函數。
- 而圖中其它的 eth0 和 bridge 都是對根本不存在的虛擬網絡設備的抽象,說白了它們就只是一些不會與外部設備打交道的數據結構,這些數據結構存在的意義是為了可以最大程度上復用現有的代碼邏輯和功能。它們可以作為媒介用來在同一個 OS 內進行進程間通信、用戶態和內核態數據交換,但無法被用于外部通信。比如我們熟知的 loopback 設備,通過它可以使本機上兩個進程間的 socket 通信完整地走完 TCP/IP 協議棧。
network namespace
我們說 network ns 用來隔離包括網卡(Network Interface)、回環設備(Loopback Device)、網絡棧、IP 地址、端口等等在內的網絡資源。它的特點是由可配置的數據組成。對于一個進程來說,這些要素,其實就構成了它發起和響應網絡請求的基本環境。這里所謂“網絡棧(Networking stack)”,包括了:路由表(Routing Table), network filter,iptables 規則等。
無論是一個 Linux 容器還是宿主機的進程所能看見的“網絡棧”,實際上是被隔離在它們各自的 network ns 當中的,通信雙方的網卡(如典型的 veth pair )也自然被隔離到相應的 namespace 中。
另外還有一個棧也會被經常提起:TCP/IP 協議棧。我們可以將 TCP/IP 協議棧看成是程序的代碼部分,而網絡棧看成是程序的數據部分。很顯然 TCP/IP 棧應該是被這個 OS 上所有人共享的,無論是進程還是容器,甚至是基于 qemu-kvm 的虛擬機都共享著宿主機的協議棧,但網絡棧卻是各個 network ns 獨享的。
二哥知道,上面的描述還是太抽象。所以我畫了下面一張圖。圖 2 把內核中負責描述進程的數據結構 task_struct 和 network ns 之間的結構關系畫出來了。進程 1 和進程 2 共享宿主機 root network ns,它包含網卡 eth0 。Pod 內的容器自然位于 Pod 自己的 network ns 中。但容器本質上也是進程而已,雖然在圖中看起來 Pod 隔離了一個完全屬于自己的 eth1,但在內核看來,一樣也是用相同的數據結構來描述它和 network ns 之間的關系。
看完這個數據結構示意圖,對于 TCP/IP 協議棧而言,希望下面兩點描述沒有讓你感到困惑:
- 網絡包無論是從容器內的網卡流出,還是離開容器后再與其它網絡設備打交道,必然都會經過內核 TCP/IP 協議棧。
- 無論網絡包是屬于容器的還是屬于宿主機 native process 的,對于內核 TCP/IP 協議棧而言,這些網絡包只是屬于不同的 network ns 而已。
圖 2:network ns與task_struct結構關系圖
網絡設備
你一定看到了圖 1 的 OS 部分包含網絡設備 eth0 和 bridge。
其中 eth0 用來描述物理網卡,它在內核中用數據結構 net_device 來表示。一個 net_device 里面都包含些什么呢?我將其中一些重要的部分畫在了圖 3 里面。簡單來說就是包含了用來操作這個物理網卡的 netdev_ops (如 set _mac / ioctl 之類),與 BSP 相關的諸如總線地址、IRQ等設置,與具體網卡型號相關的收/發環形隊列,還有 IP 地址設置等等。
因為 eth0 是屬于一個 network ns 的,這就意味著如果有多個 network ns ,就可能會出現多個 eth0(如果都重命名為 eth0 的話)。
圖 3:net_device 所含部分內容示意圖
bridge 又名網橋,是一個虛擬的二層交互機。用它來搭配虛擬網絡設備 veth / tap 可以模擬物理交換機以及插入其上的 RJ-45 網絡插頭。
在圖 4 所示的這個環境里,一個網橋可以組成一個簡單子局域網,插在網橋上的設備之間可以如物理局域網絡那樣相互通過二層交流。這樣的交流不需要離開 bridge ,這通常發生在位于同一個 Work Node 上面的不同 Pod 之間相互通信的場景。
圖 4:veth + bridge 所組成的子局域網
而如果網絡包的目的 MAC 地址為網橋本身,并且網橋設置了 IP 地址的話,那么 bridge 就認為該網絡包應該是發往創建該網橋的那臺主機,于是這個數據包將不會轉發到任何設備,而是直接交給上層(三層)協議棧去處理。處理的過程會涉及到基于本機路由表的路由查詢。
上述過程可以結合圖 5 來理解。例如當 Pod 想要訪問百度的時候,請求就會沿著圖中紅色的線流動。如果我們將紅線看成一個管道的話,那么 Pod 的請求從管道一端流入。而管道的流出端接進了宿主機協議棧的 IP 層。在這里經過 iptables 和路由表的處理后,最終通過宿主機的 eth0 離開這臺機器。
這種情況下,如果我說宿主機的 eth0 可以看成 bridge 的 gateway,你同意嗎?
如果你對這個細節感興趣的話,可以閱讀《當從Pod訪問百度時會用到VTEP嗎》。
圖 5:bridge 將 traffic 交由宿主機三層處理
讓我們把圖 5 再放大一些。把圖 5 中 network ns 里的路由表、 iptables 、eth0 、bridge 拎出來看看。看看當 bridge 處理 Pod 訪問百度的請求時,是如何把流量先送進 root network ns 又是如何以宿主機為 gateway 將流量送至外部網絡的。
圖 6:bridge 處理數據流放大示意圖