整理自《Docker進階與實戰》docker
爲了解決容器網絡性能低下、功能不足的問題,Docker啓動了子項目「Libnetwork」。Libnetwork提出了新的容器網絡模型(Container Network Model,簡稱CNM),定義了標準的API用於爲容器配置網絡,其底層能夠適配各類網絡驅動(如圖Docker-network01所示)。CNM有三個:shell
沙盒
沙盒是一個隔離的網絡運行環境,保存了容器網絡棧的配置,包括了對網絡接口、路由表和DNS配置的管理。在Linux平臺上,沙盒是用Linux Network Namespace實現的,在其餘平臺上多是不一樣的概念,如FreeBSD Jail。一個沙盒能夠包括來自多個網絡的多個Endpoint(端點)。ubuntu
Endpoint
Endpoint將沙盒加入一個網絡,Endpoint的實現能夠是一對veth pair或者OVS內部端口,當前的Libnetwork使用的是veth pair。一個Endpoint只能隸屬於一個沙盒及一個網絡。經過給沙盒增長多個Endpoint能夠將一個沙盒加入多個網絡。segmentfault
網絡
網絡包括一組能互相通訊的Endpoint。網絡的實現能夠是Linux bridge、vlan等。 安全
從CNM的概念角度講,Libnetwork的出現使得Docker具有了跨主機多子網的能力,同一個子網內的不一樣容器能夠運行在不一樣主機上。好比,同屬於192.168.0.0/24子網IP地址分別爲192.168.0.1和192.168.0.2的容器能夠位於不一樣的主機上且能夠直接通訊,而持有IP 192.168.1.1的容器即便與IP爲192.168.0.1的容器處於同一主機也不能互通。bash
Libnetwork已經實現了五種驅動(driver):網絡
bridge
Docker默認的容器網絡驅動。Container經過一對veth pair鏈接到docker0網橋上,由Docker爲容器動態分配IP及配置路由、防火牆規則等。函數
host
容器與主機共享同一Network Namespace,共享同一套網絡協議棧、路由表及iptables規則等。容器與主機看到的是相同的網絡視圖。性能
null
容器內網絡配置爲空,須要用戶手動爲容器配置網絡接口及路由等。spa
remote
Docker網絡插件的實現。Remote driver使得Libnetwork能夠經過HTTP RESTful API對接第三方的網絡方案,相似SocketPlane的SDN方案只要實現了約定的HTTP URL處理函數及底層的網絡接口配置方法,就能夠替換Docker原生的網絡實現。
overlay
Docker原生的跨主機多子網網絡方案。主要經過使用Linux bridge和vxlan隧道實現,底層經過相似於etcd或consul的KV存儲系統實現多機的信息同步。overlay驅動當前還未正式發佈,但開發者能夠經過編譯實驗版的Docker來嘗試使用,Docker實驗版同時提供了額外的network和service子命令來進行更靈活的網絡操做,不過,須要內核版本>=3.16纔可正常使用。
以上五種驅動已經隨Docker 1.8一同發佈。
Linux平臺下,Docker容器網絡資源經過內核的Network Namespace機制實現隔離,不一樣的Network Namespace有各自的網絡設備、協議棧、路由表、防火牆規則等,反之,同一Network Namespace下的進程共享同一網絡視圖。經過對Network Namespace的靈活操縱,Docker提供了五種容器網絡模式。
none
不爲容器配置任何網絡功能。
在該模式下,須要以-–net=none
參數啓動容器
$ docker run --net=none -ti ubuntu:latest ip addr show
使用-–net=none
啓動容器以後,仍然能夠手動爲容器配置網絡。
container
與另外一個運行中的容器共享Network Namespace,共享相同的網絡視圖。
舉個例子,首先以默認網絡配置(bridge模式)啓動一個容器,設置hostname
爲dockerNet
,dns
爲8.8.4.4
。
$ docker run -h dockerNet --dns 8.8.4.4 -tid ubuntu:latest bash 964286222ab53c67b2d6fb1882b2364c745be718a4a13530b016fe51b4968054
而後以–-net=container:96428
方式啓動另外一個容器
$ docker run --net=container:96428 -ti ubuntu:latest bash
進入容器,經過ip addr show
命令能夠發現兩個容器的IP地址、DNS、hostname都是相同的。實質上兩個容器是共享同一個Network Namespace的,網絡配置天然也是徹底相同的。
host
與主機共享Root Network Namespace,容器有完整的權限能夠操縱主機的協議棧、路由表和防火牆等,因此被認爲是不安全的。
相應的,host模式啓動時須要指定-–net=host
參數。舉個例子
$ docker run -ti --net=host ubuntu:latest bash
host模式下,容器能夠操縱主機的網絡配置,這是危險的,除非萬不得已,應該儘量避免使用host模式。
bridge
Docker設計的NAT網絡模型。
Docker daemon啓動時會在主機建立一個Linux網橋(默認爲docker0,可經過-b參數手動指定)。容器啓動時,Docker會建立一對veth pair(虛擬網絡接口)設備,veth設備的特色是成對存在,從一端進入的數據會同時出如今另外一端。Docker會將一端掛載到docker0網橋上,另外一端放入容器的Network Namespace內,從而實現容器與主機通訊的目的。bridge模式下的網絡拓撲圖如圖docker-network02所示:
在橋接模式下,Docker容器與Internet的通訊,以及不一樣容器之間的通訊,都是經過iptables規則控制的。總之,Docker網絡的初始化動做包括:建立docker0網橋、爲docker0網橋新建子網及路由、建立相應的iptables規則等。Bridge模式是Docker默認的容器運行模式,以bridge模式啓動的容器,默認會從172.17.42.1/16子網內分配IP。
overlay
Docker原生的跨主機多子網模型。
overlay網絡模型比較複雜,底層須要相似consul或etcd的KV存儲系統進行消息同步,核心是經過Linux網橋與vxlan隧道實現跨主機劃分子網。如圖Docker-network03所示,每建立一個網絡,Docker會在主機上建立一個單獨的沙盒,沙盒的實現實質上是一個Network Namespace。在沙盒中,Docker會建立名爲br0的網橋,並在網橋上增長一個vxlan接口,每一個網絡佔用一個vxlan ID,當前Docker建立vxlan隧道的ID範圍爲256~1000,於是最多能夠建立745個網絡。當添加一個容器到某一個網絡上時,Docker會建立一對veth網卡設備,一端鏈接到此網絡相關沙盒內的br0網橋上,另外一端放入容器的沙盒內,並設置br0的IP地址做爲容器內路由默認的網關地址,從而實現容器加入網絡的目的。
以圖Docker-network03爲例,容器1和容器4同屬一個網絡,容器1須要經過256號vxlan隧道訪問另外一臺主機的容器4。Docker經過vxlan和Linux網橋實現了跨主機的虛擬子網功能。
使用shell命令查看overlay網絡拓撲
# 建立網絡 $ docker network create -d overlay dev # 顯示網絡列表 $ docker network ls 9101d162c6db bridge bridge fcd0327f5104 dev overlay f5f9c8723777 none null eb81445767e1 host host # fcd0327f5104實質上是dev網絡的網絡ID,建立軟連接的目的是爲了可以使用ip命令操縱名字空間。 # ln -s /var/run/docker/netns/fcd0327f5104 /var/run/netns/fcd0327f5104 # 查看端口詳細信息 $ ip netns exec fcd0327f5104 ip addr show # 查看網橋信息 $ ip netns exec fcd0327f5104 brctl show # 查看vxlan詳細信息 $ ip netns exec fcd0327f5104 ip -d link show vxlan1
綜上所述,Docker的整個網絡模型,是創建在Network Namespace、Linux網橋、vxlan隧道、iptables規則之上的,也正是因爲過於依賴網橋與iptables,致使Docker的網絡效率不高。
關於Docker網絡相關參數請參考「Docker(1.11.1)命令」。
待續···