不論是 docker 仍是 kubernetes,在網絡方面目前都沒有一個完美的、終極的、普適性的解決方案,不一樣的用戶和企業由於各類緣由會使用不一樣的網絡方案。目前存在網絡方案 flannel、calico、openvswitch、weave、ipvlan等,並且之後必定會有其餘的網絡方案,這些方案接口和使用方法都不相同,而不一樣的容器平臺都須要網絡功能,它們之間的適配若是沒有統一的標準,會有很大的工做量和重複勞動。html
CNI 就是這樣一個標準,它旨在爲容器平臺提供網絡的標準化。不一樣的容器平臺(好比目前的 kubernetes、mesos 和 rkt)可以經過相同的接口調用不一樣的網絡組件。linux
CNI(Conteinre Network Interface) 是 google 和 CoreOS 主導制定的容器網絡標準,它 自己並非實現或者代碼,能夠理解成一個協議。這個標準是在 rkt 網絡提議 的基礎上發展起來的,綜合考慮了靈活性、擴展性、ip 分配、多網卡等因素。git
這個協議鏈接了兩個組件:容器管理系統和網絡插件。它們之間經過 JSON 格式的文件進行通訊,實現容器的網絡功能。具體的事情都是插件來實現的,包括:建立容器網絡空間(network namespace)、把網絡接口(interface)放到對應的網絡空間、給網絡接口分配 IP 等等。github
關於網絡,docker 也提出了 CNM 標準,它要解決的問題和 CNI 是重合的,也就是說目前二者是競爭關係。目前 CNM 只能使用在 docker 中,而 CNI 可使用在任何容器運行時。CNM 主要用來實現 docker 自身的網絡問題,也就是 docker network
子命令提供的功能。docker
全部的標準和協議都要有具體的實現,纔可以被你們使用。CNI 也不例外,目前官方在 github 上維護了同名的 CNI 代碼庫,裏面已經有不少能夠直接拿來使用的 CNI 插件。服務器
官方提供的插件目前分紅三類:main、meta 和 ipam。main 是主要的實現了某種特定網絡功能的插件;meta 自己並不會提供具體的網絡功能,它會調用其餘插件,或者單純是爲了測試;ipam 是分配 IP 地址的插件。網絡
ipam 並不提供某種網絡功能,只是爲了靈活性把它單獨抽象出來,這樣不一樣的網絡插件能夠根據需求選擇 ipam,或者實現本身的 ipam。dom
這些插件的功能說明以下:oop
lo
網卡,並配置上 127.0.0.1/8
地址網絡插件是獨立的可執行文件,被上層的容器管理平臺調用。網絡插件只有兩件事情要作:把容器加入到網絡以及把容器從網絡中刪除。調用插件的數據經過兩種方式傳遞:環境變量和標準輸入。通常插件須要三種類型的數據:容器相關的信息,好比 ns 的文件、容器 id 等;網絡配置的信息,包括網段、網關、DNS 以及插件額外的信息等;還有就是 CNI 自己的信息,好比 CNI 插件的位置、添加網絡仍是刪除網絡。測試
咱們來看一下爲容器添加網絡是怎麼工做的,刪除網絡和它過程同樣。
把容器加入到網絡
調用插件的時候,這些參數會經過環境變量進行傳遞:
CNI_COMMAND
:要執行的操做,能夠是 ADD
(把容器加入到某個網絡)、DEL
(把容器從某個網絡中刪除)CNI_CONTAINERID
:容器的 ID,好比 ipam 會把容器 ID 和分配的 IP 地址保存下來。可選的參數,可是推薦傳遞過去。須要保證在管理平臺上是惟一的,若是容器被刪除後能夠循環使用CNI_NETNS
:容器的 network namespace 文件,訪問這個文件能夠在容器的網絡 namespace 中操做CNI_IFNAME
:要配置的 interface 名字,好比 eth0
CNI_ARGS
:額外的參數,是由分號;
分割的鍵值對,好比 「FOO=BAR;hello=world」CNI_PATH
:CNI 二進制查找的路徑列表,多個路徑用分隔符 :
分隔網絡信息主要經過標準輸入,做爲 JSON 字符串傳遞給插件,必須的參數包括:
cniVersion
:CNI 標準的版本號。由於 CNI 在演化過程當中,不一樣的版本有不一樣的要求name
:網絡的名字,在集羣中應該保持惟一type
:網絡插件的類型,也就是 CNI 可執行文件的名稱args
:額外的信息,類型爲字典ipMasq
:是否在主機上爲該網絡配置 IP masqueradeipam
:IP 分配相關的信息,類型爲字典dns
:DNS 相關的信息,類型爲字典插件接到這些數據,從輸入和環境變量解析到須要的信息,根據這些信息執行程序邏輯,而後把結果返回給調用者,返回的結果中通常包括這些參數:
CNI 協議的內容還在不斷更新,請到官方文檔獲取當前的信息。
CNI 做爲一個協議/標準,它有很強的擴展性和靈活性。若是用戶對某個插件有額外的需求,能夠經過輸入中的 args
和環境變量 CNI_ARGS
傳輸,而後在插件中實現自定義的功能,這大大增長了它的擴展性;CNI 插件把 main 和 ipam 分開,用戶能夠自由組合它們,並且一個 CNI 插件也能夠直接調用另一個 CNI 插件,使用起來很是靈活。
若是要實現一個繼承性的 CNI 插件也不復雜,能夠編寫本身的 CNI 插件,根據傳入的配置調用 main 中已經有的插件,就能讓用戶自由選擇容器的網絡。
CNI 目前已經在 kubernetes 中開始使用,也是目前官方推薦的網絡方案,具體的配置方法能夠參考kubernetes 官方文檔。
kubernetes 使用了 CNI 網絡插件以後,工做過程是這樣的:
http://cizixs.com/2017/05/23/container-network-cni