為什么Kubernetes不用libnetwork

jopen 8年前發布 | 13K 次閱讀 Kubernetes

【編者的話】libnetwork是2015年5月1日Docker發布的自家的容器網絡管理項目。libnetwork使用Go語言編寫,目標是定義一個容器網絡模型(CNM),并為應用程序提供一致的編程接口以及網絡抽象。為什么后來發布的Kubernetes在網絡管理方面,沒有使用Docker中得libnetwork呢?且聽google工程師的一些看法。

Kubernetes 1.0版本之前就已經具有基本的網絡插件體系。與此同時,Docker也將 libnetworkCNM (容器網絡模型)引入系統中使用。與之不同的是,Kubernetes網絡插件系統卻還停留在Alpha階段。既然Docker的網絡插件libnetwork已經發布并支持,那問題來了,為什么Kubernetes沒有使用libnetwork呢?畢竟大部分的供應商肯定會支持Docker的網絡插件,為什么不選擇使用相同的組件呢?

深入討論之前,首先我們要知道:Kubernetes是一個支持多容器的運行環境,而Docker只是其中一個容器而已。每一個運行環境都會去配置網絡環境,所以當人們問“Kubernetes將會支持CNM嗎?”時,他們真正的意思是“Kubernetes是否在Docker運行時下支持CNM?”。如果我們能使用用相同的網絡組件支持多運行時的話,這當然很好。但是,這并不是明確的目標。

Kubernetes確實沒有在Docker中采用CNM/libnetwork。事實上,我們一直在研究能不能用CoreOS提出的APP Container( appc )標準中得容器網絡接口(Container Network Interface, CNI )替代它。為什么呢?這里有一些技術和非技術上的原因。

首先,在Docker的網絡驅動設計中,預先做了一些兼容的基本假設,這給我們帶來不少的問題。

在Docker中有一個“本地”驅動和“全局”驅動的概念。本地驅動是以一臺機器為中心(例如“bridge”),不能實現跨機器節點的協作。全局驅動依賴 libkv (一個抽象的鍵值對存數對象)可以實現跨機器節點的協作(例如:overlay)。libkv是一個非常底層(語義層面的)的鍵值對存儲接口。為了能讓Docker中類似overlay的全局驅動在Kubernetes集群運行,我們還需要集群系統管理員運行 consuletcd 或者 zookeeper 實例(參考 multi-host networking ,或者我們不得不在Kubernetes中提供我們自己對于libkv的實現。

聽起來后者更有吸引力一些,而且我們也正在嘗試實現它。但是,libkv的接口太過于底層,而且它的架構模式也是Docker內部的量身定制版,我們要么直接暴露底層的key-value存儲,要么提供key-value語義接口(在一個key-value系統上實現結構存儲的API)。就起性能、可擴展性和安全性而言,以上兩種方案都不是太合適。我們使用Docker網絡的目標是簡化操作,如果那樣做的話,很明顯會使整個系統將變得更加復雜。

對于那些想運行 Docker 的全局驅動并能有能力配置 Docker 的用戶來說,Docker 的網絡應該是“可行的”。對 Kubernetes 來說,我們不希望介入或影響 Docker 的配置步驟,并且不論 Kubernetes 這個項目今后如何發展,這一點應該都不會改變。Docker 的全局驅動是對用戶和開發者來說增加了多余的負擔,并且我們不會用它作為默認的網絡選項,這也意味著使用 Docker 插件再沒什么價值。

Docker 的網絡模型在設計上還做了很多和 Kubernetes 不兼容的假設。在 Docker 1.8 和 1.9 的版本中,它在實現“Discovery”時有一個根本性的設計缺陷,結果導致了容器中的 /etc/hosts 文件被隨意改寫甚至破壞( docker #17190 ) ,而且我們還不能輕易關閉“服務發現”這個功能。Docker在 1.10 的版本中,還計劃增加 捆綁一個新 DNS 服務器 的功能 ,而我們現在還不不清楚這個功能能否被關閉。對 Kubernetes 來說,把命名尋址綁定在容器層面,并不是一個正確的設計—我們已經自己定義了一套 Service 命名、尋址、綁定的概念和規則,并且我們也有了我們自己的 DNS 架構和服務(構建在很成熟的 SkyDNS 上)。所以,捆綁一個 DNS 服務器這樣的方案并不能滿足我們的需求,而且它還有可能無法被關閉。

除了“本地/全局”驅動這樣的區分,Docker 還定義了“進程內”和“進程外”(“遠程”)插件。我們還研究了下是否可以繞過 libnework 本身(這樣就能避開之前所述的那些問題)來直接使用”遠程“插件。不幸的是,這意味著我們同時也失去了使用 Docker 的那些“進程內”插件的可能,特別是”bridge”和”overlay”這樣的全局插件。這又令使用 libnetwork 失去了很大一部分意義。

另一方面來說,CNI 和 Kubernetes 在設計哲學上非常一致。它遠比 CNM 簡單,不需要守護進程,并且至少是跨平臺的(CoreOS 的 rkt 容器支持 CNI)。跨平臺意味著同一個網絡配置可以在多個運行環境下使用(例如 Docker, rkt 和 Hyper)。這也非常符合 Unix 的設計哲學:做好一件事。

另外,包裝 CNI 模塊來實現一個自定義的模塊是非常簡單的-通過一個簡單的 shell 腳本就可以完成。相反 CNM 就復雜多了。因此我們認為 CNI 更適合快速開發和迭代。早期的實驗嘗試證明我們可以利用 CNI 插件來替代幾乎所有 kubelet 中硬編碼的網絡邏輯。

我們也嘗試為 Docker 實現了一個 “bridge”CNM 驅動來使用 CNI 的驅動。結果表明這更加復雜了問題。首先 CNM 和 CNI 的模型非常不同,沒有一個“methods”能把它們很好的兼容。其次,我們還是有之前提到的“全局”和“本地”以及 key-value 的問題存在。假設這是個本地驅動,那么我們仍舊要從 Kubernetes 中去得到相應的邏輯網絡的信息。

不幸的是,Docker驅動很難映射接入到類似Kubernetes這樣的管理平臺。特別是這些驅動使用了 Docker 內部分配的一個 ID 而不是一個通用的網絡名字來指向一個容器所屬的網絡。這樣的設計導致一個被定義在外部系統中(例如 Kubernetes )的網絡很難被驅動所理解識別。

我們和其它網絡提供商將這些問題和其它一些相關問題都匯報給了 Docker 的開發人員。盡管這些問題給非 Docker 的第三方系統帶來了很多困擾,它們通常被以“設計就是如此”的理由所關閉( libnetwork #139 , libnetwork #486 , libnetwork #514 , libnetwork #865 , docker #18864 )。通過這些舉動,我們觀察到 Docker 清楚的表明了他們對于有些建議的態度不夠開放,因為這些建議可能會分散其一些主要精力、或者降低其對項目的控制。這一點讓我們很擔憂,因為 Kubernetes 一直支持 Docker,并且為其增加了如此多的功能,但同時 Kubernetes 也是一個獨立于 Docker 之外的項目。

種種原因致使我們選擇了 CNI 作為 Kubernetes 的網絡模型。這將會帶來一些令人遺憾的副作用,雖然絕大部分都是一些小問題,比如 Docker 的 inspect 命令顯示不了網絡地址。不過也會有一些顯著的問題,特別是被 Docker 所啟動的容器可能不能和被 Kubernetes 啟動的容器溝通,以及網絡整合工程師必須提供 CNI 驅動來把網絡完全整合到 Kubernetes 中。但重要的是,Kubernetes 會變得更簡單、靈活并且不需要進行提前配置(比如配置 Docker 使用我們的網橋)。

隨著我們越走越遠,我們會毋庸置疑地汲取更多更好的整合、簡化的方法。如果您對此有啥想法,我們洗耳恭聽——可以通過 slack ( http://slack.k8s.io /) 和 network SIG 郵件列表聯系我們。

原文鏈接: why-Kubernetes-doesnt-use-libnetwork (整理:ylzhang )

參考鏈接: http://www.infoq.com/cn/articl ... twork

來自: http://dockone.io/article/973

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!