Docker 網絡
Docker 的網絡實現其實就是利用了 Linux 上的網絡名稱空間和虛擬網絡設備(特別是 veth pair)。
Linux 網絡命名空間:https://www.jianshu.com/p/369e50201bce
Linux虛擬網絡設備之veth:?https://segmentfault.com/a/1190000009251098
監控和調整Linux網絡堆棧:接收數據:https://blog.packagecloud.io/eng/2016/06/22/monitoring-tuning-linux-networking-stack-receiving-data/
Linux網絡-數據包的發送過程:https://segmentfault.com/a/1190000008926093
Docker網絡核心原理? ?http://blog.51cto.com/ganbing/2087598
?
基本原理
首先,要實現網絡通信,機器需要至少一個網絡接口(物理接口或虛擬接口)來收發數據包;此外,如果不同子網之間要進行通信,需要路由機制。
Docker 中的網絡接口默認都是虛擬的接口。虛擬接口的優勢之一是轉發效率較高。Linux 通過在內核中進行數據復制來實現虛擬接口之間的數據轉發,發送接口的發送緩存中的數據包被直接復制到接收接口的接收緩存中。
對于本地系統和容器內系統看來就像是一個正常的以太網卡,只是它不需要真正同外部網絡設備通信,速度要快很多。
Docker 容器網絡就利用了這項技術。它在本地主機和容器內分別創建一個虛擬接口,并讓它們彼此連通(這樣的一對接口叫做?veth pair
)。
?
veth設備的特點
?
- veth和其它的網絡設備都一樣,一端連接的是內核協議棧。
- veth設備是成對出現的,另一端兩個設備彼此相連
- 一個設備收到協議棧的數據發送請求后,會將數據發送到另一個設備上去。
?
參考自??http://blog.51cto.com/ganbing/2087598? ??https://segmentfault.com/a/1190000009251098
使用docker run命令創建一個執行shell(/bin/bash)的Docker容器,假設容器名稱為con1。
? ? ?在con1容器中可以看到它有兩個網卡lo和eth0。lo設備不必多說,是容器的回環網卡;eth0即為容器與外界通信的網卡,eth0的ip 為 172.17.0.2/16,和宿主機上的網橋docker0在同一個網段。
? ? ?查看con1的路由表,可以發現con1的默認網關正是宿主機的docker0網卡,通過測試, con1可以順利訪問外網和宿主機網絡,因此表明con1的eth0網卡與宿主機的docker0網卡是相互連通的。
? ? ?這時再來查看(ifconfig)宿主機的網絡設備,會發現有一塊以"veth"開頭的網卡,如veth60b16bd,我們可以大膽猜測這塊網卡肯定是veth設備了,而veth pair總是成對出現的。veth pair通常用來連接兩個network namespace,
? ? ?那么另一個應該是Docker容器con1中的eth0了。之前已經判斷con1容器的eth0和宿主機的docker0是相連的,那么veth60b16bd也應該是與docker0相連的,不難想到,docker0就不只是一個簡單的網卡設備了,而是一個網橋。
? ? ?真實情況正是如此,下圖即為Docker默認網絡模式(bridge模式)下的網絡環境拓撲圖,創建了docker0網橋,并以eth pair連接各容器的網絡,容器中的數據通過docker0網橋轉發到eth0網卡上。
? ? 這里的網橋概念等同于交換機,為連在其上的設備轉發數據幀。網橋上的veth網卡設備相當于交換機上的端口,可以將多個容器或虛擬機連接在上面,這些端口工作在二層,所以是不需要配置IP信息的。
? ? 圖中docker0網橋就為連在其上的容器轉發數據幀,使得同一臺宿主機上的Docker容器之間可以相互通信。
? ? 大家應該注意到docker0既然是二層設備,它上面怎么設置了IP呢?docker0是普通的linux網橋,它是可以在上面配置IP的,可以認為其內部有一個可以用于配置IP信息的網卡接口
? ?(如同每一個Open vSwitch網橋都有一個同名的內部接口一樣)。在Docker的橋接網絡模式中,docker0的IP地址作為連于之上的容器的默認網關地址存在。
在Linux中,可以使用brctl命令查看和管理網橋(需要安裝bridge-utils軟件包),比如查看本機上的Linux網橋以及其上的端口:
# yum install bridge-utils
# brctl show? ?//四個虛擬接口
bridge name bridge id STP enabled interfaces docker0 8000.02428f0e6a12 no veth6a95f3bveth6d97324veth7314b3evethb2e752fvethdb62bce
更多關于brctl命令的功能和用法,大家通過man brctl或brctl --help查閱。
? ? docker0網橋是在Docker daemon啟動時自動創建的,其IP默認為172.17.0.1/16,之后創建的Docker容器都會在docker0子網的范圍內選取一個未占用的IP使用,并連接到docker0網橋上。
? ? 除了使用docker0網橋外,還可以使用自己創建的網橋,比如創建一個名為br0的網橋,配置IP:
# ip link show? ? //veth7314b3e和if8是一對
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000link/ether 00:0c:29:ee:53:1e brd ff:ff:ff:ff:ff:ff
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 02:42:8f:0e:6a:12 brd ff:ff:ff:ff:ff:ff
9: veth7314b3e@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether 42:a0:eb:96:15:cf brd ff:ff:ff:ff:ff:ff link-netnsid 0
11: vethb2e752f@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether 5a:8e:fa:1c:7f:8d brd ff:ff:ff:ff:ff:ff link-netnsid 1
13: veth6d97324@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether 4a:2f:07:20:53:15 brd ff:ff:ff:ff:ff:ff link-netnsid 2
17: vethdb62bce@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether 8a:1a:78:56:07:d8 brd ff:ff:ff:ff:ff:ff link-netnsid 3
19: veth6a95f3b@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether aa:02:b6:a3:44:87 brd ff:ff:ff:ff:ff:ff link-netnsid 4
?
iptables規則
?Docker安裝完成后,將默認在宿主機系統上增加一些iptables規則,以用于Docker容器和容器之間以及和外界的通信,可以使用iptables-save命令查看。其中nat表中的POSTROUTING鏈有這么一條規則:
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
參數說明:
-s :源地址172.17.0.0/16
-o:指定數據報文流出接口為docker0
-j :動作為MASQUERADE(地址偽裝)
?? 上面這條規則關系著Docker容器和外界的通信,含義是:將源地址為172.17.0.0/16的數據包(即Docker容器發出的數據),當不是從docker0網卡發出時做SNAT。
? ? 這樣一來,從Docker容器訪問外網的流量,在外部看來就是從宿主機上發出的,外部感覺不到Docker容器的存在。
?? 那么,外界想到訪問Docker容器的服務時該怎么辦呢?我們啟動一個簡單的web服務容器,觀察iptables規則有何變化。
?
OVS:全稱是Open VSwitch,就是一個虛擬交換機,用于虛擬機VM環境。在虛擬化環境中,一個虛擬交換機主要有兩個作用:傳遞虛擬機VM之間的通信,以及實現VM和外界網絡的通信。
OVS主要由以下4層組成:
虛擬網卡:位于虛擬機內,在虛擬機創建后,會掛載在OVS上,每個虛擬網卡都有不同的MAC地址。
虛擬交換層:通過2個ovs虛擬交換機完成通信。OVS除提供基本網絡交換外,還提供一些高級功能,如NetFlow等。
bond層:bond是由linux提供的將多個物理網卡綁定在一起的技術,另一種說法叫trunk。Bond模式主要有:負載平衡、主備模式。目前主要使用的是主備模式,在主備模式下,有一個網卡是主用狀態,其它網卡均是備用狀態。這一層是可選的,如果沒有這一層,物理網卡可以直接掛在ovs上。
物理網卡:真正執行收發包的物理設備,一般都會掛載在trunk上,常見的物理網卡有Intel 82599 10G網卡、Intel 82576 1G網卡、Intel I350 1G網卡、SIGMA mellanox 10G網卡。
按照這樣的解釋,應該就比較清楚了。
OVS與傳統的硬件交換機工作原理也沒什么區別,就是基于MAC地址實現報文的交換。
host? ?https://blog.csdn.net/wangguohe/article/details/81535942
容器不會獲得一個獨立的network namespace,而是與宿主機共用一個。
在容器中使用ifconfig查看網絡發現顯示的是宿主機的網絡
host
父進程在創建子進程時,如果不使用```CLONE_NEWNET```這個參數標志,那么創建出的子進程會與父 進程共享同一個網絡namespace。
Docker就是采用了這個簡單的原理,在創建進程啟動容器的過程中,沒有傳入CLONE_NEWNET
參數標志,實現Docker Container與宿主機共享同一個網絡環境,即實現host網絡模式。
優勢:
- 可以直接使用宿主機的IP地址與外界進行通信,若宿主機的eth0是一個公有IP,那么容器也擁有這個公有IP。
- 同時容器內服務的端口也可以使用宿主機的端口,無需額外進行NAT轉換。
缺陷:
- 最明顯的是Docker Container網絡環境隔離性的弱化,即容器不再擁有隔離、獨立的網絡棧。
- 使用host模式的Docker Container雖然可以讓容器內部的服務和傳統情況無差別、無改造的使用,但是由于網絡隔離性的弱化,該容器會與宿主機共享競爭網絡棧的使用;
- 容器內部將不再擁有所有的端口資源,原因是部分端口資源已經被宿主機本身的服務占用,還有部分端口已經用以bridge網絡模式容器的端口映射。
none
獲取獨立的network namespace,但不為容器進行任何網絡配置,之后用戶可以自己進行配置,容器內部只能使用loopback網絡設備,不會再有其他的網絡資源。
創建docker網絡
# docker network ls
NETWORK ID NAME DRIVER SCOPE
5ebae7e509fa bridge bridge local //默認網絡
b255b50dc21e host host local
db26f5263d07 none null local
# docker container run --help
?--network string? ? ? ? ? ? ? ? ?Connect a container to a network (default "default")? ?//string指明要使用哪個網絡,默認是bridge
# docker network inspect bridge? ? //查看bridge的信息
# docker container inspect web1? ?//查看容器web1的詳細信息
?