假如重新設(shè)計(jì)Kubernetes
最近,我和領(lǐng)域內(nèi)的專(zhuān)家Vallery Lancey有過(guò)一次閑聊,主題是關(guān)于Kubernetes的。具體說(shuō)來(lái),假設(shè)我們從零開(kāi)始設(shè)計(jì)一個(gè)新的編排系統(tǒng),不必拘泥于與現(xiàn)有Kubernetes的兼容性,我們可能會(huì)采取哪些不同的做法。我發(fā)現(xiàn)對(duì)話(huà)過(guò)程非常有意義,以至于我覺(jué)得有必要記錄下期間涌現(xiàn)的諸多想法,所以就有了這篇文章。
落筆前,我想強(qiáng)調(diào)幾點(diǎn):
- 這不是一個(gè)完全成形的設(shè)計(jì)。其中某些想法可能根本無(wú)法落地,或者需要進(jìn)行大量的重構(gòu)。很多章節(jié)的內(nèi)容都是想到哪寫(xiě)到哪。
 - 這些觀(guān)點(diǎn)不單純是我一個(gè)人的想法。有些是我原創(chuàng)的,更多的是集體思考,交流碰撞后的產(chǎn)物,就像Kubernetes社區(qū)中的許多設(shè)計(jì)一樣。我知道至少Vallery和Maisem Ali不止一次地啟發(fā)了我的思考,還有更多我說(shuō)不出名字的。如果你覺(jué)得文中有些想法很不錯(cuò),那請(qǐng)把它當(dāng)成是集體努力的結(jié)果。如果你不太認(rèn)同其中一些看法,那把它當(dāng)成是我個(gè)人的小小失誤吧。
 - 文中的一些觀(guān)點(diǎn)是非常極端激進(jìn)的。我只是嘗試把腦海的一些設(shè)計(jì)表達(dá)出來(lái),一吐為快。
 
設(shè)計(jì)原則
我過(guò)往的Kubernetes實(shí)踐經(jīng)驗(yàn)來(lái)自?xún)蓚€(gè)截然不同的地方:一個(gè)是為裸金屬機(jī)集群維護(hù)MetalLB;另一個(gè)是在GKE SRE中運(yùn)維大型的集群即服務(wù)(clusters-as-a-service)。這兩個(gè)經(jīng)歷都讓我覺(jué)得,Kubernetes相當(dāng)復(fù)雜,要達(dá)到目前市面上宣傳的效果,往往需要做大量的前置工作,而大多數(shù)躍躍欲試的用戶(hù)對(duì)此都沒(méi)有充分的準(zhǔn)備。
維護(hù)MetalLB的經(jīng)歷告訴我,想構(gòu)建與Kubernetes集成的健壯性?xún)?yōu)異的軟件十分困難。我認(rèn)為MetalLB穩(wěn)定性堪稱(chēng)優(yōu)秀,但是Kubernetes還是非常容易使它出現(xiàn)配置錯(cuò)誤的情況,而調(diào)試起來(lái)也相當(dāng)費(fèi)勁。 GKE SRE的運(yùn)維經(jīng)歷則教會(huì)我,即使是最出色的Kubernetes專(zhuān)家也無(wú)法不出差錯(cuò)地運(yùn)維大規(guī)模Kubernetes集群(盡管GKE SRE借助一些工具能做得非常出色)。
Kubernetes可以類(lèi)比成編排軟件中的C ++。功能強(qiáng)大,特性完備,看上去似乎挺簡(jiǎn)單,但你會(huì)不停踩坑,直到你投入大量時(shí)間和精力,去弄清它的所有原理為止。即便如此,Kubernetes的配置和部署方式方法眾多,生態(tài)還在不停發(fā)展,以至于很難讓人覺(jué)得可以停下腳步歇口氣了。
按照這個(gè)類(lèi)比,我理想的參照物是Go。如果Kubernetes是C ++,那么編排系統(tǒng)中Go會(huì)是什么樣的呢?極度簡(jiǎn)潔,特點(diǎn)突出,緩慢而謹(jǐn)慎地拓展新特性,你可以在不到一周的時(shí)間里上手,然后就能用它去完成你的工作。
接下來(lái),我們就遵循上面這些原則開(kāi)始了。重新設(shè)計(jì)一個(gè)Kubernetes,可以不考慮和現(xiàn)有的兼容,另辟蹊徑,該考慮哪些點(diǎn)呢?
可修改的Pod
在Kubernetes中,大部分(但不是全部)Pod在創(chuàng)建后是不可變的。如果你想直接修改一個(gè)Pod,不行。得重新創(chuàng)建一個(gè)再刪掉舊的。這與Kubernetes中的大多數(shù)資源對(duì)象的處理方式不同,在Kubernetes中的大多數(shù)對(duì)象都是可變的,并且當(dāng)預(yù)期狀態(tài)出現(xiàn)變化時(shí),可以?xún)?yōu)雅地將實(shí)際狀態(tài)協(xié)調(diào)到與預(yù)期一致。
因此,我不想讓Pod成為一個(gè)例外。我打算將它設(shè)計(jì)成完全可讀寫(xiě),并讓它擁有像其它資源對(duì)象一樣的調(diào)諧邏輯。
對(duì)此我第一時(shí)間想到的方案是原地重啟。如果Pod的調(diào)度約束和需求資源前后沒(méi)有改變,猜一下如何實(shí)現(xiàn)? 發(fā)出SIGTERM信號(hào)終止runc,使用不同的參數(shù)重新啟動(dòng)runc,就已完成重啟。這樣一來(lái),Pod有點(diǎn)像從前的systemd服務(wù),必要時(shí)還可以在不同機(jī)器之間漂移。
請(qǐng)注意,這不需要在運(yùn)行時(shí)層面操作可變性。如果用戶(hù)更改了Pod定義,仍然可以先終止容器并使用新配置重新啟動(dòng)容器。 Pod仍會(huì)保留在原節(jié)點(diǎn)上預(yù)留的資源,因此從概念上講,它等效于systemctl restart blah.service。你也可以嘗試在并在運(yùn)行時(shí)層級(jí)上來(lái)執(zhí)行Pod的更新操作,但其實(shí)沒(méi)有必要這樣做。不這么做的主要好處是將調(diào)度、Pod生命周期及運(yùn)行時(shí)生命周期管理解耦。
版本管理
來(lái)繼續(xù)討論P(yáng)od的設(shè)計(jì):既然它現(xiàn)在是可變的了,那么我接下來(lái)考慮的事情自然而然就是Pod回滾。為此,讓我們保留Pod舊版本的定義,如此一來(lái)“回滾到特定舊版本”就輕而易舉了。
現(xiàn)在,Pod更新流程如下:編寫(xiě)文件更新Pod定義,并進(jìn)行更新以符合預(yù)期定義。更新出錯(cuò)?回滾上一個(gè)版本,流程結(jié)束。
上述流程的好處是:無(wú)需依賴(lài)所謂的GitOps,即可輕松了解到集群中應(yīng)用的版本迭代。如無(wú)必要就不用引入GitOps,盡管它有不少優(yōu)點(diǎn)。如果,你只希望解決一個(gè)很基本的“集群發(fā)生了什么變化?”的問(wèn)題,僅僅使用集群中的數(shù)據(jù)就夠了。
其中還涉及到更多設(shè)計(jì)細(xì)節(jié)。尤其是我想將外部更改(用戶(hù)提交Pod的變更)與系統(tǒng)變更(Kubernetes內(nèi)部觸發(fā)的Pod定義變更)這兩者區(qū)分開(kāi)。我還沒(méi)有考慮清楚如何對(duì)這兩種變更的歷史信息進(jìn)行編碼,并使得運(yùn)維人員和其他系統(tǒng)組件都可以獲取到這些變更。也許可以設(shè)計(jì)成完全通用的,“修改人”在提交新版本時(shí)會(huì)標(biāo)識(shí)自己。然后用戶(hù)可以指定特定修改人(或排除特定修改人)以查詢(xún)某類(lèi)變更(類(lèi)似于標(biāo)簽查詢(xún)的工作原理)。同樣的,這里還需要更多的設(shè)計(jì)考量,我確定的是我想要一個(gè)具有版本管理特性的Pod對(duì)象,可以查詢(xún)它的歷史版本記錄。
最后,還需要考慮垃圾回收。具體說(shuō)就是,對(duì)每個(gè)Pod的更改應(yīng)該可以很好地進(jìn)行增量壓縮。默認(rèn)設(shè)置是保留所有變更內(nèi)容,積累到一定數(shù)據(jù)量后,在此基礎(chǔ)上進(jìn)行一次壓縮。保留所有變更內(nèi)容也會(huì)對(duì)系統(tǒng)產(chǎn)生一定壓力,但可避免“因頻繁提交更改”而給系統(tǒng)的其它部分帶來(lái)影響。這里用戶(hù)要注意,為方便聚合,應(yīng)該進(jìn)行次數(shù)更少同時(shí)更有意義的變更,而不是每次改動(dòng)一個(gè)字段進(jìn)而產(chǎn)生一系列版本。
一旦有了歷史版本這個(gè)功能后,我們還可以整一些其它的小功能。例如,節(jié)點(diǎn)可以將最近的若干個(gè)版本的容器鏡像保留在節(jié)點(diǎn)上,從而使回滾更快。原來(lái)的垃圾回收超過(guò)一定期限就觸發(fā),有了歷史版本記錄,可以更精確地保留需要的版本數(shù)。概括而言,所有編排軟件都將舊版本用作各種資源對(duì)象的GC roots,以加快回滾速度?;貪L是避免服務(wù)中斷的基本方式,這是非常有價(jià)值的事情。
用PinnedDeployment替換Deployment
這是部分內(nèi)容比較簡(jiǎn)短,主要是受Vallery啟發(fā)。他的PinnedDeployment設(shè)計(jì)非常讓人驚嘆。PinnedDeployment使運(yùn)維人員可以通過(guò)跟蹤兩個(gè)版本的Deployment狀態(tài)來(lái)控制應(yīng)用發(fā)布。這是由SRE設(shè)計(jì)的部署對(duì)象。設(shè)計(jì)人員非常清楚SRE在部署中的關(guān)注的焦點(diǎn)。我個(gè)人很喜歡這個(gè)設(shè)計(jì)。
這可以和上面的可版本管理、可原地更新的Pod結(jié)合得非常好,真想不到還有什么可以添加的了。它非常清晰的解釋了多個(gè)Pod時(shí)的工作流程。要從Kubernetes各項(xiàng)約束中脫離來(lái)適應(yīng)這一個(gè)全新的流程,可能需要做些調(diào)整,但是大體設(shè)計(jì)是非常不錯(cuò)的。
顯式的編排流程
我認(rèn)為Kubernetes的“API machinery”機(jī)制最大問(wèn)題是編排,即一系列獨(dú)立控制循環(huán)的松散集合所構(gòu)成工作流程。從表面上看,這似乎是一個(gè)好主意:你有好幾十個(gè)微小的控制循環(huán),每個(gè)控制循環(huán)只負(fù)責(zé)一個(gè)小功能。當(dāng)它們被整合到一個(gè)集群時(shí),它們彼此互相協(xié)作以調(diào)諧資源對(duì)象狀態(tài)并收斂至符合預(yù)期的最終狀態(tài)。所以這其中有何問(wèn)題?
問(wèn)題就在于出現(xiàn)錯(cuò)誤時(shí)幾乎不可能去進(jìn)行調(diào)試。 Kubernetes中典型的出錯(cuò),就是用戶(hù)將變更提交給集群,然后反復(fù)刷新以等待資源對(duì)象符合預(yù)期,如果遲遲沒(méi)有符合……那么,來(lái)問(wèn)題了。 Kubernetes分辨不出“對(duì)象已符合預(yù)期”和“控制循環(huán)被中斷并阻塞了其他事物”之間的區(qū)別。你或許希望有問(wèn)題的控制循環(huán)會(huì)發(fā)布它所管理對(duì)象的一些事件來(lái)幫你排錯(cuò),但總的來(lái)說(shuō)它們發(fā)揮不了多少作用。
此時(shí),你唯一的可行選擇是收集可能涉及的每個(gè)控制循環(huán)的日志,尋找被中斷的循環(huán)。如果你對(duì)所有控制循環(huán)的工作機(jī)制都有深入的了解,則定位錯(cuò)誤的速度可以更快一些,豐富的經(jīng)驗(yàn)可以讓你從資源對(duì)象的當(dāng)前狀態(tài),推斷出是哪個(gè)控制循環(huán)出錯(cuò),并正嘗試恢復(fù)運(yùn)行。
這里要注意關(guān)鍵一點(diǎn),我們看待復(fù)雜度的視角已經(jīng)從控制循環(huán)的設(shè)計(jì)者轉(zhuǎn)換到到了集群運(yùn)維人員。設(shè)計(jì)一個(gè)可以獨(dú)立執(zhí)行單一任務(wù)的控制循環(huán)很容易(并非是說(shuō)其不重要)。但是,要在集群中維護(hù)數(shù)十個(gè)這樣的控制循環(huán),就需要運(yùn)維人員非常熟悉這些控制循環(huán)的操作,以及它們之間的交互,并嘗試?yán)斫膺@樣一個(gè)組織松散的系統(tǒng)。這是必須認(rèn)真考慮的問(wèn)題,通常設(shè)計(jì)者編寫(xiě)控制循環(huán)代碼驗(yàn)證其功能這樣的工作是一次性的,但是運(yùn)維人員可能要終日和它們打交道,并反復(fù)處理控制循環(huán)出現(xiàn)的問(wèn)題。簡(jiǎn)化那些你只需要做一次的事情對(duì)運(yùn)維人員來(lái)說(shuō)不公平。
為了解決這個(gè)問(wèn)題,我會(huì)參照systemd的做法。它解決了類(lèi)似的生命周期管理問(wèn)題:給定當(dāng)前狀態(tài)A和目標(biāo)狀態(tài)B,如何從A變?yōu)锽?區(qū)別是,在systemd中,操作步驟及其依賴(lài)是顯式的。你告訴systemd,你的服務(wù)單元是multi-user.target服務(wù)組的一部分,則它必須在掛載文件系統(tǒng)之后聯(lián)網(wǎng)之前啟動(dòng)運(yùn)行。您還可以依賴(lài)系統(tǒng)的其他具體組件,例如說(shuō)只要sshd運(yùn)行,你的服務(wù)就需要運(yùn)行(聽(tīng)起來(lái)像邊車(chē),是吧?)。
這樣做的好處是systemd可以準(zhǔn)確地告訴用戶(hù),是系統(tǒng)的哪一部分發(fā)生故障,哪部分仍在運(yùn)行,或是哪個(gè)前置條件沒(méi)通過(guò)。它甚至還可以打印出系統(tǒng)啟動(dòng)的執(zhí)行過(guò)程,以供分析定位問(wèn)題,例如“哪個(gè)服務(wù)的啟動(dòng)耗時(shí)最長(zhǎng)”。
我想批量的照搬這些設(shè)計(jì)到我的集群編排系統(tǒng)中。不過(guò)也確實(shí)需要一些微調(diào),但大致來(lái)說(shuō):控制循環(huán)必須聲明它們對(duì)其他控制循環(huán)的依賴(lài)性,必須生成結(jié)構(gòu)化日志,以便用戶(hù)可以輕松搜索到“有關(guān)Pod X的所有控制循環(huán)的操作日志”,并且編排系統(tǒng)處理生命周期事件,可以采取像systemd那樣的做法,逐個(gè)排查定位到出問(wèn)題的服務(wù)組單元。
這在實(shí)踐起來(lái)會(huì)是怎么樣的?先結(jié)合Pod的生命周期說(shuō)起??赡芪覀儗⒍x一個(gè)抽象的“運(yùn)行”target,這是我們要達(dá)到的狀態(tài)——Pod已經(jīng)啟動(dòng)并且一切正常。容器運(yùn)行時(shí)將添加一個(gè)任務(wù)到“運(yùn)行”之前,以啟動(dòng)容器。但它可能要到存儲(chǔ)系統(tǒng)完成網(wǎng)絡(luò)設(shè)備掛載后才能運(yùn)行,因此它將在“存儲(chǔ)”target之后自行啟動(dòng)。同樣地,對(duì)于網(wǎng)絡(luò),容器希望在“網(wǎng)絡(luò)”target之后啟動(dòng)。
現(xiàn)在,你的Ceph控制循環(huán)將自己安排在“存儲(chǔ)”target之前運(yùn)行,因?yàn)樗?fù)責(zé)啟動(dòng)存儲(chǔ)。其他存儲(chǔ)控制循環(huán)也是相同的執(zhí)行流程(local bind mount,NFS等)。請(qǐng)注意,這里的執(zhí)行流程可以是并發(fā)執(zhí)行,因?yàn)樗鼈兌悸暶饕诖鎯?chǔ)準(zhǔn)備就緒之前執(zhí)行,但是并不在意在其他存儲(chǔ)插件的控制循環(huán)之前還是之后執(zhí)行。也有可能存在例外情況!比如你編寫(xiě)了一個(gè)很棒的存儲(chǔ)插件,它功能出色,但是必須先進(jìn)行NFS掛載,然后才能運(yùn)行。好了,我們只需要在nfs-mounts步驟中添加一個(gè)依賴(lài)項(xiàng),就可以完成了。這就和systemd類(lèi)似,我們既規(guī)定了順序,又規(guī)定了“還需要其他組件才能正常工作”這樣的硬性要求,因此用戶(hù)可以輕松定義服務(wù)的啟動(dòng)步驟。
(此處的討論我稍微簡(jiǎn)化了一下,并假設(shè)各項(xiàng)操作步驟沒(méi)有太多的循環(huán)依賴(lài)。要深入的話(huà),這可以展開(kāi)出更復(fù)雜的流程。請(qǐng)參閱下文進(jìn)一步探討,這里先不討論太過(guò)于復(fù)雜的流程。)
有了這些設(shè)計(jì),編排系統(tǒng)可以回答用戶(hù)“為什么Pod沒(méi)有啟動(dòng)?”用戶(hù)可以dump下Pod的啟動(dòng)流程圖,并查看哪些步驟已完成,哪些步驟失敗,哪些已在運(yùn)行。 NFS掛載已經(jīng)進(jìn)行了5分鐘?會(huì)不會(huì)有可能是NFS服務(wù)器已掛掉,但控制循環(huán)沒(méi)報(bào)超時(shí)?服務(wù)的各項(xiàng)配置和可能的狀態(tài),疊加出來(lái)的結(jié)果矩陣是非常龐大的:如果有了我們?cè)O(shè)計(jì)的這樣一個(gè)輔助調(diào)試的工具,這也不算個(gè)大問(wèn)題。 Systemd允許用戶(hù)以任意順序、任意約束往服務(wù)的啟動(dòng)過(guò)程添加內(nèi)容。但是當(dāng)出現(xiàn)問(wèn)題時(shí),我仍然可以輕松對(duì)其進(jìn)行故障排查,根據(jù)約束條件,在調(diào)試工具的輔助下,我可以第一時(shí)間定位到問(wèn)題的關(guān)鍵所在。
和Systemd給系統(tǒng)啟動(dòng)帶來(lái)的好處類(lèi)似,這讓系統(tǒng)可以盡可能地并行執(zhí)行生命周期操作,但也僅此而已。而且由于工作流程是顯式的,它還可以擴(kuò)展。你的集群是否存在這種情況:在每個(gè)Pod上都有企業(yè)定制的操作,且必須在某個(gè)生命周期階段內(nèi)執(zhí)行的?可以定義一個(gè)新的中間target,使其依賴(lài)于于正確的前置或后置條件,然后將控制循環(huán)掛接(hook)到這里接收回調(diào)。編排系統(tǒng)將確??刂蒲h(huán)在生命周期的各階段發(fā)揮作用。
請(qǐng)注意,這還解決了諸如Istio之類(lèi)的存在奇葩問(wèn)題。在Istio中,它們必須注入一些額外的開(kāi)發(fā)者提供的定義才能起作用。沒(méi)必要!提供對(duì)應(yīng)的控制循環(huán)介入到生命周期管理中,并根據(jù)實(shí)際需要在進(jìn)行調(diào)整。只要你可以向系統(tǒng)表示,在生命周期中某個(gè)特定階段需要執(zhí)行操作的,就無(wú)需考慮通過(guò)向運(yùn)維人員提供額外的資源對(duì)象去操作。
這部分內(nèi)容很長(zhǎng),但想表達(dá)的意思很簡(jiǎn)短。這和Kubernetes的原來(lái)的API machinery大相徑庭,因此需要大量新的設(shè)計(jì)工作才能實(shí)現(xiàn)。最突出的變化,控制循環(huán)不再只是簡(jiǎn)單地觀(guān)察集群對(duì)象的狀態(tài)并做出修正,還必須等待編排器(Orchestrator)完成對(duì)特定對(duì)象的調(diào)用,當(dāng)這些對(duì)象達(dá)到符合預(yù)期的狀態(tài)時(shí),控制循環(huán)再進(jìn)一步響應(yīng)。你現(xiàn)在可以通過(guò)注解和約定,將其在Kubernetes實(shí)現(xiàn)上。但除非對(duì)工作機(jī)制的細(xì)枝末節(jié)的都了解得一清二楚,否則就可觀(guān)察性和可調(diào)試性來(lái)說(shuō),沒(méi)什么幫助。
有趣的是,Kubernetes已經(jīng)有其中一些想法的原型實(shí)現(xiàn):Initializers和Finalizers 。它們分別是生命周期兩個(gè)不同階段里執(zhí)行預(yù)操作的鉤子。它使您可以將控制循環(huán)掛接到兩個(gè)硬編碼的“target”上。他們將控制循環(huán)分為三個(gè)部分:初始,“默認(rèn)”和終結(jié)。雖然是硬編碼,這是顯式工作流程圖的雛形。我打算把這個(gè)設(shè)計(jì)推廣到更一般的情況。
顯式的字段歸屬
承接上一部分設(shè)計(jì)的適度擴(kuò)展:使資源對(duì)象的每個(gè)字段都被特定的控制循環(huán)顯式擁有。該循環(huán)是唯一允許寫(xiě)入該字段的循環(huán)。如果未定義所有者,則該字段可被集群運(yùn)維人員寫(xiě)入,但運(yùn)維人員不能寫(xiě)其他任何內(nèi)容。這是由API machinery(而非約定)強(qiáng)制執(zhí)行的。
這已經(jīng)是大多數(shù)情況,但還是存在字段所有權(quán)模糊不清的時(shí)候。這導(dǎo)致兩個(gè)問(wèn)題:如果字段錯(cuò)誤,則很難弄清誰(shuí)負(fù)責(zé);而且一不小心就會(huì)進(jìn)入到兩個(gè)控制器修改一個(gè)字段的情況,陷入循環(huán)。
后者是MetalLB存在的大麻煩,它與其他一些負(fù)載均衡器實(shí)現(xiàn)方式發(fā)生了沖突。不應(yīng)該出現(xiàn)這樣的情況。Orchestrator應(yīng)該拒絕MetalLB添加到集群中,因?yàn)榕cLB相關(guān)的字段將有兩個(gè)所有者。
可能需要留個(gè)后門(mén),讓用戶(hù)處理一個(gè)字段有多個(gè)歸屬者的情況。但簡(jiǎn)單起見(jiàn),我在這里先不考慮,然后看看設(shè)計(jì)是不是經(jīng)得起考驗(yàn)。除非有充分證明支持,否則共享所有權(quán)就是一個(gè)會(huì)帶來(lái)潛在隱患的設(shè)計(jì)。
如果你還要求控制循環(huán)顯式注冊(cè)讀取的字段(并把那些沒(méi)有注冊(cè)的字段剝離出來(lái)——不準(zhǔn)作弊),這也可以讓你做一些有意義的事情,比如證明系統(tǒng)收斂(沒(méi)有讀->寫(xiě)->讀的循環(huán)),或是幫你照出拖慢系統(tǒng)響應(yīng)速度的調(diào)用環(huán)節(jié)。
有且只有IPv6
我對(duì)Kubernetes網(wǎng)絡(luò)部分非常熟悉,它是我最想全盤(pán)推倒重來(lái)的一個(gè)部分。有很多原因造成了網(wǎng)絡(luò)模塊發(fā)展成今天這個(gè)局面,我并不是想說(shuō)Kubernetes網(wǎng)絡(luò)設(shè)計(jì)得一無(wú)是處。但網(wǎng)絡(luò)不在我的編排體系里。這部分內(nèi)容很長(zhǎng),請(qǐng)帶點(diǎn)耐心。
首先,讓我們先徹底拋開(kāi)Kubernetes現(xiàn)有的網(wǎng)絡(luò)。覆蓋網(wǎng)絡(luò),Service, CNI,kube-proxy,網(wǎng)絡(luò)插件,這些統(tǒng)統(tǒng)都不要了。
(順便提一句,為什么網(wǎng)絡(luò)插件是不應(yīng)該出現(xiàn)K8s理想的設(shè)計(jì)中的。目前,已經(jīng)有不少企業(yè)開(kāi)始兜售他們的網(wǎng)絡(luò)插件了,你最好不要相信他們能保持客觀(guān)中立,讓我來(lái)列出反駁他們的理由。無(wú)論是自然界還是軟件界,所有生態(tài)系統(tǒng)的第一要?jiǎng)?wù)都是確保其繼續(xù)存在。你不能要求一個(gè)生態(tài)系統(tǒng)自我進(jìn)化到滅亡,你必須從外部觸發(fā)滅亡。)
回到正題,現(xiàn)在一切歸零了。我們有容器,它們需要互相通信,和外部通信。那該做什么?
讓我們賦予每個(gè)Pod一個(gè)IPv6地址。是的,只有一個(gè)IPv6地址。它們從哪里來(lái)?這里要求局域網(wǎng)支持IPv6(假定具備這樣的條件,畢竟我們的設(shè)計(jì)要面向未來(lái)),IP地址就從這來(lái)。你幾乎都不需要做IP地址沖突檢測(cè),2^64足夠大,隨機(jī)生成的IP地址基本上就滿(mǎn)足需求了。我們需要一個(gè)機(jī)制,好讓每個(gè)節(jié)點(diǎn)上之間能互相發(fā)現(xiàn),這樣就可以找到其他 Pod 在哪個(gè)節(jié)點(diǎn)上。這應(yīng)該不難實(shí)現(xiàn),這么做的理由很簡(jiǎn)單:對(duì)集群網(wǎng)絡(luò)內(nèi)的其他部分而言,一個(gè) Pod 看起來(lái)就像是在運(yùn)行其中的某個(gè)節(jié)點(diǎn)。
或者我們干脆組一個(gè)全是唯一本地地址的網(wǎng)絡(luò),然后手動(dòng)在每個(gè)節(jié)點(diǎn)上做路由。這實(shí)現(xiàn)起來(lái)非常容易,而且地址分配基本上就是 "隨便選一個(gè)數(shù)字就可以了"??赡苓€需要設(shè)計(jì)一個(gè)子集,這樣節(jié)點(diǎn)到節(jié)點(diǎn)的路由才會(huì)更有效率,但這都是不太復(fù)雜的東西。
有個(gè)麻煩是云服務(wù)商喜歡介入到網(wǎng)絡(luò)的基礎(chǔ)部分。所以IPAM模塊要保持可插拔性(在上文所提到工作流模型之內(nèi)),這樣我們就可以做一些事情,比如向AWS解釋流量是如何轉(zhuǎn)發(fā)的。不過(guò),使用IPv6可能就無(wú)法在GCP上運(yùn)行了。
不管怎么說(shuō),有許多備選的方案來(lái)做這部分的設(shè)計(jì)。就其根本而言,我只想在節(jié)點(diǎn)之間使用IPv6和配置一些基本的、簡(jiǎn)單的路由就可以了。這樣就可以在接近零配置的情況下,解決Pod之間的連接問(wèn)題,因?yàn)镮Pv6是有足夠大的地址空間,我們選一些隨機(jī)數(shù)字就能完事。
如果你有更復(fù)雜的連接需求,你就把這些作為額外的網(wǎng)絡(luò)接口和我設(shè)計(jì)的簡(jiǎn)單、可預(yù)測(cè)的IPv6路由接上。需要保證節(jié)點(diǎn)間的通信安全?引入wireguard隧道,添加路由,通過(guò)wireguard隧道推送節(jié)點(diǎn)IP,完事。編排系統(tǒng)不需要知道這些細(xì)枝末節(jié),除了可能會(huì)在節(jié)點(diǎn)生命周期管理中添加一個(gè)小小的控制循環(huán),這樣在隧道建立好之后,才讓節(jié)點(diǎn)處于就緒狀態(tài)。
好了,Pod之間的互聯(lián)互通,Pod和外部網(wǎng)絡(luò)的連接,這兩個(gè)問(wèn)題都解決了??紤]到現(xiàn)在只有IPv6,我們?nèi)绾翁幚砹魅爰旱腎Pv4流量呢?
首先,我們規(guī)定IPv4只適用于Pod和Internet連通的這種情況。在集群內(nèi)必須強(qiáng)制使用IPv6。
我們可以用幾種方法來(lái)應(yīng)對(duì)這個(gè)限制。簡(jiǎn)單來(lái)說(shuō),我們可以讓每個(gè)節(jié)點(diǎn)封裝IPv4流量,為Pod預(yù)留一小塊符合RFC 1918規(guī)范的地址空間(所有節(jié)點(diǎn)上預(yù)留的地址都從屬于這個(gè)空間)。這樣就可以讓它們到達(dá)IPv4互聯(lián)網(wǎng),但這都是每個(gè)節(jié)點(diǎn)的靜態(tài)配置,根本不需要集群可見(jiàn)。你甚至可以將IPv4的東西完全隱藏在控制平面中,這只是每臺(tái)機(jī)器運(yùn)行時(shí)的一個(gè)實(shí)現(xiàn)細(xì)節(jié)。
我們也可以用NAT64和CLAT來(lái)找點(diǎn)樂(lè)子:讓整個(gè)網(wǎng)絡(luò)只用IPv6,但用CLAT來(lái)欺騙Pods,讓它們以為自己有IPv4連接。然后在Pod內(nèi)進(jìn)行 IPv4到IPv6的地址翻譯,并將流量發(fā)送到NAT64網(wǎng)關(guān)??梢允敲颗_(tái)機(jī)器的NAT64,也可以是集群內(nèi)的部署的。如果你需要處理大量的NAT64流量,甚至可以用一個(gè)集群外部類(lèi)似CGNAT這樣的東西。在這一點(diǎn)上,CLAT和NAT64已經(jīng)有很好的應(yīng)用:你的手機(jī)可能正是通過(guò)這樣的方式來(lái)讓你獲得IPv4地址接入互聯(lián)網(wǎng)。
我可能會(huì)從簡(jiǎn)單的IPv4偽裝開(kāi)始(第一種方案),因?yàn)樗璧呐渲昧繕O少,都可以由每臺(tái)機(jī)器在本地處理,不會(huì)有任何交叉影響,讓我們更容易著手實(shí)現(xiàn)。另外,后期改起來(lái)也很方便,因?yàn)樵赑od看來(lái)都是一樣的,而且我們也不希望通過(guò)一個(gè)網(wǎng)絡(luò)插件來(lái)處理任何東西。
到這我們已經(jīng)處理了出站方面的問(wèn)題,我們有雙棧上網(wǎng)。接下來(lái)怎么處理入站端呢?負(fù)載均衡器。不考慮把它構(gòu)建在核心編排系統(tǒng)中。編排系統(tǒng)應(yīng)該專(zhuān)注于一件事:如果一個(gè)數(shù)據(jù)包的目的IP是Pod IP,就把這個(gè)數(shù)據(jù)包交付給Pod。
正好,這應(yīng)該主要適合公有云的場(chǎng)景。廠(chǎng)商們也傾向于這樣的模型,這樣就可以把他們的負(fù)載均衡器產(chǎn)品賣(mài)給你了。好吧,你贏了,姑且先采取這樣的設(shè)計(jì)模型。不過(guò)我想要一個(gè)控制循環(huán)來(lái)控制負(fù)載均衡器,并將其與IPAM集成,這樣VPC就能明白如何將數(shù)據(jù)包路由到Pod IP。
這忽略了由物理機(jī)搭建集群的場(chǎng)景。但這也不是一件壞事,因?yàn)闆](méi)有一個(gè)放之四海而皆準(zhǔn)的負(fù)載均衡器。如果我試圖給你一個(gè)負(fù)載均衡器,但它沒(méi)有完全按照你預(yù)想的工作。這說(shuō)不定還會(huì)讓你抓狂,一氣之下裝起了Istio,這時(shí)我所討論到降低復(fù)雜性都是無(wú)用功了。
讓負(fù)載均衡器集中精力把一件事做好:如果要把數(shù)據(jù)包轉(zhuǎn)發(fā)給Pod,那就把數(shù)據(jù)包轉(zhuǎn)發(fā)給Pod。在遵循這一原則的前提下,你可以基于LVS、Nginx、無(wú)狀態(tài)、云廠(chǎng)商負(fù)載均衡服務(wù)、F5等來(lái)構(gòu)建負(fù)載均衡器,你可以自由發(fā)揮。這里也許可以考慮提供幾個(gè)“默認(rèn)”實(shí)現(xiàn)。對(duì)于負(fù)載均衡器這部分,我確實(shí)有很多想法,也許我設(shè)計(jì)的方案就挺合適。這里的關(guān)鍵是編排系統(tǒng)對(duì)負(fù)載均衡器如何實(shí)現(xiàn)毫不關(guān)心,只要能把數(shù)據(jù)包轉(zhuǎn)發(fā)到Pod上。
我沒(méi)有觸及IPv4 ingress的問(wèn)題,主要是我認(rèn)為這是負(fù)載均衡器該做的事情,讓它們各自用最合適的方式來(lái)解決問(wèn)題。像Nginx這樣的代理型負(fù)載均衡器,只需要通過(guò)IPv6轉(zhuǎn)發(fā)后端就可以了,沒(méi)什么問(wèn)題。無(wú)狀態(tài)的負(fù)載均衡器可以很容易地將IPv4地址轉(zhuǎn)換成IPv6,其間有個(gè)轉(zhuǎn)換標(biāo)準(zhǔn)。源地址為::fffff:1.2.3.4數(shù)據(jù)包到達(dá)Pod時(shí),Pod可以將其轉(zhuǎn)回IPv4?;蛘吒纱鄬⑵湟暈镮Pv6直接處理,這樣的處理方式就假定網(wǎng)絡(luò)中的地址都是IPv6。如果使用了無(wú)狀態(tài)翻譯方式,出站的時(shí)候需要有狀態(tài)的跟蹤機(jī)制,來(lái)映射回IPv4。但這也比原先在IPv4下采取的層層封裝方式來(lái)得好。從節(jié)點(diǎn)的視角來(lái)看,這完全可以通過(guò)一條額外的::fffff:0000:0000/96的路由來(lái)處理。
將極簡(jiǎn)貫徹到底
作為上述所有網(wǎng)絡(luò)問(wèn)題的替代方案,我們干脆都不要了?;氐紹org式的端口分配,所有服務(wù)都在主機(jī)的網(wǎng)絡(luò)命名空間中運(yùn)行,并且必須請(qǐng)求分配端口。不是監(jiān)聽(tīng):80,而是監(jiān)聽(tīng):%port%,然后編排系統(tǒng)會(huì)用一個(gè)未使用的端口號(hào)來(lái)代替。例如,最終會(huì)變成監(jiān)聽(tīng)主機(jī)上的:53928。
這樣的設(shè)計(jì)真的非常非常簡(jiǎn)單。簡(jiǎn)單到基本沒(méi)什么需要額外做的。在分配端口時(shí),需要做一些煩人的檢查,以避免端口沖突,這倒是一個(gè)令人頭疼的問(wèn)題。還有一個(gè)端口耗盡的問(wèn)題,因?yàn)槿绻愕目蛻?hù)端非?;钴S且數(shù)量不少,65000個(gè)端口其實(shí)并不算太多。但這個(gè)真的非常非常簡(jiǎn)潔。我個(gè)人崇尚簡(jiǎn)潔。
我們也可以采用經(jīng)典的Docker方式,將其和上面的設(shè)計(jì)結(jié)合起來(lái):容器在自己的網(wǎng)路命名空間中運(yùn)行,使用一些臨時(shí)的私有 IP。你可以使用任意的端口,但對(duì)其他Pod和外部可見(jiàn)的只有那些告知運(yùn)行時(shí)要暴露的端口。而且你只能聲明要暴露的容器端口,映射到主機(jī)上的端口是由容器運(yùn)行時(shí)選擇的。(這里也可以留一些后門(mén)來(lái)應(yīng)對(duì)特例,你可以告訴系統(tǒng)你非要80端口不可,然后通過(guò)調(diào)度約束來(lái)起作用,調(diào)度到80端口沒(méi)被占用的機(jī)器——類(lèi)似于當(dāng)前Kubernetes在這方面的處理。)
上面論述的關(guān)鍵點(diǎn)是,這些設(shè)計(jì)極大地簡(jiǎn)化了網(wǎng)絡(luò)層。以至于我可以在短短幾分鐘內(nèi)向別人解釋清楚,確保他們能夠了解其工作機(jī)制。
缺點(diǎn)是這把復(fù)雜性推給了服務(wù)發(fā)現(xiàn)。你不能使用“純粹的DNS”作為發(fā)現(xiàn)機(jī)制,因?yàn)榇蠖鄶?shù)DNS客戶(hù)端不解析SRV記錄,因此不會(huì)動(dòng)態(tài)發(fā)現(xiàn)隨機(jī)端口。
搞笑的是,服務(wù)網(wǎng)格的逐漸普及讓這個(gè)問(wèn)題不再是個(gè)問(wèn)題。因?yàn)槿藗儸F(xiàn)在假設(shè)存在一個(gè)本地智能代理,它可以做任何服務(wù)發(fā)現(xiàn)能做的事情,并將其映射到一個(gè)網(wǎng)絡(luò)視圖上,而這個(gè)視圖只被需要它的 Pod 看到。不過(guò),我不太愿意接受這種做法,因?yàn)榉?wù)網(wǎng)格增加了太多的復(fù)雜性和維護(hù)成本,所以我不想采用它們……至少在有實(shí)踐方案表明能使它們良好運(yùn)行之前,我維持這樣的觀(guān)點(diǎn)。
所以,我們不妨做一些類(lèi)似服務(wù)網(wǎng)格的東西,但更簡(jiǎn)單點(diǎn)。在源主機(jī)上做一些自動(dòng)的IP端口轉(zhuǎn)換……不過(guò)這看起來(lái)很像kube-proxy,這隨之而來(lái)的就是復(fù)雜性和調(diào)試?yán)щy(這不是一個(gè)通過(guò)在不同的地方執(zhí)行tcpdump就能解決的問(wèn)題,因?yàn)榱髁繒?huì)在不同的跳數(shù)之間變化)。
所以,這個(gè)方案也表明顯式主機(jī)端口映射可能也算個(gè)解決方案,但仍存在很多隱藏的復(fù)雜性(我相信這就是為什么Kubernetes一開(kāi)始就采用單Pod單IP的原因)。Borg通過(guò)強(qiáng)制規(guī)定解決了這種復(fù)雜性,它規(guī)定了應(yīng)用都必須用自家設(shè)計(jì)的依賴(lài)庫(kù)和框架。所以這里有個(gè)顯而易見(jiàn)的缺點(diǎn),不能隨意更換的服務(wù)發(fā)現(xiàn)和負(fù)載平衡的實(shí)現(xiàn)框架。除非我們采用真正的服務(wù)網(wǎng)格,否則做不到這點(diǎn)。
本節(jié)描述的方案還有可改善之處,但我更傾向于上一節(jié)的實(shí)現(xiàn)。它的設(shè)計(jì)時(shí)要考慮的東西更多一些,但可以得到是一個(gè)可組合、可調(diào)試、可理解的系統(tǒng),不需要無(wú)限制地增加功能以滿(mǎn)足新需求。
安全同樣重要
長(zhǎng)篇大論的探討完網(wǎng)絡(luò)之后,來(lái)簡(jiǎn)單說(shuō)一下安全問(wèn)題。容器默認(rèn)應(yīng)該被最大限度的沙盒化,并需要顯式的雙重確認(rèn)步驟。
我們可以直接應(yīng)用Jessie Frazelle在容器安全方面出色的工作成果。打開(kāi)默認(rèn)的apparmor和seccomp配置文件。不允許在容器中以root身份運(yùn)行。使用user命名空間進(jìn)行隔離,這樣哪怕有人設(shè)法在容器中升級(jí)為root,那也不是系統(tǒng)root。默認(rèn)阻止所有設(shè)備掛載。不允許主機(jī)綁定掛載。為了達(dá)到效果,寫(xiě)一個(gè)你能想的的最嚴(yán)格的Pod安全策略,然后把他們作為默認(rèn)值,并且讓它們很難背離默認(rèn)值。
Pod安全策略與此相當(dāng)接近,因?yàn)樗鼈儚?qiáng)制執(zhí)行雙重確認(rèn):集群運(yùn)維人員確認(rèn)允許用戶(hù)做不安全的操作,而用戶(hù)必須顯式申請(qǐng)權(quán)限執(zhí)行不安全的操作。遺憾的是,Kubernetes現(xiàn)有的設(shè)計(jì)并沒(méi)有這么考慮。這里我們先不關(guān)心向下的兼容性,把默認(rèn)值做得盡可能安全。
(溫馨提示:從這里開(kāi)始,章節(jié)內(nèi)容開(kāi)始有點(diǎn)天馬行空。這些都是我想要的設(shè)計(jì),不過(guò)我強(qiáng)烈意識(shí)到,很多細(xì)節(jié)沒(méi)有考慮清楚。)
gVisor?Firecracker?
說(shuō)到默認(rèn)情況下的最高級(jí)別的安全,我覺(jué)得不妨采取更激進(jìn)的沙盒化措施。可以考慮將gVisor或Firecracker作為默認(rèn)容器沙箱,并開(kāi)啟雙重確認(rèn)機(jī)制,最終達(dá)到“與主機(jī)共享內(nèi)核的最安全的容器環(huán)境”這目的?
這里需要再斟酌斟酌。一方面,這些工具所承諾的極度安全非常吸引我。另一方面,這也不可避免地要運(yùn)行一大堆額外的代碼,也帶來(lái)潛在漏洞和復(fù)雜性。而且這些沙盒對(duì)你能做的事情進(jìn)行了極度的限制。甚至,任何與存儲(chǔ)有關(guān)的事情都會(huì)演變成“不,你不能有任何存儲(chǔ)”。這對(duì)于某些場(chǎng)景而言來(lái)說(shuō)是不錯(cuò),但把它變成默認(rèn)值就限制得太過(guò)分了。
至少在存儲(chǔ)方面,virtio-fs的成熟會(huì)解決很多這樣的問(wèn)題,能讓這些沙盒在不破壞安全模型的前提下,執(zhí)行有效地綁定和掛載操作??赡芪覀儜?yīng)該在那個(gè)時(shí)候再重新審視這個(gè)決定?
去中心化集群
我猜這個(gè)時(shí)髦的術(shù)語(yǔ)應(yīng)該是“邊緣計(jì)算”,但我真正的意思是,我想讓我所有的服務(wù)器都在一個(gè)編排系統(tǒng)下,把它們作為一個(gè)單元來(lái)運(yùn)作。這意味著我家里服務(wù)器機(jī)架上的計(jì)算機(jī),我在DigitalOcean上的虛擬機(jī),以及在互聯(lián)網(wǎng)上的其他幾臺(tái)服務(wù)器。這些都應(yīng)該是集群內(nèi)基本等效的一部分,實(shí)際上也具備這樣的能力。
這就導(dǎo)致了幾個(gè)與Kubernetes不一樣的地方。首先,工作節(jié)點(diǎn)應(yīng)該設(shè)計(jì)得比當(dāng)前更加獨(dú)立,對(duì)控制節(jié)點(diǎn)的依賴(lài)更少??梢栽跊](méi)有控制節(jié)點(diǎn)的情況下長(zhǎng)時(shí)間(極端情況下是幾周)運(yùn)行,只要沒(méi)有機(jī)器故障,導(dǎo)致需要Pod重新調(diào)度。
我認(rèn)為主要的轉(zhuǎn)變是將更多的數(shù)據(jù)同步節(jié)點(diǎn)上,并存到持久化存儲(chǔ)中。這樣節(jié)點(diǎn)自身就有了恢復(fù)正常運(yùn)行所需要的數(shù)據(jù),和主節(jié)點(diǎn)失聯(lián)后也能從冷啟動(dòng)中恢復(fù)到可響應(yīng)狀態(tài)。理論上,我希望集群編排系統(tǒng)在每個(gè)節(jié)點(diǎn)上填充一組systemd單元,在節(jié)點(diǎn)的運(yùn)行過(guò)程中扮演一個(gè)被動(dòng)管理的角色。它在本地?fù)碛兴枰囊磺?,除非這些東西需要改變,否則節(jié)點(diǎn)是獨(dú)立于管理節(jié)點(diǎn)的。
這確實(shí)導(dǎo)致了如何處理節(jié)點(diǎn)失聯(lián)的問(wèn)題。在“中心化”的集群中,這是觸發(fā)工作負(fù)載重新調(diào)度的關(guān)鍵信號(hào),但在去中心化的情況下,我更有可能會(huì)說(shuō)“別擔(dān)心,這可能是短暫的失聯(lián),節(jié)點(diǎn)很快就會(huì)回來(lái)”。所以,節(jié)點(diǎn)生命周期以及它與Pod生命周期的關(guān)系將不得不改變。也許你必須顯式聲明你是否希望Pod是“高可用”(即當(dāng)節(jié)點(diǎn)失聯(lián)時(shí)主動(dòng)地重新調(diào)度)或 “盡力”(只有當(dāng)系統(tǒng)確定一個(gè)節(jié)點(diǎn)已經(jīng)掛了并無(wú)法恢復(fù)時(shí)才重新調(diào)度)。
一種說(shuō)法是,在我設(shè)計(jì)的“去中心化”集群中,Pod的表現(xiàn)更像是“獨(dú)一無(wú)二的寵物”而不是“牧場(chǎng)里的羊群”。我會(huì)考慮設(shè)計(jì)類(lèi)似無(wú)狀態(tài)應(yīng)用水平擴(kuò)展的機(jī)制,但與Kubernetes不同,在這個(gè)場(chǎng)景下,當(dāng)應(yīng)用副本數(shù)縮小到一個(gè)時(shí),我可以干預(yù)這一個(gè)應(yīng)用運(yùn)行在哪個(gè)節(jié)點(diǎn)上。這是Kubernetes不鼓勵(lì)的做法,所以此處我們不得不背離Kubernetes的某些做法。
另一種觀(guān)點(diǎn)是,將集群聯(lián)邦視為一級(jí)對(duì)象。實(shí)際上可以把分散的機(jī)器看成是單獨(dú)的集群,各自有自己的控制平面,然后將它們整合作為一個(gè)超大型集群來(lái)使用。這當(dāng)然可以,并且回答了一些關(guān)于如何將節(jié)點(diǎn)與控制平面解耦的問(wèn)題(我個(gè)人的答案:不要嘗試這么做,應(yīng)當(dāng)將控制平面的功能盡可能地下放到數(shù)量龐大的工作節(jié)點(diǎn))。在這種情況下,我希望控制平面是極其精簡(jiǎn)的,否則在Kubernetes中這樣做的開(kāi)銷(xiāo)會(huì)很大,我個(gè)人希望避免這種情況。
這也提高了網(wǎng)絡(luò)部分的難度,因?yàn)槲覀儸F(xiàn)在必須跨網(wǎng)連接。我的做法是以某種方式去和Tailscale集成,這剛好解決我們需求。也可以選擇需要一些更定制化的、組件更少的方案(不要進(jìn)行多余的NAT轉(zhuǎn)換)。
納管虛擬機(jī)
注意:當(dāng)我在這里說(shuō)虛擬機(jī)的時(shí)候,我并不是指“用戶(hù)在Kubernetes上運(yùn)行的Pod”。我指的是管理員自己創(chuàng)建的hypervisor的服務(wù)器虛擬機(jī)。類(lèi)似Proxmox或ESXi創(chuàng)建出來(lái)的,但不是EC2這種托管的。
我希望我的編排系統(tǒng)能夠無(wú)縫地管理容器和虛擬機(jī)。否則,在實(shí)踐中,我將需要一個(gè)單獨(dú)的hypervisor,那樣一來(lái)我將有兩套的管理系統(tǒng)。
我不確定這究竟會(huì)成為一種怎樣的設(shè)計(jì),只是一個(gè)粗略的想法。kubevirt提供的功能應(yīng)該內(nèi)置到系統(tǒng)中,并成為系統(tǒng)關(guān)鍵的一部分,就像容器一樣。這是一個(gè)相當(dāng)龐大的問(wèn)題,因?yàn)檫@可能意味著從“讓我運(yùn)行一個(gè)帶有虛擬軟盤(pán)的系統(tǒng)”到“運(yùn)行一個(gè)看起來(lái)和感覺(jué)都有點(diǎn)像EC2的管理程序”,這是非常不同的兩件事。我唯一確定的是,我不希望運(yùn)行同時(shí)運(yùn)行Proxmox和這套編排系統(tǒng),但我確實(shí)需要同時(shí)擁有虛擬機(jī)和容器。
如何存儲(chǔ)?
在我當(dāng)前的設(shè)想中,存儲(chǔ)是一個(gè)巨大未知數(shù)。我缺乏充足的經(jīng)驗(yàn),沒(méi)有太多獨(dú)到的見(jiàn)解。我覺(jué)得CSI太復(fù)雜了,應(yīng)當(dāng)精簡(jiǎn),但除了上面提到的,與生命周期工作流程有關(guān)的那一小部分,我也沒(méi)有好的想法可以提出來(lái)。存儲(chǔ)是我目前唯一個(gè)想保留目前Kubernetes插件化設(shè)計(jì)的模塊,不過(guò)一旦我對(duì)這方面的知識(shí)了解到位,我可能會(huì)有不同想法。
最后
寫(xiě)到這里,文章的內(nèi)容很多,我相信我可能遺漏了一些我一開(kāi)始想解決的問(wèn)題或是一些古怪的想法。但是,如果我明天就要著手替換Kubernetes,上面列的幾點(diǎn)應(yīng)該是我一定要改的地方。
我沒(méi)有過(guò)多提及這個(gè)行業(yè)內(nèi)的其他玩家——Hashicorp的Nomad,F(xiàn)acebook的Twine,Google的Borg和Omega,Twitter的Mesos。除了Borg之外,我還沒(méi)有實(shí)踐過(guò)其它方案,無(wú)法對(duì)其有深刻見(jiàn)解。如果要著手開(kāi)發(fā)一個(gè)全新的Kubernetes,我一定先投入更多的時(shí)間去了解清楚這些競(jìng)品,這樣我就可以取其精華,去其糟粕。我也會(huì)對(duì)Nix進(jìn)行深入的思考,好好想想如何把它糅合到我的設(shè)計(jì)中。
老實(shí)說(shuō),我可能也只是想想而已,什么也沒(méi)實(shí)踐。我從Borg上學(xué)到了很多關(guān)于云計(jì)算理念的精髓,而Kubernetes也促使我進(jìn)行了反思。我目前依舊相信,最好的容器編排系統(tǒng)就是沒(méi)有容器編排系統(tǒng),而這種努力將不惜一切代價(jià)避免Kubernetes各種坑。顯然,這個(gè)想法與構(gòu)建容器編排系統(tǒng)是格格不入的。















 
 
 



 
 
 
 