阿里開源富容器引擎 PouchContainer 的 network 鏈接機制

引言

PouchContainer 是阿里巴巴集團開源的高效、輕量級企業級富容器引擎技術,擁有隔離性強、可移植性高、資源佔用少等特性。能夠幫助企業快速實現存量業務容器化,同時提升超大規模下數據中心的物理資源利用率。linux

PouchContainer 源自阿里巴巴內部場景,誕生初期,在如何爲互聯網應用保駕護航方面,傾盡了阿里巴巴工程師們的設計心血。PouchContainer 的強隔離、富容器等技術特性是最好的證實。在阿里巴巴的體量規模下,PouchContainer 對業務的支撐獲得雙 11 前所未有的檢驗,開源以後,阿里容器成爲一項普惠技術,定位於「助力企業快速實現存量業務容器化」。網絡

本文將給你們介紹 PouchContainer 實現 network 的機制以及將容器鏈接到 network 上的原理。爲了充分闡述 network 的鏈接機制,本文將以Connect方法爲例,敘述如何動態地將一個 container 鏈接到一個已存在的 network 上。函數

一、 PouchContainer 實現 network 的機制

在目前的容器網絡虛擬化技術中,Docker 推行的 CNM (Container Network Model)模型是一種通用的解決方案,CNM 構建了一種成熟的容器虛擬化網絡模型,並定義了多種供開發者調用的標準化接口。PouchContainer 沿用了 CNM 模型,基於 libnetwork 來實現容器間通訊。下面先對 Sandbox、Endpoint 和 Network 這三個 CNM 中的核心組件進行介紹。ui

Sandboxspa

Sandbox 一詞在不一樣的機制裏,被分別賦予了不一樣的定義。例如,在 CRI(container runtime interface)裏面 sandbox 就表明着pod的概念。而在 CNM 模型裏,Sandbox 表明着一個容器的網絡棧配置,包含管理容器的網卡,路由表以及 DNS 設置。Sandbox 的具體實現能夠經過 linux 系統的 network namespace,一個 FreeBSD Jail 或者其餘相似的概念。一個 Sandbox 能夠包含多個 Endpoints。設計

Endpoint3d

一個 Endpoint 將 Sandbox 鏈接到 Network 上。一個 Endpoint 的實現能夠經過 veth pair,Open vSwitch internal port 或者其餘的方式。比較常見的方法是用 veth pair,顧名思義,veth pair必定是成對出現的,所以會存在 veth0 和 veth1 兩塊網卡。建立容器時,其中一塊會被設置到容器內部,充當容器內部的eth0,全部目的地址爲容器 IP 的數據包都要通過 eth0 網卡;另外一塊(如下稱爲 veth 設備)則會被鏈接到宿主機的網橋上。從 veth 設備出去的數據包,會轉發到對應的 eth0 設備上,當數據包的目的地址爲 eth0 設備的 IP 時,就能被內核協議棧處理。用 veth pair 來鏈接兩個 network namespace,從而創建網絡連通關係。一個 Endpoint 只能屬於一個 Network,也只能屬於一個 Sandbox。blog

Network接口

一個 Network 是一組能夠相互通訊的 Endpoints 的集合。一個 Network 的實現能夠經過 Linux bridge,vlan 或者其餘方式。值得一提的是,一個 Network 中能夠包含不少個 Endpoints。ip

能夠看到,在以下圖所示的結構下,Container A 和Container B 同屬於 Backend Network,這兩個 Container經過各自紫色的 Endpoint 構成 Network 鏈接;Container B和 Container C 同屬於 Frontend Network,經過藍色的 Endpoint 構成 Network 鏈接。所以Container A和Container B之間能夠通訊,Container B和Container C之間也能夠通訊。

接下來重點看一下 Container B 內部的兩個 Endpoints,雖然 Backend Network 和 Frontend Network 在Container B 內都有各自對應的 Endpoint,但紫色 Endpoint 和藍色 Endpoint 間不構成通訊。所以 Backend Network 和 Frontend Network 是兩個徹底隔離的 Network,並不由於鏈接同一個 Container 而產生連通。顯而易見,Container A 和 Container C 間實際上是沒法通訊的。

clipboard.png

二、PouchContainer 內置的 network 模式

2.1 bridge 模式

bridge 模式是 PouchContainer 默認的網絡模式,在建立容器不指定 network 模式,即不寫--net參數,該容器就會以 bridge 模式建立。pouchd啓動的時候,會自動在主機上建立一個虛擬網橋 p0。後續以 bridge 模式建立容器時,pouchd從 p0 網橋所在的 IP 網段中選取一個未使用的 IP 分配給容器的 eth0 網卡,p0 的 IP 是這些容器的默認網關。

clipboard.png

2.2 host 模式

在啓動容器的時候,選擇 host 模式,那麼容器將不會得到獨立的 network namespace,而是和主機共享 network namespace。所以,這個容器也就沒有本身的網卡和 IP 配置,會使用主機的 IP 和端口,但 fs 和 pid 等與主機仍是隔離的。

clipboard.png

2.3 container 模式

以 container 模式建立的容器,會和已經存在的容器共享一個 network namespace,直接沿用其 veth 設備對。

clipboard.png

2.4 none 模式

使用 none 模式建立的容器,擁有獨立的 network namespace,可是不會對容器進行任何的網絡配置。所以,能夠認爲 none 模式下的容器,是不和其它容器通訊的。不過,在容器建立後,能夠再給它添加網卡、配置 IP,這樣就能夠與同一個 network 下的容器通訊了。

clipboard.png

2.5 CNM 與 network 模式的概念交叉

一個 Network 是一個惟一的、可識別的 Endpoint 組,組內的 Endpoint 能夠相互通信。對比 CNM 來看,Endpoint 能夠簡單理解成 veth 設備對,容器的 Sandbox 裏能夠有多個 Endpoints,每一個 Endpoint 表明和一個特定 Network 的鏈接關係。

三、network connect 的流程分析

// daemon/mgr/container.go

clipboard.png

能夠看到在Connect函數裏,首先根據傳入的參數獲取到具體的 container 和 network。而epConfig參數裏面,存放的是在 CLI 端經過 flag 傳入的參數,如 container 在特定 network 中的別名、指定的 IP 範圍等。

查看c.State.Status來判斷 container 此時的狀態,dead 狀態的 container 是沒法執行 connect 操做的。對於非 running 可是還 live的container,只是簡單地調用updateNetworkConfig()來更新 container 的網絡配置,將傳入的epConfig加入到容器的 network 配置中。在這種狀況下,不會爲 container 分配網卡,所以 container 並無成功連通到 network 中。對於 running 狀態的 container,調用connectToNetwork()來進行後續的操做,connectToNetwork()會根據給定的 network 和 container 進行網卡的配置,再在主機上分配一個網卡,最後將網卡加入到 container 的 sandbox 裏面。這樣,container 就成功地鏈接到 network 上了!具體的流程會在後續進行解析。

c.Write(mgr.Store)的做用,是將 container 鏈接到 network 上的一系列配置寫入 container 的 metadata 裏面,這樣就保證了數據的持久化。不然,創建的 network 鏈接只是一次性的,全部的數據和相關配置在pouchd重啓後都會丟失。

// daemon/mgr/container.go

clipboard.png

endpoint 裏面包含三部分的信息,一部分的信息來自於 container,一部分的信息來自 network,最後一部分信息是 connect 命令裏 flag 中的配置。buildContainerEndpoint()的邏輯比較簡單,就是獲取到 endpoint 須要的 container 相關信息。隨後調用了NetworkMgr的EndpointCreate()來進行具體的構建。

// daemon/mgr/network.go

clipboard.png

建立 endpoint 的整個過程,都是調用 libnetwork 來實現的。首先調用endpointOptions()來構建接口要求的EndpointOption參數,這個 setter 函數類型的參數能將不一樣的 option 傳遞給 network 和 endpoint 的接口。隨後調用 libnetwork 的

CreateEndpoint()接口來進行具體的構建。CreateEndpoint()執行的實際工做包括爲這個 Endpoint 分配 IP 和接口(Iface),對應的配置會被應用到 Endpoint 中,其中包括 iptables 的配置規則和端口信息等。

sandbox 所表明的就是 container 獨有的 network namespace,其建立也是基於 libnetwork。sandbox 裏面包含 container 創建網絡通訊的標誌性信息,如 IP 地址、Mac 地址、路由和 DNS 等配置。會對已存在的 sandbox 進行遍歷,判斷是否存在相應的 sandbox,存在的話就直接返回對應的 sandbox。在 none 模式下,container 沿用主機的 namespace,返回的 sandbox 爲空,這時候會建立一個新的 sandbox。sandbox 的建立過程,就是調用 namespace 和 cgroup 來建立一個獨立 sandbox 空間。

將 endpoint 加入到 sandbox 的操做,實際上就是將網卡分配給 container 的過程,將 endpoint 分配到的網絡資源注入到 sandbox 中。網卡是創建鏈接的核心,container 經過虛擬網卡鏈接到 network,從而與其它 container 進行通訊。

最後一步,將變化同步更新到 endpoint 的配置裏面。

四、總結

回顧創建 network 鏈接的整個流程,能夠簡單的分紅幾步。container 在通訊時須要惟一的 network namespace 來標誌本身,那麼就要有 sandbox 的建立;通訊的實現須要網卡做爲基礎,那麼就要有 endpoint 的建立;最後將endpoint 加入 sandbox,創建容器間通訊的基礎,鏈接的創建就成功完成了。

本文做者:酥蕊

閱讀原文

本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索