docker 的出現是革命性的,改變了我們開發以及部署專案的方式。社群一直致力於讓容器技術標準化,這篇文章主要討論的是其中的一個方面:網路。
網路層面:虛擬機器 vs 容器技術
在開始探討不同的容器網路標準模型之前,先來從網路角度對比一下虛擬機器和 docker。
虛擬機器是一整套作業系統層級的虛擬化,它還會虛擬出虛擬網路卡(virtual network interface cards (NIC)),這些虛擬網路卡會和真正的物理機網路卡相連線。
docker 實質上就是一個程式,被 container runtime 統一管理,還會共享一個 Linux kernel。所以,容器有更靈活的網路解決方案:
- 和宿主機是共享同一個network interface和 network namespace
- 連線另外的虛擬網路,使用這個虛擬網路的network interface和 network namespace
容器網路設計
早期的容器網路設計把重點放在瞭如何連線一個宿主機上的容器,讓他們可以和外界進行互動。
在"host"模式中,執行在一個宿主機上的容器使用 host 的network namespace,和宿主機一個ip。為了暴露容器,容器會佔用宿主機上的一個埠,通過這個埠和外界通訊。所以,你需要手動維護埠的分配,不要使不同的容器服務執行在一個埠上。
"bridge"模式,在"host"模式的基礎上做了些改進。在該模式裡面,容器被分配到了一個虛擬的區域網裡,在這個network namespace 獲得分配到的 ip 地址,由於 ip 地址是獨立的,就解決了"host"模式中不同容器服務不能執行在同一埠的問題。不過還是有一個問題,如果容器想要和外界通訊的話,還是需要使用 host 的 ip 地址。這時候需要用到 NAT 將 host-ip:port 轉換成 private-ip:port。這一部分的 NAT 規則表示用Linux Iptables 維護的,這會在一定程度上影響效能(雖然不大)。
上述的兩種模式都沒有解決一個問題:多 host 網路解決方案。
CNI 和 CNM 的對比
- CNM: Docker 公司(docker container runtime 背後的公司)提出。
- CNI:CoreOS公司提出。
Kubernetes 在處理網路上,沒有選擇自己再獨立創造一個,而是選擇了其中的 CNI作為了自己的網路外掛。(至於為什麼不選擇 CNM,可以看看這篇官方的解釋:Why Kubernetes doesn’t use libnetwork)。不使用 CNM 最關鍵的一點,是 k8s 考慮到CNM 在一定程度上和 container runtime 聯絡相對比較緊密,不好解耦。 有了 k8s 這種巨無霸的選擇之後,後來的很多專案都在 CNM 和 CNI 之間選擇了 CNI。
下面是兩種網路模型的詳細對比:
- CNM
CNM 的 api 包含了兩部分:IPAM 外掛和網路外掛。IPAM 外掛負責建立/刪除 address pools、分配網路地址,network 外掛負責建立/刪除 networks、以及分配或收回容器的 ip 地址。事實上,這兩種外掛都可以實現所有的 API,你可以選擇用 IPAM,也可以選擇用 network,或者 BOTH。但是,container runtime 會在不同情況下使用到不同的外掛,這帶來了複雜性。還有就是,CNM 需要使用分散式儲存系統來儲存網路配置資訊,例如 etcd。
- CNI
CNI 對外暴露了從一個網路裡面新增和剔除容器的介面。CNI 使用一個 json 配置檔案儲存網路配置資訊。和 CNM 不一樣,CNI 不需要一個額外的分散式儲存引擎。
總結
CNI目前已經獲得了眾多開源專案的青睞,比如 K8S、Memos、Cloud Foundry。同時被Cloud Native Computing Foundation所認可。CNCF 背後有眾多的科技大亨,所以可以預見,CNI 將會成為未來容器網路的標準。