k8s-cni原理

一個 Linux 容器能看見的“網(wǎng)絡椧挪ぃ”,實際上是被隔離在它自己的 Network Namespace 當中的华蜒。而所謂“網(wǎng)絡椪尬常”,就包括了:網(wǎng)卡(Network Interface)叭喜、回環(huán)設備(Loopback Device)贺拣、路由表(Routing Table)和iptables規(guī)則。對于一個進程來說捂蕴,這些要素譬涡,其實就構(gòu)成了它發(fā)起和響應網(wǎng)絡請求的基本環(huán)境。
作為一種最簡單的使容器與目標網(wǎng)絡聯(lián)通起來的方法啥辨,就是將他以某種形式借用宿主機的網(wǎng)絡棧涡匀。

借用宿主機網(wǎng)絡棧

容器可以聲明直接使用宿主機的網(wǎng)絡棧(–net=host),即:不開啟 Network Namespace溉知,比如:

$ docker run –d –net=host --name nginx-host nginx

在這種情況下陨瘩,這個容器啟動后腕够,直接監(jiān)聽的就是宿主機的80端口。像這樣直接使用宿主機網(wǎng)絡棧的方式舌劳,雖然可以為容器提供良好的網(wǎng)絡性能帚湘,但也會不可避免地引入共享網(wǎng)絡資源的問題,比如端口沖突甚淡。所以大诸,在大多數(shù)情況下,我們都希望容器進程能使用自己Network Namespace里的網(wǎng)絡棧贯卦,即:擁有屬于自己的IP地址和端口资柔。

Veth設備

這個被隔離的容器進程,要跟其他Network Namespace里的容器進程脸侥、甚至宿主機進行交互建邓,需要一個聯(lián)通到宿主機的連線盈厘。通過創(chuàng)建Veth設備可以解決這個問題:

  • veth和其它的網(wǎng)絡設備都一樣睁枕,一端連接的是內(nèi)核協(xié)議棧
  • veth設備是成對出現(xiàn)的,另一端兩個設備彼此相連
  • 一個設備收到協(xié)議棧的數(shù)據(jù)發(fā)送請求后沸手,會將數(shù)據(jù)發(fā)送到另一個設備上去
    基于以上幾點外遇,veth設備非常適合于作為連接不同Network Namespace的連線。
    事實上契吉,我們進入容器看到的網(wǎng)卡跳仿,其實就是veth設備的一端,它的另一端在宿主機的主network namespace上捐晶。要讓容器或者pod具備獨立的網(wǎng)絡棧菲语,基本上都是從這個veth設備入手進行考慮,在宿主機上添加各種路由策略惑灵、網(wǎng)橋等山上,使容器流量去往正確的方向。

CNI是什么

CNI便是k8s用于實現(xiàn)以上任務的標準接口英支。通過編寫支持這套協(xié)議方法的插件佩憾,可以實現(xiàn)自己對k8s網(wǎng)絡的管理。包括:

  • CNI Plugin負責給容器配置網(wǎng)絡干花,它包括兩個基本的接口:
    配置網(wǎng)絡: AddNetwork(net NetworkConfig, rt RuntimeConf) (types.Result, error)
    清理網(wǎng)絡: DelNetwork(net NetworkConfig, rt RuntimeConf) error
  • IPAM Plugin負責給容器分配IP地址妄帘,主要實現(xiàn)包括host-local和dhcp。而虎牙Athena容器云所實現(xiàn)的ip不變的方案池凄,便是通過在ipam plugin中控制ip的分配策略所實現(xiàn)抡驼。
    以上兩種插件的支持,使得k8s的網(wǎng)絡可以支持各式各樣的管理模式肿仑,當前在業(yè)界也出現(xiàn)了大量的支持方案致盟,其中比較流行的比如flannel桑阶、calico等。

kubernetes配置了cni網(wǎng)絡插件后勾邦,其容器網(wǎng)絡創(chuàng)建流程為:

  • kubernetes先創(chuàng)建pause容器生成對應的network namespace
  • 調(diào)用網(wǎng)絡driver蚣录,因為配置的是CNI,所以會調(diào)用CNI相關代碼
  • CNI driver根據(jù)配置調(diào)用具體的CNI插件
  • CNI插件給pause容器配置正確的網(wǎng)絡眷篇,pod中其他的容器都是用pause的網(wǎng)絡

其中萎河,CNI Plugin是獨立的可執(zhí)行文件,被上層的容器管理平臺(kubelet)調(diào)用蕉饼。網(wǎng)絡插件只有兩件事情要做:把容器加入到網(wǎng)絡(AddNetwork)以及把容器從網(wǎng)絡中刪除(DelNetwork)虐杯。
對應于具體的CNI框架內(nèi)的實現(xiàn),即兩個基本操作ADD和DEL昧港,前者用于加入容器網(wǎng)絡擎椰,后者用于從容器網(wǎng)絡中退出。

當CNI插件被調(diào)用時创肥,首先進入main函數(shù)达舒,main函數(shù)會對環(huán)境變量和標準輸入中的配置信息進行解析,接著根據(jù)解析得到的操作方式(ADD或DEL)叹侄,轉(zhuǎn)入具體的執(zhí)行函數(shù)完成網(wǎng)絡的配置工作巩搏。如果是ADD操作,則調(diào)用cmdAdd()函數(shù)趾代,反之贯底,如果是DEL操作,則調(diào)用cmdDel()函數(shù)撒强。從宏觀角度來看禽捆,以上為CNI插件的實現(xiàn)框架主體。

編寫自己的cni插件

按照上述說法飘哨,由于cni插件是kubelet以二進制的形式調(diào)用的胚想,具體實現(xiàn)上主體為cmdAdd,cmdDel兩大函數(shù)。

package main

import (
...
)

const (
...
)

func cmdAdd(args *skel.CmdArgs) error {
    conf := types.NetConf{}
    if err := json.Unmarshal(args.StdinData, &conf); err != nil {
        log.Errorf("Error loading config from args: %v", err)
        return errors.Wrap(err, "add cmd: error loading config from args")
    }

    versionDecoder := &cniversion.ConfigDecoder{}
    confVersion, err := versionDecoder.Decode(args.StdinData)
    if err != nil {
        return err
    }

    // 在此實現(xiàn):
    // 1. 調(diào)用ipam plugin接口進行ip申請
    // 2. 容器及宿主機各自網(wǎng)絡棧內(nèi)的操作杖玲,如創(chuàng)建veth顿仇,配置ip地址,配置路由等

    ips := []*current.IPConfig{{Version: "4", Address: *ipnet}}

    result := &current.Result{
        IPs: ips,
    }

    return cnitypes.PrintResult(result, confVersion)
}

func cmdDel(args *skel.CmdArgs) error {
    conf := types.NetConf{}
    if err := json.Unmarshal(args.StdinData, &conf); err != nil {
        log.Errorf("Error loading config from args: %v", err)
        return errors.Wrap(err, "add cmd: error loading config from args")
    }

    versionDecoder := &cniversion.ConfigDecoder{}
    confVersion, err := versionDecoder.Decode(args.StdinData)
    if err != nil {
        return err
    }

    // 在此實現(xiàn):
    // 1. 調(diào)用ipam plugin接口進行ip釋放
    // 2. 容器及宿主機各自網(wǎng)絡棧內(nèi)的操作摆马,如刪除veth臼闻,刪除路由等

    return nil
}

func main() {
    log.SetLevel(log.DebugLevel)
    ConfigLocalFilesystemLogger(logPath, 24*60*time.Hour, 24*time.Hour)
    exitCode := 0

    if e := skel.PluginMainWithError(cmdAdd, nil, cmdDel, cniversion.All, "<版本說明等信息>"); e != nil {
        exitCode = 1
        log.Error("Failed CNI request: ", e)
        if err := e.Print(); err != nil {
            log.Error("Error writing error JSON to stdout: ", err)
        }
    }

    os.Exit(exitCode)
}

至于其中ipam接口如何調(diào)用,則不一定按照官方的ipam plugin規(guī)范編寫囤采,甚至可將ipam相關邏輯結(jié)合到cni plugin中述呐。也可以獨立服務,并通過API蕉毯、RPC等方式調(diào)用乓搬。

坑在哪

本文介紹了容器網(wǎng)絡CNI插件的原理思犁,簡化后的代碼接口清晰簡潔,主體流程圍繞在:解析參數(shù)进肯、執(zhí)行add/del激蹲、返回結(jié)果上,按照CNI規(guī)范的結(jié)構(gòu)編寫配置江掩、入?yún)⒀琛⒎祷刂担蓪崿F(xiàn)簡單CNI邏輯环形。
但CNI特點在于具體的網(wǎng)絡配置策泣、網(wǎng)絡連通方案、ip分配方案可由插件自定義抬吟,k8s僅負責調(diào)用萨咕。因此CNI的出現(xiàn),使k8s網(wǎng)絡架構(gòu)更為靈活多變火本,也引入了更加復雜的因素:

  • 因為k8s與容器網(wǎng)絡的相對分離危队,容易形成容器的聲明周期與其網(wǎng)絡資源的生命周期相脫節(jié)
    kubelet通過pleg進行的pod聲明周期管理,使pod可控发侵,但容器網(wǎng)絡不可控交掏。CNI的編寫上妆偏,需要支持上層(kubelet)調(diào)用的多次重入及冪等刃鳄,且pod與cni無強依賴,容易導致容器網(wǎng)絡遺漏钱骂、殘留等問題發(fā)生叔锐。
    因此,在cni插件編寫上见秽,需進行更多的一致性校驗及補漏愉烙、清理工作。
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末解取,一起剝皮案震驚了整個濱河市步责,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌禀苦,老刑警劉巖蔓肯,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異振乏,居然都是意外死亡蔗包,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門慧邮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來调限,“玉大人舟陆,你說我怎么就攤上這事〕馨” “怎么了秦躯?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長裆装。 經(jīng)常有香客問我宦赠,道長,這世上最難降的妖魔是什么米母? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任勾扭,我火速辦了婚禮,結(jié)果婚禮上铁瞒,老公的妹妹穿的比我還像新娘妙色。我一直安慰自己,他們只是感情好慧耍,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布身辨。 她就那樣靜靜地躺著,像睡著了一般芍碧。 火紅的嫁衣襯著肌膚如雪煌珊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天泌豆,我揣著相機與錄音定庵,去河邊找鬼。 笑死踪危,一個胖子當著我的面吹牛蔬浙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贞远,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼畴博,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蓝仲?” 一聲冷哼從身側(cè)響起俱病,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎袱结,沒想到半個月后亮隙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡擎勘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年咱揍,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片棚饵。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡煤裙,死狀恐怖掩完,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情硼砰,我是刑警寧澤且蓬,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站题翰,受9級特大地震影響恶阴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜豹障,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一冯事、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧血公,春花似錦昵仅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至垦写,卻和暖如春吕世,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背梯投。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工命辖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人晚伙。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓吮龄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親咆疗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容