Docker默認的網絡環境下,單台主機上的Docker容器可以通過docker0網橋直接通信,而不同主機上的Docker容器之間只能通過在主機上做端口映射進行通信。這種端口映射方式對很多集群應用來說極不方便。如果能讓Docker容器之間直接使用自己的IP地址進行通信,會解決很多問題。按實現原理可分別直接路由方式、橋接方式(如pipework)、Overlay隧道方式(如flannel、ovs+gre)等。
docker0網關修改:
首先刪除舊的網絡
$ sudo ip link set dev docker0 down $ sudo brctl delbr docker0
修改 /etc/docker/daemon.json,改變默認docker0網關
{ "bip": "192.188.0.1/16”, }
查看
$ ifconfig docker0 docker0 Link encap:Ethernet HWaddr 02:42:38:60:08:25 inet addr:192.188.0.1 Bcast:0.0.0.0 Mask:255.255.0.0 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
或者手動創建一個新的網橋bridge0
$ sudo brctl addbr bridge0 $ sudo ip addr add 192.188.0.1/16 dev bridge0 $ sudo ip link set dev bridge0 up $ ip addr show bridge0 4: bridge0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state UP group default link/ether 66:38:d0:0d:76:18 brd ff:ff:ff:ff:ff:ff inet 192.188.0.1/16 scope global bridge0 valid_lft forever preferred_lft forever
在 Docker 配置文件/etc/docker/daemon.json 中添加如下內容,即可將Docker默認橋接到 創建的網橋上。
{ "bridge": "bridge0", }
直接路由
通過在Docker主機上添加靜態路由實現跨宿主機通信:

Pipework
Pipework是一個簡單易用的Docker容器網絡配置工具。由200多行shell腳本實現。通過使用ip、brctl、ovs-vsctl等命令來為Docker容器配置自定義的網橋、網卡、路由等。
- 使用新建的br0網橋代替缺省的docker0網橋
- br0網橋與缺省的docker0網橋的區別:br0和主機eth0之間是veth pair

如圖,不同容器之間的通信可以借助pipework這個工具給docker容器新建虛擬網卡並綁定IP橋接到br0
Flannel(Flannel + UDP 或者 Flannel + VxLAN)

Flannel實現的容器的跨主機通信通過如下過程實現:
- 每個主機上安裝並運行etcd(或其它分布式健值存儲數據庫)和flannel;
- 在etcd中規划配置所有主機的docker0子網范圍;Flannel為每個主機自動分配獨立的subnet,用戶只需要指定一個大的IP池。不同subnet之間的路由信息也由Flannel自動生成和配置。
- 每個主機上的flanneld根據etcd中的配置,為本主機的docker0分配子網,保證所有主機上的docker0網段不重復,並將結果(即本主機上的docker0子網信息和本主機IP的對應關系)存入etcd庫中,這樣etcd庫中就保存了所有主機上的docker子網信息和本主機IP的對應關系(相當於通過etcd服務維護了一張節點間的路由表);
- 當需要與其他主機上的容器進行通信時,查找etcd數據庫,找到目的容器的子網所對應的outip(目的宿主機的IP);
- 將原始數據包封裝在VXLAN或UDP數據包中,IP層以outip為目的IP進行封裝;
- 由於目的IP是宿主機IP,因此路由是可達的:數據從源容器發出后,經由所在主機的docker0虛擬網卡轉發到flannel0虛擬網卡(P2P虛擬網卡),flanneld服務監聽在flannel0網卡的另一端,它將原本是數據內容封裝后根據自己的路由表投遞給目的節點的flanneld服務。
- VXLAN或UDP數據包到達目的宿主機解封裝,解出原始數據包,最終到達目的容器。
PS:Flannel網絡有兩種模式:上述是一種overlay覆蓋網絡,而host-gw模式將主機作為網關,依賴於純三層的ip轉發;
缺點:不同Flannel網絡中的容器可以直接通信,Flannel沒有提供網絡隔離。與外網通信需要通過bridge網絡。
Weave
Weave網絡也是一種overlay覆蓋網絡;
Weave自己負責在主機間交換網絡配置信息,不需要etcd或consul這些數據庫;
Weave默認配置下所有容器使用10.32.0.0/12的subnet,如果此地址空間與現有IP沖突,則可以通過--ipalloc-range分配特定的subnet。
Weave網絡默認配置下所有容器在一個大的subnet中,可以自由通信。如果要實現網絡隔離,需要為容器指定不同的subnet或IP;若要與外網通信,則需要將主機加入到weave網絡,並把主機當作網關。
Calico
Calico是一個純三層的方案,為虛機及容器提供多主機間通信,沒有使用重疊網絡(如flannel)驅動,采用虛擬路由代替虛擬交換,每一台虛擬路由器通過BGP協議傳播可達信息(路由)到其他虛擬或物理路由器。
Calico通過IP Pool可以為每個主機定制自己的subnet。
Calico默認配置下只允許同一網絡中的容器之間通信,但通過其強大的Policy能夠實現幾乎任意場景的訪問控制。

calico包括如下重要組件:
- Felix:Calico agent,運行在每台workload節點。主要負責路由配置以及ACLS規則的配置以及下發,確保endpoint的連通狀態。
- etcd:分布式鍵值存儲,主要負責網絡元數據一致性,確保Calico網絡狀態的准確性,可以與kubernetes共用;
- BGP Client:主要負責把Felix寫入kernel的路由信息分發到當前Calico網絡,確保workload間的通信的有效性;
- BGP Route Reflector:大規模部署時使用,摒棄所有節點互聯的mesh模式,通過一個或者多個BGPRoute Reflector來完成集中式的路由分發。
如下圖所示,描述了從源容器經過源宿主機,經過數據中心的路由,然后到達目的宿主機最后分配到目的容器的過程。

整個過程中始終都是根據iptables規則進行路由轉發,並沒有進行封包、解包的過程。而flannel在進行路由轉發的基礎上進行了封包解包的操作,浪費了CPU的計算資源。
下圖是從網上找到的各個開源網絡組件的性能對比。可以看出無論是帶寬還是網絡延遲,calico和主機的性能是差不多的。
