Docker的bridge和macvlan兩種網絡模式
項目上部署的Docker集群創建的容器網絡遇到問題,借機會學習了一下docker的網絡模式,其他類型我們用的不多,這裏只列舉我們常用的bridge和macvlan兩種,下面的描述和截圖有一些是直接從網上下載的。
Bridge模式
Bridge模式是Docker默認的網絡模式,當Docker進程啟動時,會在主機上創建一個名為docker0的虛擬網橋,用來連接宿主機和容器,此主機上的Docker容器都會連接到這個虛擬網橋上,虛擬網橋的工作方式和物理交換機類似,這樣所有容器就通過交換機連在了一個二層網絡中。
Docker利用 veth pair技術,在宿主機上創建了兩個虛擬網絡接口 veth0 和 veth1(veth pair技術的特性可以保證無論哪一個veth 接收到網絡報文,都會無條件地傳輸給另一方),Docker將veth pair設備的一端放在新創建的容器中,並命名為eth0(容器的網卡,從docker0子網中分配一個IP給容器使用,並設置docker0的IP地址為容器的默認網關),另一端放在主機中,以vethxxx這樣類似的名字命名,並將這個網絡設備加入到docker0網橋中。可以通過brctl show命令查看,這樣容器和網橋就可以相互通信了。網絡結構如下圖:
容器與宿主機通信 : 在橋接模式下,Docker Daemon將veth0附加到docker0網橋上,保證宿主機的報文有能力發往veth0。再將veth1 添加到Docker 容器所屬的網絡命名空間,保證宿主機的網絡報文若發往 veth0 可以立即被 veth1 收到。
容器與外界通信 : 容器如果需要聯網,則需要采用 NAT(是一種在 ip 數據包通過路由器或防火墻時,重寫來源 ip 地址或目的 ip 地址的技術) 方式。準確的說,是 NATP (網絡地址端口轉換) 方式。NATP 包含兩種轉換方式:SNAT 和 DNAT 。
- 宿主機外訪問容器時(修改數據包的目的地址):
由於容器的 IP 與端口對外都是不可見的,所以數據包的目的地址為宿主機
數據包經過路由器發給宿主機 eth0,再經 eth0 轉發給 docker0 網橋。由於存在 DNAT 規則,會將數據包的目的地址轉換為容器的 ip 和端口,為 172.17.0.n:24 。
宿主機上的 docker0 網橋識別到容器 ip 和端口,於是將數據包發送附加到 docker0 網橋上的 veth0 接口,veth0 接口再將數據包發送給容器內部的 veth1 接口,容器接收數據包並作出響應。
整個過程如下圖:
- 容器訪問宿主機之外時(修改數據包的源地址)
此時數據包的源地址為容器的 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 容器對外是不可見的。
整個過程如下圖:
macvlan模式
macvlan本身是linxu kernel的模塊,本質上是一種網卡虛擬化技術。其功能是允許在同一個物理網卡上虛擬出多個網卡,通過不同的MAC地址在數據鏈路層進行網絡數據的轉發,一塊網卡上配置多個 MAC 地址(即多個 interface),每個interface可以配置自己的IP,Docker的macvlan網絡實際上就是使用了Linux提供的macvlan驅動
因為多個MAC地址的網絡數據包都是從同一塊網卡上傳輸,所以需要打開網卡的混雜模式ip link set eth0 promisc on;
創建macvlan網絡不同於橋接模式,需要指定網段和網關,並且都得是真實存在的,例如docker network create -d macvlan --subnet=10.9.8.0/24 --gateway=10.9.8.254 -o parent=eth0 macvlan-test
macvlan模式不依賴網橋,所以brctl show查看並沒有創建新的bridge,但是查看容器的網絡,會看到虛擬網卡對應了一個interface是2
查看宿主機的網絡,2正是虛機的網卡
可見,容器的 eth0 就是宿主機的eth0通過macvlan虛擬出來的interface。容器的interface直接與主機的網卡連接,這種方案使得容器無需通過NAT和端口映射就能與外網直接通信(只要有網關),在網絡上看起來與其他獨立主機沒有區別。當前網絡結構如圖所示:
macvlan會獨占主機的網卡,也就是說一個網卡只能創建一個macvlan 網絡,否則會報錯,為了能支持更多的macvlan網絡,macvlan不僅可以連接到interface(如eth0),也可以連接到網卡的子接口sub-interface(如eth0.xxx)。
VLAN 是現代網絡常用的網絡虛擬化技術,它可以將物理的二層網絡劃分成多達 4094 個邏輯網絡,這些邏輯網絡在二層上是隔離的,每個邏輯網絡(即 VLAN)由 VLAN ID 區分,VLAN ID 的取值為 1-4094。Linux 的網卡也能支持 VLAN(apt-get install vlan),同一個 interface可以收發多個VLAN 的數據包,不過前提是要創建 VLAN的 sub-interface。比如希望 eth0同時支持 VLAN10 和 VLAN20,則需創建 sub-interface eth0.10 和 eth0.20。創建的子接口是可以看到的,如下如
在交換機上,如果某個端口只能收發單個VLAN的數據,該port為Access模式,如果支持多個VLAN,則為Trunk模式,要實現多個macvlan,網卡要接在交換機的 trunk口上。
例如給網卡創建了10、20兩個子接口後,分別創建容器後的網絡結構如下圖:
Docker的bridge和macvlan兩種網絡模式