探索 Docker bridge 的正確姿勢,親測有效!

a1drup41g3 8年前發布 | 27K 次閱讀 Docker 網絡設備

上一回合,小白折騰了 Docker 架構,鐵要趁熱我開始學習 Docker 容器網絡。此刻的心情,是激動的,也是不安的。激動是因為終于要面對 Docker 的第一座大山 : 網絡 ,不安是因為網絡問題一直以來都是小白的軟肋,那些年我們一起學過的網絡知識,如今……

硬著頭皮翻開《 Docker 進階與實戰 》開始 Docker 網絡初探,里面講述了 Docker 容器網絡的好幾種模式。其中 “ bridge” 模式 成功的吸引了我的注意。bridge 模式俗稱橋接模式,關于它的定義小白早就忘了,但不難理解的是 bridge 的作用, bridge 可以連接不同的東西。

早期的二層網絡中,bridge 可以連接不同的 LAN 網,如下圖所示。當主機 1 發出一個數據包時,LAN 1 的其他主機和網橋 br0 都會收到該數據包。網橋再將數據包從入口端復制到其他端口上(本例中就是另外一個端口)。因此,LAN 2 上的主機也會接收到主機 A 發出的數據包,從而實現不同 LAN 網上所有主機的通信。

隨著網絡技術的發展,傳統 bridge 衍生出適用不同應用場景的模式,其中最典型要屬 Linux bridge 模式,它是 Linux Kernel 網絡模塊的一個重要組成部分,用以保障不同虛擬機之間的通信,或是虛擬機與宿主機之間的通信,如下圖所示 :

依葫蘆畫瓢,Docker bridge 十有八九是用來連接不同容器,或是連接容器與宿主機的。

帶著疑問,我快速瀏覽了這個章節,結果是大驚從早到晚失色,書中的介紹比我預想的復雜很多,Docker bridge 模式不僅使用了 veth pair  技術,還使用了 網絡命名空間技術 ,更令我吃驚的是,Docker bridge 模式下竟然采用了  NAT  方式。Docker bridge 和 Linux bridge 二者,初看如出一轍,再看又相去甚遠,還真是傻傻分不清楚。沒想到我的容器網絡學習計劃,剛起步便遭遇了滑鐵盧。

沒有搞清楚 Docker bridge 與 Linux bridge 的區別前,這書簡直沒法看了。依小白的經驗,云里霧里的時候摸清楚基本概念最有效,先從 Linux bridge 模式的基本工作原理入手,再從 Docker bridge 模式下的 “黑科技” (veth pair、網絡命名空間技術、NAT)入手 ,或許能找出點頭緒。壓抑住內心的憤懣,我翻開了《 深入理解 LINUX 網絡技術的內幕 》,找尋這些關鍵字的足跡。

?Linux bridge 模式

Linux bridge 模式下,Linux Kernel 會創建出一個 虛擬網橋 ,用以實現 主機網絡 接口虛擬網絡接口 間的通信。從功能上來看,Linux bridge 像一臺虛擬交換機,所有橋接設置的虛擬機分別連接到這個交換機的一個接口上,接口之間可以相互訪問且互不干擾,這種連接方式對物理主機而言也是如此。

在橋接的作用下,虛擬網橋會把主機網絡接口接收到的網絡流量轉發給虛擬網絡接口,于是后者能夠接收到路由器發出的 DHCP(動態主機設定協議,用于獲取局域網 IP)信息及路由更新。這樣的工作流程,同樣適用于不同虛擬網絡接口間的通信。具體的實現方式如下所示:

虛擬機與宿主機通信: 用戶可以手動為虛擬機配置IP 地址、子網掩碼,該 IP 需要和宿主機 IP 處于同一網段,這樣虛擬機才能和宿主機進行通信。

虛擬機與外界通信: 如果虛擬機需要聯網,還需為它手動配置網關,該網關也要和宿主機網關保持一致。

除此之外,還有一種較為簡單的方法,那就是虛擬機通過 DHCP 自動獲取 IP,實現與宿主機或宿主機以外的世界通信,小白親測有效。

Docker bridge 模式

大致清楚 Linux bridge 模式后,再來看 Docker bridge 模式,小白也有了信心。再次翻開《 Docker 進階與實戰》,仔細閱讀后小白了解到在該 bridge 模式下,Docker Daemon 會創建出一個名為 docker0 的 虛擬網橋 ,用來連接 宿主機容器 ,或者連接 不同的容器 ,書中的介紹與小白之前的假設也不謀而合。

Docker 利用 veth pair [注釋1]技術,在宿主機上創建了兩個虛擬網絡接口 veth0 和 veth1(veth pair 技術的特性可以保證無論哪一個 veth 接收到網絡報文,都會無條件地傳輸給另一方)。

容器與宿主機通信: 在橋接模式下,Docker Daemon 將 veth0 附加到 docker0 網橋上,保證宿主機的報文有能力發往 veth0。再將 veth1 添加到 Docker 容器所屬的網絡命名空間[注釋2],保證宿主機的網絡報文若發往 veth0 可以立即被 veth1 收到。

容器與外界通信: 容器如果需要聯網,則需要采用 NAT [注釋2] 方式。準確的說,是 NATP (網絡地址端口轉換) 方式。NATP 包含兩種轉換方式:SNAT 和 DNAT 。

  • 目的 NAT (Destination NAT,DNAT): 修改數據包的目的地址。

當宿主機以外的世界需要訪問容器時,數據包的流向如下圖所示:

由于容器的 IP 與端口對外都是不可見的,所以數據包的目的地址為 宿主機 的  ip端口 ,為 192.168.1.10:24 。

數據包經過路由器發給宿主機 eth0,再經 eth0 轉發給 docker0 網橋。由于存在 DNAT 規則,會將數據包的目的地址轉換為 容器 的  ip 端口 ,為 172.17.0.n:24 。

宿主機上的 docker0 網橋識別到容器 ip 和端口,于是將數據包發送附加到 docker0 網橋上的 veth0 接口,veth0 接口再將數據包發送給容器內部的 veth1 接口,容器接收數據包并作出響應。

  • 源 NAT (Source NAT,SNAT): 修改數據包的源地址。

當容器需要訪問宿主機以外的世界時,數據包的流向為下圖所示:

此時數據包的源地址為 容器 ip端口 ,為 172.17.0.n:24,容器內部的 veth1 接口將數據包發往 veth0 接口,到達 docker0 網橋。

宿主機上的 docker0 網橋發現數據包的目的地址為外界的 IP 和端口,便會將數據包轉發給 eth0 ,并從 eth0 發出去。由于存在 SNAT 規則,會將數據包的源地址轉換為 宿主機ip 端口 ,為 192.168.1.10:24 。

由于路由器可以識別到宿主機的 ip 地址,所以再將數據包轉發給外界,外界接受數據包并作出響應。這時候,在外界看來,這個數據包就是從 192.168.1.10:24 上發出來的,Docker 容器對外是不可見的。

小結

小白的容器網絡學習只是剛剛開了頭,竟也能折騰出這么多玩兒意,有 veth pair,有網絡命名空間, 還有 NAT 。雖說 docker bridge 模式僅僅是容器網絡的冰山一角,后面的學習之路仍然且行且艱辛,但小白也掌握了一些學習經驗,那就是面對錯綜復雜的網絡模式,首先需要識其筋骨勝肉,抓住本質含義。小白就是憑著對 bridge 的理解,才展開了一系列大膽的假設,帶著問題最終在書中得到求證。Disappointing, but not fatal。

[注釋1] veth pair是用于不同network namespace間進行通信的方式,veth pair 將一個 network namespace 數據發往另一個 network namespace 的 veth。

[注釋2] 網絡命名空間是用于隔離網絡資源(/proc/net、IP 地址、網卡、路由等)。由于一個物理的網絡設備最多存放在一個網絡命名空間中,所以通過 veth pair 在不同的網絡命名空間中創建通道,才能達到通信的目的。

[注釋3] NAT 為網絡地址轉換(Network Address Translation)的縮寫,是一種在 ip 數據包通過路由器或防火墻時重寫來源 ip 地址或目的 ip 地址的技術。

 

 

來自:http://blog.daocloud.io/docker-bridge/

 

 本文由用戶 a1drup41g3 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!