網(wǎng)絡(luò)無處不在及穗,每當(dāng)基礎(chǔ)設(shè)施出現(xiàn)問題,被抱怨的通常是網(wǎng)絡(luò)丰嘉。很大一部分原因是誓焦,網(wǎng)絡(luò)負(fù)責(zé)連接一切——無網(wǎng)絡(luò)予借,無APP狞换。
11.1 Docker網(wǎng)絡(luò)——簡介
Docker在容器內(nèi)部運(yùn)行應(yīng)用现柠,這些應(yīng)用之間的交互依賴于大量不同的網(wǎng)絡(luò),這意味著Docker 需要強(qiáng)大的網(wǎng)絡(luò)功能论矾。
幸運(yùn)的是章姓,Docker對于容器之間、容器與外部網(wǎng)絡(luò)和VLAN之間的連接均有相應(yīng)的解決方案孝扛。后者對于那些需要跟外部系統(tǒng)(如虛擬機(jī)和物理機(jī))的服務(wù)打交道的容器化應(yīng)用來說至關(guān)重要臼勉。
Docker網(wǎng)絡(luò)架構(gòu)源自一種叫做容器的網(wǎng)絡(luò)模型(CNM)的方案论笔,該方案是開源的并且支持插式連接。Libnetwork式Docker對CNM的一種實(shí)現(xiàn)忆家,提供了Docker核心網(wǎng)絡(luò)架構(gòu)的全部功能。不同的驅(qū)動可以通過插拔的方式接入Libnerwork來提供定制化的網(wǎng)絡(luò)拓?fù)洹?/p>
為了實(shí)現(xiàn)開箱即用的效果袭蝗,Docker封裝了一系列本地驅(qū)動闰蚕、覆蓋了大部分常見的網(wǎng)絡(luò)需求。其中包括單機(jī)橋接網(wǎng)絡(luò)、多級覆蓋網(wǎng)絡(luò)剃斧,并且支持接入現(xiàn)有的VLAN。Docker生態(tài)系統(tǒng)中的合作伙伴通過提供驅(qū)動的方式丑婿,進(jìn)一步拓展了Docker的網(wǎng)絡(luò)功能。
最后要說的是煤蚌,Libnetwork提供了本地服務(wù)發(fā)現(xiàn)和基礎(chǔ)的容器負(fù)載均衡的解決方案耕挨。
11.2 Docker網(wǎng)絡(luò)——詳解
11.2.1 基礎(chǔ)理論
在頂層設(shè)計中,Docker網(wǎng)絡(luò)架構(gòu)由3個主要部分構(gòu)成:CNM尉桩、Libnetwork和驅(qū)動筒占。
其中CNM是涉及標(biāo)準(zhǔn),在CNM中蜘犁,規(guī)定了Docker網(wǎng)絡(luò)架構(gòu)的基礎(chǔ)組成要素翰苫;Libnetwork是CNM的具體實(shí)現(xiàn),并且被Docker采用奏窑。Libnetwork通過Go語言編寫导披,并實(shí)現(xiàn)了CNM中列舉的核心組件。驅(qū)動通過實(shí)現(xiàn)特定網(wǎng)絡(luò)拓?fù)涞姆绞絹硗卣乖撃P偷哪芰Α?/p>
1.CNM
CNM定義了3個基本要素:沙盒(Sandbox)良哲、終端(Endpoint)盛卡、和網(wǎng)絡(luò)(Network)。
沙盒是一個獨(dú)立的網(wǎng)絡(luò)棧筑凫。其中包括以太網(wǎng)接口滑沧、端口、路由表以及DNS配置巍实;終端就是虛擬網(wǎng)絡(luò)接口滓技。就像是普通的網(wǎng)絡(luò)接口一樣,終端主要職責(zé)是負(fù)責(zé)創(chuàng)建連接棚潦。在CNM中令漂,終端負(fù)責(zé)將沙盒連接到網(wǎng)絡(luò);網(wǎng)絡(luò)就是 802.1d網(wǎng)橋(交換機(jī))的軟件實(shí)現(xiàn)丸边。因此叠必,網(wǎng)絡(luò)就是需要交互的終端的集合,并且終端之間相互獨(dú)立妹窖。
Docker環(huán)境中最小的調(diào)度單位就是容器纬朝,而CNM也恰如其名,負(fù)責(zé)為容器提供網(wǎng)絡(luò)功能骄呼。下圖展示了CNM組件時如何與容器進(jìn)行關(guān)聯(lián)的——沙盒放置在容器內(nèi)部共苛,為容器提供給網(wǎng)絡(luò)連接。
上圖可以看到蜓萄,容器A只有一個接口(終端)并連接到網(wǎng)絡(luò)A隅茎。容器B有兩個接口(終端)并且分別接入了網(wǎng)絡(luò)A和B。容器A和B之間時可以相互通信的嫉沽,因?yàn)槎冀尤肓司W(wǎng)絡(luò)A辟犀。但是,如果沒有三層路由器的支持绸硕,容器B的兩個終端之間時不能通信的堂竟。
這時候可以把容器類比為我們現(xiàn)實(shí)中的PC,一個PC可以有多個網(wǎng)卡接口(終端)臣咖,所以可以接入到不同網(wǎng)絡(luò)中跃捣。接入到同一網(wǎng)絡(luò)中的兩個容器可以相互通信漱牵,接入不同網(wǎng)絡(luò)的容器必須依賴三層路由才能實(shí)現(xiàn)通信夺蛇。
- Libnetwork
CNM是設(shè)計規(guī)范文檔,Libnetwork是標(biāo)準(zhǔn)的實(shí)現(xiàn)酣胀。在早期刁赦,網(wǎng)絡(luò)部分的代碼都存在daemon中娶聘,daemon顯得非常臃腫。后來Docker將該網(wǎng)絡(luò)部分從daemon中拆分甚脉,并重構(gòu)了一個叫做Libnetwork的外部類庫⊥枭現(xiàn)在,Docker核心網(wǎng)絡(luò)架構(gòu)代碼都在Libnetwork當(dāng)中牺氨。
Libnetwork除了實(shí)現(xiàn)CNM中定義的三個組件外狡耻,還實(shí)現(xiàn)了本地服務(wù)發(fā)現(xiàn)、基于 Ingress的容器負(fù)載均衡以及網(wǎng)絡(luò)控制層和管理層功能猴凹。
- 驅(qū)動
如果說Libnetwork實(shí)現(xiàn)了控制層和管理層功能夷狰,那么驅(qū)動就負(fù)責(zé)實(shí)現(xiàn)數(shù)據(jù)層。比如網(wǎng)絡(luò)連通性和隔離性就是由驅(qū)動來處理的郊霎,驅(qū)動層實(shí)際創(chuàng)建網(wǎng)絡(luò)對象也是如此沼头。
Docker封裝了若干內(nèi)置驅(qū)動,通常被叫做原生驅(qū)動或者本地驅(qū)動书劝。在Linux中包括Bridge进倍、overlay以及Macvlan,在Windows上包括NAT购对、Overlay猾昆、Transport以及L2 Bridge。當(dāng)然也有第三方的一些驅(qū)動洞斯。
每個驅(qū)動都負(fù)責(zé)其上所有網(wǎng)絡(luò)資源的創(chuàng)建和管理毡庆。為了滿足復(fù)雜且不固定的環(huán)境需求,Libnetwork支持同時激活多個網(wǎng)絡(luò)驅(qū)動烙如。這意味著Docker環(huán)境可以支持一個龐大的異構(gòu)網(wǎng)絡(luò)么抗。
11.2.2 單機(jī)橋接網(wǎng)絡(luò)
最簡單的Docker網(wǎng)絡(luò)就是單機(jī)橋接網(wǎng)絡(luò)了。從名稱中可以看到兩點(diǎn)亚铁。
- 單機(jī)意味著該網(wǎng)絡(luò)只能在單個Docker主機(jī)上運(yùn)行蝇刀,并且只能與所在Docker主機(jī)上的容器進(jìn)行連接。
- 橋接意味著這是 802.1d橋接的一種實(shí)現(xiàn)(二層交換機(jī))徘溢。
Linux Docker創(chuàng)建單機(jī)橋接網(wǎng)絡(luò)采用內(nèi)置的橋接驅(qū)動吞琐,而Windows Docker創(chuàng)建時使用內(nèi)置的NAT驅(qū)動。實(shí)際上然爆,著兩種驅(qū)動工作起來毫無差異站粟。
每個Docker主機(jī)都有一個默認(rèn)的單機(jī)橋接網(wǎng)絡(luò)。在Linux上網(wǎng)絡(luò)名稱為bridge曾雕,在Windows上叫做nat奴烙。除非讀者通過命令創(chuàng)建容器的時候指定參數(shù) --network ,否則默認(rèn)情況下,新創(chuàng)建的容器都會連接到該網(wǎng)絡(luò)上切诀。
使用docker network ls 可以查看Docker主機(jī)的網(wǎng)絡(luò)情況揩环,一開始只有一個默認(rèn)的網(wǎng)絡(luò)。
[pangcm@docker01 ~]$ docker network ls
NETWORK ID NAME DRIVER SCOPE
7cb75625ceeb bridge bridge local
使用 docker network inspect 命令可以查看網(wǎng)絡(luò)的更多內(nèi)容幅虑。
在Linux主機(jī)中丰滑,Docker網(wǎng)絡(luò)由Bridge驅(qū)動創(chuàng)建,而Bridge底層是基于Linux內(nèi)核中久經(jīng)考驗(yàn)達(dá)15年之久的Linux Bridge技術(shù)倒庵。這意味著Bridge是高性能并且非常穩(wěn)定的褒墨。同時這還表示可以通過標(biāo)準(zhǔn)的Linux去查看這些網(wǎng)絡(luò),比如 ip link show 擎宝。
[pangcm@docker01 ~]$ ip link show docker0
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:01:12:07:d9 brd ff:ff:ff:ff:ff:ff
在Linux Docker主機(jī)之上貌亭,默認(rèn)的 bridge 網(wǎng)絡(luò)被映射到內(nèi)核中為 docker0 的Linux網(wǎng)橋。所以认臊,我們也可以通過 dokcer network inspect 命令觀察到上面輸出的內(nèi)容圃庭。
我們除了可以使用默認(rèn)的bridge網(wǎng)絡(luò)之外,我們可以自己新建一個單機(jī)橋接的網(wǎng)絡(luò)失晴。使用 docker network create 命令創(chuàng)建剧腻。
docker network create -d bridge localnet
就這樣,新網(wǎng)絡(luò)創(chuàng)建成功涂屁,名為 localnet书在,我們可以使用docker network ls 去查看。和默認(rèn)的bridge網(wǎng)絡(luò)一樣拆又,新創(chuàng)建的網(wǎng)絡(luò)一樣在我們Docker 主機(jī)上新建一個Linux網(wǎng)橋儒旬。通過使用 brctl show 命令即可查看。
[pangcm@docker01 ~]$ brctl show
bridge name bridge id STP enabled interfaces
br-e6bca1080f16 8000.0242126f947e no
docker0 8000.0242011207d9 no
目前這兩個網(wǎng)絡(luò)都沒有任何設(shè)備的接入帖族,STP也沒有開啟栈源。下面我們新建一個容器,并加入到新建的橋接網(wǎng)絡(luò)中去竖般。
docker container run -d --name test2 --network localnet alpine sleep 1d
就這樣甚垦,新創(chuàng)建的容器加入了我們上面創(chuàng)建的網(wǎng)絡(luò)中去了』恋瘢可以通過 docker network inspect 命令去確認(rèn)艰亮。
[pangcm@docker01 ~]$ docker network inspect localnet format
...
"Containers": {
"e1e87148a8a3b06cf3315991a0502b82314721877c425a52657e4b1ec72e74ed": {
"Name": "test2",
"EndpointID": "e8903620447d66e987ea36dc332c5f65ec7ea8bdb922dfd8e7d6565dde892dbf",
"MacAddress": "02:42:ac:13:00:02",
"IPv4Address": "172.19.0.2/16",
"IPv6Address": ""
}
},
...
可以看到容器 test2 已經(jīng)加入到橋接網(wǎng)絡(luò) localnet上了,我們再次使用 brctl 查看下挣郭。
[pangcm@docker01 ~]$ brctl show
bridge name bridge id STP enabled interfaces
br-e6bca1080f16 8000.0242126f947e no vethbff0b42
docker0 8000.0242011207d9 no
前面我們有提到加入同一個橋接網(wǎng)絡(luò)的不同容器是可以相互通信的(同一個局域網(wǎng))迄埃,事實(shí)上在我們自定義的網(wǎng)絡(luò)中除了可以使用IP來進(jìn)行通信之外,還可以使用容器名稱去進(jìn)行通信(默認(rèn)的bridge不行)兑障。原因是新容器都會注冊到指定的Docker DNS 服務(wù)中侄非,所以相同網(wǎng)絡(luò)的容器可以解析其他容器的名稱伶棒。下面我們來測試下吧。
##新建一個 test3 容器彩库,加入localnet
docker container run -it --name test3 --network localnet alpine sh
##進(jìn)入到容器里面,我們直接ping test2
ping test2
可以驗(yàn)證ping命令是生效的先蒋。
在上面骇钦,我們驗(yàn)證了同一個Docker主機(jī)同一個橋接網(wǎng)絡(luò)之間的容器可以相互通信的。那么不同Docker主機(jī)上的橋接網(wǎng)絡(luò)容器可以相互通信么竞漾?答案是可以的眯搭,怎么做呢。
這個我們前面已經(jīng)驗(yàn)證過很多次了业岁,就是用端口映射鳞仙。把橋接網(wǎng)絡(luò)中的容器端口映射到Docker主機(jī)上,然后訪問Docker主機(jī)的端口流量就會轉(zhuǎn)發(fā)到Docker的端口上了笔时。例如我要把一個nginx 容器的80端口映射到Docker主機(jī)的8888端口上棍好。
docker container run -d --name test4 --network localnet -p 8888:80 nginx
在其他網(wǎng)絡(luò)上訪問Docker主機(jī)的8888端口就能訪問到Docker容器的80端口了。
11.2.3 多機(jī)覆蓋網(wǎng)絡(luò)
后面會有專門的介紹允耿,有點(diǎn)復(fù)雜借笙。
11.2.4 接入現(xiàn)有網(wǎng)絡(luò)
能夠?qū)⑷萜骰瘧?yīng)用連接到外部系統(tǒng)以及物理網(wǎng)絡(luò)的能力是非常必要的。常見的例子是部分容器化的應(yīng)用——應(yīng)用中已容器化的部分需要與那些運(yùn)行在物理網(wǎng)絡(luò)和VLAN上未容器化部分進(jìn)行通信较锡。
Docker內(nèi)置的Macvlan驅(qū)動(Windows上是Transparent)就是為此場景而生业稼。通過為容器提供MAC和IP地址,讓容器在物理網(wǎng)絡(luò)上成為“一等公民”蚂蕴。(就是和物理網(wǎng)絡(luò)同一個網(wǎng)段)
Macvlan的優(yōu)點(diǎn)是性能優(yōu)異低散,因?yàn)闊o須端口映射或者額外橋接,可以直接通過主機(jī)接口(或子接口)訪問容器接口骡楼。但是熔号,Macvlan的缺點(diǎn)是需要將主機(jī)網(wǎng)卡設(shè)置為混雜模式(Promiscuous Mode),這在大部分的公有云平臺上是不允許的鸟整。所以Macvlan對于公司內(nèi)部數(shù)據(jù)中心網(wǎng)絡(luò)來說很好跨嘉,但是在共有用上卻不可行。
macvlan的實(shí)驗(yàn)這里不做介紹了吃嘿,因?yàn)橛玫貌欢唷?/p>
11.2.5 服務(wù)發(fā)現(xiàn)
作為核心網(wǎng)絡(luò)架構(gòu)祠乃,Libnetwork還提供了一些重要的網(wǎng)絡(luò)服務(wù)。服務(wù)發(fā)現(xiàn)運(yùn)行容器和Swarm服務(wù)通過名稱相互定位兑燥。唯一的要求就是需要處于統(tǒng)一網(wǎng)絡(luò)當(dāng)中亮瓷。
其底層實(shí)現(xiàn)是利用了Docker內(nèi)置的DNS服務(wù)器,為每個容器提供DNS解析功能降瞳。這一點(diǎn)我們上面有提到過嘱支,DNS解析的過程和真實(shí)的DNS解析過程類似蚓胸,本地解析器找不到域名的話會向Docker的DNS服務(wù)發(fā)起一個遞歸查詢。
每個啟動時使用了 --name 參數(shù)的Swarm服務(wù)或者獨(dú)立容器除师,都會將自己的名稱和IP地址注冊到Docker DNS服務(wù)沛膳。這意味著容器和服務(wù)副本可以通過Docker DNS服務(wù)相互發(fā)現(xiàn)。但是汛聚,服務(wù)發(fā)現(xiàn)時受網(wǎng)絡(luò)限制的锹安。這意味著名稱解析只對同一個網(wǎng)絡(luò)中的容器和服務(wù)生效。如果兩個容器在不同的網(wǎng)絡(luò)倚舀,那么就不能相互解析了叹哭。
用戶可以為Swarm服務(wù)和獨(dú)立容器進(jìn)行自定義的DNS配置。舉個例子痕貌, --dns參數(shù)允許讀者指定自定義的DNS服務(wù)列表风罩,以防出現(xiàn)內(nèi)置的Docker DNS服務(wù)器解析失敗的情況。此外也可以使用 --dns-search 參數(shù)指定自定義查詢時所使用的域名(例如當(dāng)查詢名稱并非完整域名的時候)舵稠。
在Linux上超升,上述工作都是通過容器內(nèi)部 /et/resolve.conf 文件內(nèi)部增加條目來實(shí)現(xiàn)的。下面的例子會啟動一個新的容器哺徊,并添加聲名狼藉的 8.8.8.8 Google DNS服務(wù)器廓俭,同時指定 dockercerts.com 作為域名添加到非完整查詢當(dāng)中。
docker container run -it --name test5 --dns=8.8.8.8 \
--dns-search=dockercerts.com alpine sh
11.2.6 Ingress 網(wǎng)格
Swarm支持兩種服務(wù)發(fā)布模式唉工,兩種模式均保證服務(wù)從集群外可訪問研乒。分別是:Ingress模式(默認(rèn))和Host模式。
通過Ingress模式發(fā)布的服務(wù)淋硝,可以保證從Swarm集群內(nèi)任一節(jié)點(diǎn)(即使沒有運(yùn)行服務(wù)的副本)都能訪問該服務(wù)雹熬;以Host模式發(fā)布的服務(wù)只能通過運(yùn)行服務(wù)副本的節(jié)點(diǎn)來訪問。
Ingress模式是默認(rèn)方式谣膳,如果要使用Host模式發(fā)布服務(wù)竿报,讀者需要使用 --publish 參數(shù)的完整格式,并添加 mode=host继谚。下面來看下怎么做烈菌。
docker service create -d --name svc1 \
--publish published=5000,target=80,mode=host nginx
上面就是完整的 --publish 參數(shù)示例。
在底層花履,Ingress模式采用名為 Service Mesh 或者 Swarm Mode Service Mesh 的四層路由網(wǎng)絡(luò)來實(shí)現(xiàn)芽世。書本在這里有個示例,這里不做演示诡壁,后面在第14章中有對應(yīng)的實(shí)驗(yàn)济瓢。這里只給出書中的兩個結(jié)論。
一是使用Ingress模式的服務(wù)妹卿,訪問任意一個節(jié)點(diǎn)(即使沒有運(yùn)行對應(yīng)的容器)旺矾,Docker都能把流量轉(zhuǎn)到實(shí)際運(yùn)行容器的節(jié)點(diǎn)上蔑鹦,;二是并且如果存在多個運(yùn)行中的副本箕宙,流量會均衡到每個副本上嚎朽。
11.3 Docker網(wǎng)絡(luò)——命令
- docker network ls 用于列出運(yùn)行在本地Docker主機(jī)上的全部網(wǎng)絡(luò)
- docker network create 創(chuàng)新的Docker網(wǎng)絡(luò)。可以使用 -d 來指定網(wǎng)絡(luò)的類型,如:
docker network create -d overlay overnet
- docker network inspect 提供 Docker網(wǎng)絡(luò)的詳細(xì)配置信息稚字。
- docker network prune 刪除Docker主機(jī)上全部未使用的網(wǎng)絡(luò)
- docker network rm 刪除Docker主機(jī)上指定的網(wǎng)絡(luò)
11.4 本章小結(jié)
容器網(wǎng)絡(luò)模型(CNM)是Docker網(wǎng)絡(luò)架構(gòu)的主要設(shè)計文檔,它定義了Docker網(wǎng)絡(luò)中用到的3個主要結(jié)構(gòu)——沙盒、終端以及網(wǎng)絡(luò)融撞。
Libnetwork是開源庫盼铁,采用Go編寫,實(shí)現(xiàn)了CNM尝偎。Docker使用了該庫饶火,并且Docker網(wǎng)絡(luò)架構(gòu)的核心代碼都在該庫中。Libnetwork同時還提供了Docker網(wǎng)絡(luò)控制層和管理層的功能致扯。
驅(qū)動通過實(shí)現(xiàn)特定網(wǎng)絡(luò)類型的方式拓展了Docker網(wǎng)絡(luò)棧肤寝,例如橋接網(wǎng)絡(luò)和覆蓋網(wǎng)絡(luò)。Docker內(nèi)置了幾種網(wǎng)絡(luò)驅(qū)動抖僵,同時也支持第三方驅(qū)動鲤看。
單機(jī)橋接網(wǎng)絡(luò)是基本的Docker網(wǎng)絡(luò)類型,對于本地開發(fā)和小型應(yīng)用來說也十分適用耍群。單機(jī)橋接網(wǎng)絡(luò)不可拓展义桂,并且對外發(fā)布服務(wù)依賴于端口映射。Linux Docker使用內(nèi)置的Bridge驅(qū)動實(shí)現(xiàn)了單機(jī)橋接網(wǎng)絡(luò)蹈垢。
覆蓋網(wǎng)絡(luò)是當(dāng)下流行的方式慷吊,并且是一種出色的多機(jī)容器網(wǎng)絡(luò)方案。下一章會介紹曹抬。
Macvlan啟動允許容器接入現(xiàn)存物理網(wǎng)絡(luò)以及VLAN溉瓶。通過賦予容器MAC和IP地址的方式,讓容器稱為網(wǎng)絡(luò)中的一等公民谤民。不過堰酿,該驅(qū)動需要主機(jī)的NIC支持混雜模式,這意味著該驅(qū)動在公有云上沒法使用张足。
Docker使用Libnetwork實(shí)現(xiàn)了基礎(chǔ)服務(wù)發(fā)現(xiàn)功能胞锰,同時還實(shí)現(xiàn)了服務(wù)網(wǎng)格,支持對入站流量實(shí)現(xiàn)容器級別的負(fù)載均衡兢榨。