網(wǎng)絡(luò)已經(jīng)無處不在。每當(dāng)基礎(chǔ)設(shè)施出現(xiàn)問題時(shí),被抱怨的通常是網(wǎng)絡(luò),很大一部分原因是,網(wǎng)絡(luò)負(fù)責(zé)連接一切——無網(wǎng)絡(luò),無 APP!
在 Docker 早期階段,網(wǎng)絡(luò)設(shè)計(jì)確實(shí)非常復(fù)雜,那時(shí)候配置網(wǎng)絡(luò)幾乎是一種樂趣。
Docker 在容器內(nèi)部運(yùn)行應(yīng)用,這些應(yīng)用之間的交互依賴于大量不同的網(wǎng)絡(luò),這意味著 Docker 需要強(qiáng)大的網(wǎng)絡(luò)功能。幸運(yùn)的是,Docker 對(duì)于容器之間、容器與外部網(wǎng)絡(luò)和 VLAN 之間的連接均有相應(yīng)的解決方案。
后者對(duì)于那些需要跟外部系統(tǒng)(如虛擬機(jī)和物理機(jī))的服務(wù)打交道的容器化應(yīng)用來說至關(guān)重要。
Docker 網(wǎng)絡(luò)架構(gòu)源自一種叫作容器網(wǎng)絡(luò)模型(CNM)的方案,該方案是開源的并且支持插接式連接。
Libnetwork 是 Docker 對(duì) CNM 的一種實(shí)現(xiàn),提供了 Docker 核心網(wǎng)絡(luò)架構(gòu)的全部功能。不同的驅(qū)動(dòng)可以通過插拔的方式接入 Libnetwork 來提供定制化的網(wǎng)絡(luò)拓?fù)洹?/p>
為了實(shí)現(xiàn)開箱即用的效果,Docker 封裝了一系列本地驅(qū)動(dòng),覆蓋了大部分常見的網(wǎng)絡(luò)需求。其中包括單機(jī)橋接網(wǎng)絡(luò)(Single-Host Bridge Network)、多機(jī)覆蓋網(wǎng)絡(luò)(Multi-Host Overlay),并且支持接入現(xiàn)有 VLAN。
Docker 生態(tài)系統(tǒng)中的合作伙伴通過提供驅(qū)動(dòng)的方式,進(jìn)一步拓展了 Docker 的網(wǎng)絡(luò)功能。Libnetwork 提供了本地服務(wù)發(fā)現(xiàn)和基礎(chǔ)的容器負(fù)載均衡解決方案。
在頂層設(shè)計(jì)中,Docker 網(wǎng)絡(luò)架構(gòu)由 3 個(gè)主要部分構(gòu)成:CNM、Libnetwork 和驅(qū)動(dòng)。
? CNM 是設(shè)計(jì)標(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ū)動(dòng)通過實(shí)現(xiàn)特定網(wǎng)絡(luò)拓?fù)涞姆绞絹硗卣乖撃P偷哪芰Α?/p>
下圖展示了頂層設(shè)計(jì)中的每個(gè)部分是如何組裝在一起的。
一切都始于設(shè)計(jì)!
Docker 網(wǎng)絡(luò)架構(gòu)的設(shè)計(jì)規(guī)范是 CNM。CNM 中規(guī)定了 Docker 網(wǎng)絡(luò)的基礎(chǔ)組成要素,完整內(nèi)容見 GitHub 的 docker/libnetwork 庫。
抽象來講,CNM 定義了 3 個(gè)基本要素:沙盒(Sandbox)、終端(Endpoint)和網(wǎng)絡(luò)(Network)。
? 沙盒是一個(gè)獨(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ú)立。
下圖展示了 3 個(gè)組件是如何連接的。
Docker 環(huán)境中最小的調(diào)度單位就是容器,而 CNM 也恰如其名,負(fù)責(zé)為容器提供網(wǎng)絡(luò)功能。
下圖展示了 CNM 組件是如何與容器進(jìn)行關(guān)聯(lián)的——沙盒被放置在容器內(nèi)部,為容器提供網(wǎng)絡(luò)連接。
容器 A 只有一個(gè)接口(終端)并連接到了網(wǎng)絡(luò) A。容器 B 有兩個(gè)接口(終端)并且分別接入了網(wǎng)絡(luò) A 和網(wǎng)絡(luò) B。容器 A 與 B 之間是可以相互通信的,因?yàn)槎冀尤肓司W(wǎng)絡(luò) A。但是,如果沒有三層路由器的支持,容器 B 的兩個(gè)終端之間是不能進(jìn)行通信的。
需要重點(diǎn)理解的是,終端與常見的網(wǎng)絡(luò)適配器類似,這意味著終端只能接入某一個(gè)網(wǎng)絡(luò)。因此,如果容器需要接入到多個(gè)網(wǎng)絡(luò),就需要多個(gè)終端。
下圖對(duì)前面的內(nèi)容進(jìn)行拓展,加上了 Docker 主機(jī)。雖然容器 A 和容器 B 運(yùn)行在同一個(gè)主機(jī)上,但其網(wǎng)絡(luò)堆棧在操作系統(tǒng)層面是互相獨(dú)立的,這一點(diǎn)由沙盒機(jī)制保證。
CNM 是設(shè)計(jì)規(guī)范文檔,Libnetwork 是標(biāo)準(zhǔn)的實(shí)現(xiàn)。Libnetwork 是開源的,采用 Go 語言編寫,它跨平臺(tái)(Linux 以及 Windows),并且被 Docker 所使用。
在 Docker 早期階段,網(wǎng)絡(luò)部分代碼都存在于 daemon 當(dāng)中。daemon 變得臃腫,并且不符合 UNIX 工具模塊化設(shè)計(jì)原則,即既能獨(dú)立工作,又易于集成到其他項(xiàng)目。
所以,Docker 將該網(wǎng)絡(luò)部分從 daemon 中拆分,并重構(gòu)為一個(gè)叫作 Libnetwork 的外部類庫。
現(xiàn)在,Docker 核心網(wǎng)絡(luò)架構(gòu)代碼都在 Libnetwork 當(dāng)中。Libnetwork 實(shí)現(xiàn)了 CNM 中定義的全部 3 個(gè)組件。此外它還實(shí)現(xiàn)了本地服務(wù)發(fā)現(xiàn)(Service Discovery)、基于 Ingress 的容器負(fù)載均衡,以及網(wǎng)絡(luò)控制層和管理層功能。
如果說 Libnetwork 實(shí)現(xiàn)了控制層和管理層功能,那么驅(qū)動(dòng)就負(fù)責(zé)實(shí)現(xiàn)數(shù)據(jù)層。比如,網(wǎng)絡(luò)連通性和隔離性是由驅(qū)動(dòng)來處理的,驅(qū)動(dòng)層實(shí)際創(chuàng)建網(wǎng)絡(luò)對(duì)象也是如此,其關(guān)系如下圖所示。
Docker 封裝了若干內(nèi)置驅(qū)動(dòng),通常被稱作原生驅(qū)動(dòng)或者本地驅(qū)動(dòng)。
在 Linux 上包括 Bridge、Overlay 以及 Macvlan,在 Windows 上包括 NAT、Overlay、Transport 以及 L2 Bridge。
第三方也可以編寫 Docker 網(wǎng)絡(luò)驅(qū)動(dòng)。這些驅(qū)動(dòng)叫作遠(yuǎn)程驅(qū)動(dòng),例如 Calico、Contiv、Kuryr 以及 Weave。
每個(gè)驅(qū)動(dòng)都負(fù)責(zé)其上所有網(wǎng)絡(luò)資源的創(chuàng)建和管理。舉例說明,一個(gè)叫作“prod-fe-cuda”的覆蓋網(wǎng)絡(luò)由 Overlay 驅(qū)動(dòng)所有并管理。這意味著 Overlay 驅(qū)動(dòng)會(huì)在創(chuàng)建、管理和刪除其上網(wǎng)絡(luò)資源的時(shí)候被調(diào)用。
為了滿足復(fù)雜且不固定的環(huán)境需求,Libnetwork 支持同時(shí)激活多個(gè)網(wǎng)絡(luò)驅(qū)動(dòng)。這意味著 Docker 環(huán)境可以支持一個(gè)龐大的異構(gòu)網(wǎng)絡(luò)。