摘要:從年以來(lái),谷歌基于容器研發(fā)三個(gè)容器管理系統(tǒng),分別是和。這篇論文由這三個(gè)容器集群管理系統(tǒng)長(zhǎng)年開(kāi)發(fā)維護(hù)的谷歌工程師和于近日發(fā)表,闡述了谷歌從到這個(gè)旅程中所獲得的知識(shí)和經(jīng)驗(yàn)教訓(xùn)。和完全是谷歌內(nèi)部系統(tǒng)相比,是開(kāi)源的。
從2000年以來(lái),谷歌基于容器研發(fā)三個(gè)容器管理系統(tǒng),分別是Borg、Omega和Kubernetes。這篇論文由這三個(gè)容器集群管理系統(tǒng)長(zhǎng)年開(kāi)發(fā)維護(hù)的谷歌工程師Brendan Burns、Brian Grant、David Oppenheimer、Eric Brewer和John Wilkes于近日發(fā)表,闡述了谷歌從Borg到Kubernetes這個(gè)旅程中所獲得的知識(shí)和經(jīng)驗(yàn)教訓(xùn)。
盡管對(duì)軟件容器廣泛傳播的興趣是最近的現(xiàn)象,但在谷歌我們大規(guī)模使用Linux容器已經(jīng)有10多年了,而且期間我們建了三種不同的容器管理系統(tǒng)。每一個(gè)系統(tǒng)都受之前的系統(tǒng)影響頗深,盡管它們的誕生是出于不同原因。這篇文章描述了我們?cè)谘邪l(fā)和使用它們的過(guò)程中得到的經(jīng)驗(yàn)教訓(xùn)。
第一個(gè)在谷歌被開(kāi)發(fā)出來(lái)的統(tǒng)一的容器管理系統(tǒng),在我們內(nèi)部稱(chēng)之為“Borg”,它管理著長(zhǎng)時(shí)間運(yùn)行的生產(chǎn)服務(wù)和批處理服務(wù)。這兩類(lèi)任務(wù)之前是由兩個(gè)分離開(kāi)的系統(tǒng)來(lái)管理的:Babysitter和Global Work Queue。Global Work Queue的構(gòu)架極大地影響了Borg,但卻只是針對(duì)批量服務(wù)的,且兩者都在Linux control groups誕生之前。Borg將這兩種應(yīng)用所用的機(jī)器統(tǒng)一成一個(gè)池子,這樣得以提高資源利用率,進(jìn)而降低成本。之所以可以實(shí)現(xiàn)這樣的機(jī)器資源共享,是因?yàn)榭梢阅玫絃inux內(nèi)核的容器支持(確實(shí),Google對(duì)Linux內(nèi)核的容器代碼貢獻(xiàn)了很多),這使得在對(duì)時(shí)限敏感的、且面對(duì)用戶的服務(wù)和占用很多CPU資源的批處理進(jìn)程提供了更好的隔離。
由于越來(lái)越多的應(yīng)用被開(kāi)發(fā)并運(yùn)行在Borg上,我們的應(yīng)用和底層團(tuán)隊(duì)開(kāi)發(fā)了一個(gè)廣泛的工具和服務(wù)的生態(tài)系統(tǒng)。這些系統(tǒng)提供了配置和更新job的機(jī)制,能夠預(yù)測(cè)資源需求,動(dòng)態(tài)地對(duì)在運(yùn)行中的程序推送配置文件、服務(wù)發(fā)現(xiàn)、負(fù)載均衡、自動(dòng)擴(kuò)容、機(jī)器生命周期的管理、額度管理以及更多。這個(gè)生態(tài)系統(tǒng)的發(fā)展源自谷歌內(nèi)部不同團(tuán)隊(duì)的需求,發(fā)展的結(jié)果成為了異構(gòu)的、ad-hoc系統(tǒng)的集合,Borg的使用者能夠用幾種不同的配置語(yǔ)言和進(jìn)程來(lái)配置和溝通。由于Borg的規(guī)模、功能的廣泛性和超高的穩(wěn)定性,Borg在谷歌內(nèi)部依然是主要的容器管理系統(tǒng)。
Omega,作為Borg的延伸,它的出現(xiàn)是出于提升Borg生態(tài)系統(tǒng)軟件工程的愿望。Omega應(yīng)用到了很多在Borg內(nèi)已經(jīng)被認(rèn)證的成功的模式,但是是從頭開(kāi)始來(lái)搭建以期更為一致的構(gòu)架。Omega存儲(chǔ)了基于Paxos、圍繞transaction的集群的狀態(tài),能夠被集群的控制面板(比如調(diào)度器)接觸到,使用了優(yōu)化的進(jìn)程控制來(lái)解決偶爾發(fā)生的沖突。這種分離允許Borgmaster的功能被區(qū)分成幾個(gè)并列的組建,而不是把所有變化都放到一個(gè)多帶帶的、巨石型的master里。許多Omega的創(chuàng)新(包括多個(gè)調(diào)度器)都被收錄進(jìn)了Borg。
谷歌研發(fā)的第三個(gè)容器管理系統(tǒng)是Kubernetes。Kubernetes的研發(fā)和認(rèn)知背景,是針對(duì)在谷歌外部的對(duì)Linux容器感興趣的開(kāi)發(fā)者以及谷歌在公有云底層商業(yè)增長(zhǎng)的考慮。和Borg、Omega完全是谷歌內(nèi)部系統(tǒng)相比,Kubernetes是開(kāi)源的。像Omega一樣,Kubernetes在其核心有一個(gè)被分享的持久存儲(chǔ),有組件來(lái)檢測(cè)相關(guān)ojbect的變化。跟Omega不同的是,Omega把存儲(chǔ)直接暴露給信任的控制面板的組件,而在Kubernete中,是要完全由domain-specific的提供更高一層的版本控制認(rèn)證、語(yǔ)義、政策的REST API來(lái)接觸,以服務(wù)更多的用戶。更重要的是,Kubernetes是由一支在集群層面應(yīng)用開(kāi)發(fā)能力更強(qiáng)的開(kāi)發(fā)者開(kāi)發(fā)的,他們主要的設(shè)計(jì)目標(biāo)是用更容易的方法去部署和管理復(fù)雜的分布式系統(tǒng),同時(shí)仍然能通過(guò)容器所提升的使用效率來(lái)受益。
這篇文章描述了谷歌從Borg到Kubernetes這個(gè)旅程中所獲得知識(shí)和經(jīng)驗(yàn)教訓(xùn)。
容器歷史上,第一個(gè)容器提供的僅僅是root file system的隔離(通過(guò)chroot),再加上FreeBSD jails提供額外的例如process ID這樣的namespaces。Solaris后來(lái)成為先鋒并且做了很多加強(qiáng)的探索。Linux control groups(cgroups)運(yùn)用了很多這些想法,在這個(gè)領(lǐng)域的發(fā)展一直延續(xù)到今天。
容器的資源隔離特性使得谷歌的資源使用率遠(yuǎn)遠(yuǎn)高出業(yè)界同行。例如,Borg使用容器將對(duì)延遲敏感、面向用戶的任務(wù)和批量任務(wù)放在相通的物理機(jī)上,并會(huì)為它們預(yù)留更多的資源,這樣可以解決load spikes、fail-over等問(wèn)題。容器提供的資源管理工具使這些得以實(shí)現(xiàn),穩(wěn)定的內(nèi)核層面的資源隔離也使進(jìn)程之間不互相干擾。我們通過(guò)在研發(fā)Borg的同時(shí)加強(qiáng)Linux容器的方式來(lái)獲得成功。然而,隔離并不是完美的,容器在內(nèi)核操作系統(tǒng)不能管理的資源隔離方面鞭長(zhǎng)莫及,比如level 3 processor caches、內(nèi)存帶寬、以及容器需要被一個(gè)額外的安全層支持以抵抗云端的各種惡意攻擊。
現(xiàn)代的容器不僅僅是隔離機(jī)制:它也包括鏡像,即包含了在容器內(nèi)能夠讓?xiě)?yīng)用跑起來(lái)的文件。在谷歌內(nèi)部,MPM(Midas Package Manager)被用來(lái)建造和部署容器鏡像。在隔離機(jī)制和MPM之間同樣的共生關(guān)系,也可以在Docker daemon和Docker鏡像之間被發(fā)現(xiàn)。在這篇文章剩余的篇幅中,我們會(huì)使用“容器”這個(gè)詞來(lái)包含這兩方面:運(yùn)行時(shí)隔離和鏡像。
面向應(yīng)用的架構(gòu)(Application-oriented infrastructure)隨著時(shí)間的推移,我們?cè)絹?lái)越清楚容器在更高一層使用時(shí)的好處。容器化能使數(shù)據(jù)中心從面向機(jī)器轉(zhuǎn)為面向應(yīng)用。這個(gè)部分討論兩個(gè)例子:
容器封裝了應(yīng)用環(huán)境,把很多機(jī)器和操作系統(tǒng)的細(xì)節(jié)從應(yīng)用開(kāi)發(fā)者和部署底層那里抽象了出來(lái)。
因?yàn)樵O(shè)計(jì)良好的容器和鏡像的作用范圍是一個(gè)很小的應(yīng)用,因此管理容器意味著管理應(yīng)用而非機(jī)器,極大簡(jiǎn)化了應(yīng)用的部署和管理。
應(yīng)用環(huán)境Linux內(nèi)核里的cgroup、chroot和namespace的原本是為了保護(hù)應(yīng)用不受周邊雜亂鄰里的影響。把這些和容器鏡像組合起來(lái)創(chuàng)建一個(gè)抽象事物把應(yīng)用從運(yùn)行它們的(紛雜的)操作系統(tǒng)里隔離出來(lái),提高了部署可靠性,也通過(guò)減少不一致性和沖突而加快了開(kāi)發(fā)速度。
能讓這個(gè)抽象事物得以實(shí)現(xiàn)的關(guān)鍵在于有一個(gè)自包含的鏡像,它把一個(gè)應(yīng)用幾乎所有的依賴(lài)環(huán)境都打包然后部署在一個(gè)容器里。
如果這個(gè)過(guò)程做的正確,本地的外部環(huán)境就只剩下Linux內(nèi)核的system-call interface. 這個(gè)有限制的interface極大提高了鏡像的便攜性,它并不完美:應(yīng)用仍然暴露給了OS interface,尤其是在socket選項(xiàng)的廣泛表面上、/proc、和給ioctl call的所傳參數(shù)上。我們希望后面類(lèi)似Open Container Initiative(OCI:點(diǎn)這里)的努力能繼續(xù)把容器抽象的表層能理清。
然而,容器提供的隔離和對(duì)環(huán)境依賴(lài)的最低性在谷歌內(nèi)部頗為有效,容器也是谷歌內(nèi)部底層唯一支持的應(yīng)用程序運(yùn)行實(shí)體。這樣的好處之一就是在任何時(shí)候,谷歌在它一整臺(tái)機(jī)器上只有很少量的OS版本部署,只需要很少量的人員來(lái)管理或升級(jí)。
有很多種方式可以實(shí)現(xiàn)這些自包含的鏡像。在Borg里,程序的二進(jìn)制文件在構(gòu)建時(shí)靜態(tài)地連接到公司范圍內(nèi)repo庫(kù)里已知的library版本。即便這樣,Borg容器鏡像也并非100%的自包含:因?yàn)閼?yīng)用會(huì)共享一個(gè)所謂的基礎(chǔ)鏡像,而不是將這個(gè)基礎(chǔ)鏡像打包在每個(gè)容器中。這個(gè)基礎(chǔ)鏡像包含了一些容器需要用到的utilities,比如tar和libc library,因此對(duì)基礎(chǔ)鏡像的升級(jí)會(huì)影響運(yùn)行中的應(yīng)用,偶爾也會(huì)變成一個(gè)比較嚴(yán)重的問(wèn)題產(chǎn)生來(lái)源。
現(xiàn)在的容器鏡像格式,比如Docker和ACI把容器進(jìn)一步抽象,通過(guò)消除內(nèi)在的主機(jī)OS環(huán)境依賴(lài)和要求外在的user命令來(lái)共享容器之間的鏡像數(shù)據(jù),使得距離理想的自包含性又近了一步。
容器作為管理的單位搭建面向容器而非機(jī)器的管理API把數(shù)據(jù)中心的關(guān)鍵字從機(jī)器轉(zhuǎn)向了應(yīng)用。這樣有很多好處:(1)減輕應(yīng)用開(kāi)發(fā)者和運(yùn)維團(tuán)隊(duì)操心機(jī)器和系統(tǒng)具體細(xì)節(jié)的壓力;(2)提供底層團(tuán)隊(duì)彈性,得以升級(jí)新硬件和操作系統(tǒng),但同時(shí)對(duì)在跑的應(yīng)用和開(kāi)發(fā)者影響甚?。唬?)它把管理系統(tǒng)收集的telemetry(比如CPU和內(nèi)存用量的metrics)和應(yīng)用而非機(jī)器綁在一起,極大提升了應(yīng)用監(jiān)測(cè)和檢查,尤其是在擴(kuò)容、機(jī)器失敗或者運(yùn)維導(dǎo)致應(yīng)用實(shí)例遷移的時(shí)候。
容器能夠注冊(cè)通用的API使得管理系統(tǒng)和應(yīng)用之間盡管互相不甚明了對(duì)方的實(shí)現(xiàn)細(xì)節(jié),但也能信息流通。在Borg里,這個(gè)API是一系列HTTP終端銜接到每一個(gè)容器上。舉例來(lái)說(shuō),/healthz終端對(duì)編排器報(bào)告應(yīng)用的健康狀態(tài)。當(dāng)一個(gè)不健康的應(yīng)用被發(fā)現(xiàn),它就被自動(dòng)終止和重啟。這種自我修復(fù)對(duì)可靠的分布式系統(tǒng)而言是一個(gè)關(guān)鍵的磚頭塊。(Kubernetes提供了類(lèi)似的功能;健康檢查使用了一個(gè)用戶指定的HTTP終端或者跑在容器里的exec命令。)
容器也能提供其他面向應(yīng)用的監(jiān)測(cè):舉例來(lái)說(shuō),Linux內(nèi)核cgroups提供關(guān)于應(yīng)用的資源利用數(shù)據(jù),這些可以和先前提到的由HTTP API導(dǎo)出的客戶metrics一起被延伸。這些數(shù)據(jù)能夠?qū)崿F(xiàn)例如自動(dòng)擴(kuò)容或cAdvisor這樣一般工具的開(kāi)發(fā),這些開(kāi)發(fā)記錄或者使用這些metrics,不需要理解每個(gè)應(yīng)用的細(xì)節(jié)。因?yàn)槿萜骶褪菓?yīng)用,就不再需要從在一個(gè)物理機(jī)或者虛擬機(jī)上跑的多個(gè)應(yīng)用來(lái)多路分配信號(hào)。這個(gè)更簡(jiǎn)單、更穩(wěn)定一些,而且也允許對(duì)metrics和日志進(jìn)行更細(xì)粒度的報(bào)告和控制。拿這個(gè)跟需要ssh到一臺(tái)機(jī)器去跑top去比一下。盡管對(duì)開(kāi)發(fā)者來(lái)說(shuō),ssh到他們的容器是可能的,但程序員很少會(huì)需要這么去做。
監(jiān)測(cè),只是一個(gè)例子。面向應(yīng)用的這個(gè)變化在管理底層上是有連帶效果的。我們的負(fù)載均衡器并不平衡機(jī)器間的傳輸,它們是針對(duì)應(yīng)用實(shí)例來(lái)平衡。日志也是根據(jù)應(yīng)用,而非機(jī)器,因此它們可以很容易的被收集以及在實(shí)例之間集合,而不受到多個(gè)應(yīng)用或者操作系統(tǒng)的影響。我們可以查探到應(yīng)用失敗,更容易對(duì)這些失敗的原因來(lái)歸類(lèi),而不需要對(duì)它們進(jìn)行機(jī)器層面信號(hào)的分離。
最后,盡管到目前為止,我們對(duì)應(yīng)用的關(guān)注和對(duì)容器的關(guān)注是1:1,但在現(xiàn)實(shí)中我們使用在同一臺(tái)機(jī)器上聯(lián)動(dòng)的容器:最外面的容器提供一個(gè)資源池,里面的這些容器提供部署隔離。在Borg,最外面那層容器被稱(chēng)為資源調(diào)配器(或者alloc),在Kubernetes里,被稱(chēng)為pod。Borg也允許最頂端的應(yīng)用容器跑在alloc的外面,這個(gè)帶來(lái)了很多不方便,所以Kubernetes把這些規(guī)范化并且總是在一個(gè)頂端的pod里來(lái)跑應(yīng)用容器,即便這個(gè)pod只有單一的一個(gè)容器。
一個(gè)普遍的使用樣式,是用一個(gè)pod來(lái)裝一個(gè)復(fù)雜應(yīng)用的實(shí)例。應(yīng)用的主要部分在它其中一個(gè)容器(child containers)里,其他容器跑著支持功能,例如日志處理。跟把這些功能組合到一個(gè)單一的二進(jìn)制相比,這使得開(kāi)發(fā)團(tuán)隊(duì)開(kāi)發(fā)不同功能的部件容易很多,也提高了穩(wěn)定性(即便主體應(yīng)用有新的東西進(jìn)來(lái),日志發(fā)送依然可以繼續(xù)運(yùn)行)和可編輯性。
編排只是開(kāi)始,不是結(jié)束原始的Borg系統(tǒng)可以在共享的機(jī)器上跑不同的工作負(fù)荷來(lái)提高資源利用率。但在Borg內(nèi)支持服務(wù)的迅速進(jìn)化顯示,容器管理的本質(zhì)只是開(kāi)發(fā)和管理可靠的分布式系統(tǒng)的開(kāi)始,很多不同的系統(tǒng)在Borg上和周邊被開(kāi)發(fā),用來(lái)提高Borg所提供的基本的容器管理服務(wù)。下面這個(gè)不完整的列表給出了這些服務(wù)大概的一個(gè)范圍和多樣性:
命名和服務(wù)發(fā)現(xiàn)(Borg Name Service或BNS);
Master election(用Chubby);
面向應(yīng)用的負(fù)載均衡;
橫向(實(shí)例數(shù)量)和縱向(實(shí)例尺寸)的自動(dòng)擴(kuò)容;
發(fā)布工具,用來(lái)管理新二進(jìn)制和配置數(shù)據(jù);
工作流程工具(例如允許跑分析多任務(wù)的pipelines在不同階段有互相環(huán)境依賴(lài));
監(jiān)測(cè)工具用來(lái)收集關(guān)于容器的信息,集合這些信息、發(fā)布到dashboard上,或者用它來(lái)激發(fā)預(yù)警。
構(gòu)建這些服務(wù)是用來(lái)解決應(yīng)用開(kāi)發(fā)團(tuán)隊(duì)所經(jīng)歷的問(wèn)題。成功的服務(wù)被廣泛采用,那其他開(kāi)發(fā)者就受益。不幸的是,這些工具常常選一些怪癖的API,conventions(比如文件位置)和Borg的深度結(jié)合。一個(gè)副作用就是增加了Borg生態(tài)系統(tǒng)部署應(yīng)用的復(fù)雜性。
Kubernetes企圖通過(guò)對(duì)API采用一種一致的方法來(lái)避免這種增加的復(fù)雜性。比如說(shuō),每一個(gè)Kubernetes的對(duì)象在它的描述里有三個(gè)基本的屬性:對(duì)象的metadata、spec和狀態(tài)(status)。
對(duì)象的metadata對(duì)系統(tǒng)中的所有對(duì)象都是一樣的,它包含了例如對(duì)象名稱(chēng)、UID(特殊標(biāo)示)、一個(gè)對(duì)象的版本號(hào)碼(為了樂(lè)觀的進(jìn)程控制)以及標(biāo)簽(key-value對(duì),見(jiàn)下面描述)。Spec和status的內(nèi)容根據(jù)不同的對(duì)象類(lèi)型會(huì)不同,但它們的概念是一樣的:spec時(shí)用來(lái)描述對(duì)象的理想狀態(tài),而status提供了該對(duì)象目前當(dāng)下的只讀信息。
這種統(tǒng)一的API帶來(lái)很多好處,可以讓我們更容易的了解系統(tǒng),因?yàn)橄到y(tǒng)中所有對(duì)象都有類(lèi)似的信息。另外,統(tǒng)一的API可以更容易地編寫(xiě)通用的工具來(lái)作用于所有對(duì)象,這樣反過(guò)來(lái)也讓使用者感覺(jué)更為連貫。通過(guò)對(duì)Borg和Omega的總結(jié),Kubernetes建立在一整套可自由拆裝的部件之上,可以由開(kāi)發(fā)者任意延展。一個(gè)有共識(shí)的API和對(duì)象metadata結(jié)構(gòu)可以使這個(gè)過(guò)程更為簡(jiǎn)單。
一致性還可以通過(guò)在Kubernetes API內(nèi)解構(gòu)來(lái)完成。在API組建之間考慮進(jìn)行一些分離意味著在更高層的服務(wù)上需要共享一些基本的構(gòu)建組件。一個(gè)很好的例子是在Kubernetes的RC(replication controller)和它水平自動(dòng)擴(kuò)容系統(tǒng)之間的分離。一個(gè)RC保證了對(duì)某個(gè)角色(比如“前端”)理想的pod數(shù)量的存在。自動(dòng)擴(kuò)容器,反過(guò)來(lái),需要依賴(lài)這個(gè)能力并且簡(jiǎn)單地調(diào)整理想的pod數(shù)量,不需要擔(dān)心pod如何生成和刪除。自動(dòng)擴(kuò)容器的實(shí)現(xiàn)能夠把精力集中在需求和使用的預(yù)測(cè),忽略如何實(shí)現(xiàn)這些決定的細(xì)節(jié)。
分離保證了多個(gè)關(guān)聯(lián)但不同的組件共享一個(gè)相似的外表和感覺(jué)。舉個(gè)例子,Kubernetes有三個(gè)不同的pod副本模式:
ReplicationController:永遠(yuǎn)在運(yùn)行的容器副本(比如web服務(wù)器);
DaemonSet:確保在集群里的每個(gè)節(jié)點(diǎn)上有一個(gè)多帶帶的實(shí)例(例如日志代理);
Job:一個(gè)知道如何從開(kāi)始到結(jié)束運(yùn)行一個(gè)(可能是并行的)批處理任務(wù)的run-to-completion的控制器。
盡管在規(guī)則上有區(qū)別,所有這三個(gè)控制器都依賴(lài)共同的pod對(duì)象來(lái)制定它們想要運(yùn)行在上面的容器。
一致性也可以通過(guò)不同Kubernetes組件上共同的設(shè)計(jì)形式來(lái)達(dá)到。在Borg、Omega和Kubernetes上用來(lái)提高系統(tǒng)彈性,有一個(gè)概念:“reconciliation controller loop”(清理控制器循環(huán)),這個(gè)概念是來(lái)比較一個(gè)理想的狀態(tài)(比如需要多少個(gè)pod才能來(lái)達(dá)到一個(gè)標(biāo)簽選擇的query,即 label-selector query),和相對(duì)于觀測(cè)到的狀態(tài)(可以發(fā)現(xiàn)的這樣的pod數(shù)量)來(lái)進(jìn)行比較,然后采取行動(dòng)去把這兩個(gè)狀態(tài)做到一致。
需要避免的事情在研發(fā)這些系統(tǒng)的時(shí)候,我們也學(xué)到了許多關(guān)于哪些事情不該做,哪些事情值得去做的經(jīng)驗(yàn)。我們把其中的一些寫(xiě)出來(lái),期望后來(lái)者不再重蹈覆轍,而是集中精力去解決新問(wèn)題
別讓容器系統(tǒng)來(lái)管理port端口所有跑在Borg機(jī)器上的容器都共享主機(jī)的IP地址,所以Borg給容器分發(fā)了獨(dú)特的port端口作為調(diào)度過(guò)程的一部分。一個(gè)容器當(dāng)它移到一個(gè)新的機(jī)器上(有時(shí)候)在同樣的機(jī)器上重啟的話,會(huì)拿到一個(gè)新的端口號(hào)碼。這意味著傳統(tǒng)的例如像DNS(Domain Name System)網(wǎng)絡(luò)服務(wù)需要被home-brew版本取代;因?yàn)榉?wù)的客戶不會(huì)先驗(yàn)地知道給到服務(wù)的port端口,需要被告知;port端口號(hào)碼不能被嵌在URL里,就需要以名字為基礎(chǔ)的再次導(dǎo)向(redirection)機(jī)制;而且依賴(lài)于簡(jiǎn)單的IP地址的工具需要被重寫(xiě)來(lái)搞定IP:端口對(duì)的形式(port pairs)。
從我們?cè)贐org的經(jīng)驗(yàn)來(lái)看,我們決定Kubernetes可以來(lái)給每個(gè)pod制定IP地址,這樣把網(wǎng)絡(luò)身份(即IP地址)和應(yīng)用身份能統(tǒng)一起來(lái)。這會(huì)使得在Kubernetes上跑現(xiàn)成的軟件容易的多:應(yīng)用可以隨意使用靜態(tài)已知的端口(比如80作為HTTP端口),已經(jīng)存在的、熟悉的工具可以被用來(lái)做網(wǎng)絡(luò)分段、帶寬調(diào)節(jié)管理。所有流行的云平臺(tái)提供網(wǎng)絡(luò)的基礎(chǔ)層,能夠有每個(gè)pod的IP,在裸機(jī)上,可以使用SDN覆蓋層或者配置L3路由來(lái)管理每個(gè)機(jī)器上的多個(gè)IP.
別僅僅只是給容器編號(hào):給它們打標(biāo)簽如果你讓用戶很容易地創(chuàng)建容器,他們會(huì)傾向于創(chuàng)建很多,那么很快就會(huì)需要一種方式來(lái)管理和組織它們。Borg對(duì)于群組的相同的task提供了jobs(對(duì)于容器而言任務(wù)的名稱(chēng))。一個(gè)job是一個(gè)壓縮的容器(vector)裝了一個(gè)或多個(gè)相同的task,從0開(kāi)始計(jì)數(shù)。這提供了許多能量,而且很簡(jiǎn)單直白,但時(shí)間長(zhǎng)了我們又會(huì)后悔它過(guò)于死板。比如說(shuō),當(dāng)一個(gè)task死掉了,需要在另一臺(tái)機(jī)器上被重新啟動(dòng),在task這個(gè)vector上的相同的slot就要雙倍的工作:既要指認(rèn)這個(gè)新的備份,同時(shí)還要指向舊的那個(gè),萬(wàn)一可能需要做debug。當(dāng)task出現(xiàn)在vector的當(dāng)中,那vector就有洞。因此vector很難去支持在Borg的一層上跨越多個(gè)集群的job.同時(shí),也有潛在的、不期而遇的在Borg更新job的語(yǔ)意上(典型的是在做滾動(dòng)升級(jí)的時(shí)候按照index標(biāo)記來(lái)重啟)和應(yīng)用使用的task index標(biāo)記(比如做一些sharding活著跨task的數(shù)據(jù)的分區(qū))的互動(dòng):如果應(yīng)用使用基于task index的range sharding,那么Borg的重啟政策會(huì)導(dǎo)致拿不到數(shù)據(jù),因?yàn)樗鼤?huì)拉掉附近的任務(wù)。Borg也沒(méi)有簡(jiǎn)單的辦法去job里面增加跟應(yīng)用有關(guān)的metadata,比如角色屬性(比如“前端”)或者展示的狀態(tài)(比如是canary),所以人們要把這些信息寫(xiě)到j(luò)ob名稱(chēng)里,這樣他們可以用常規(guī)表達(dá)式(regular expression)來(lái)解析。
相比之下,Kubernetes主要使用標(biāo)簽(labels)來(lái)識(shí)別成組的容器。一個(gè)標(biāo)簽是一對(duì)key/value組,包含著容器信息可以用來(lái)識(shí)別對(duì)象。一個(gè)pod可能有這樣的標(biāo)簽:role=frontend 和 stage=production,表明這個(gè)容器服務(wù)于前端生產(chǎn)。標(biāo)簽可以動(dòng)態(tài)地被自動(dòng)工具、用戶來(lái)添加、移除和修改,也可以被其他不同的團(tuán)隊(duì)獨(dú)立地來(lái)管理他們自己的標(biāo)簽。成組的對(duì)象,可以由label selectors來(lái)定義(比如 stage==production && role==frontend)。這些組(set)可以重疊,而且一個(gè)對(duì)象可以在多個(gè)的組(set)里,因此標(biāo)簽本身要比明確的對(duì)象列表或簡(jiǎn)單靜態(tài)的屬性更靈活。因?yàn)橐粋€(gè)組(set)是由一個(gè)動(dòng)態(tài)隊(duì)列來(lái)定義的,一個(gè)新的組可以在任何時(shí)候被生成。在Kubernetes里label selectors是grouping(成組)的機(jī)制,來(lái)定義跨越多個(gè)實(shí)體的管理操作的范圍。
即便在那樣的環(huán)境里知道在一個(gè)set里的一個(gè)task的身份是很有幫助的(比如說(shuō)靜態(tài)角色的分配和工作分區(qū)或分片),適當(dāng)?shù)拿總€(gè)pod有標(biāo)簽可以被用來(lái)再次產(chǎn)生任務(wù)標(biāo)示的效果,盡管這個(gè)是應(yīng)用的責(zé)任(或者一些其他在Kubernetes外部的管理系統(tǒng)的責(zé)任)來(lái)提供這樣的標(biāo)簽。標(biāo)簽和標(biāo)簽選擇器提供了一個(gè)對(duì)這兩者的最好的通用機(jī)制。
對(duì)所有權(quán)要謹(jǐn)慎在Borg里,tasks并不是獨(dú)立于jobs存在的。生成一個(gè)job,也會(huì)生成它的task,那些tasks永遠(yuǎn)和特定的job是有關(guān)聯(lián)的,如果刪除job,也會(huì)刪除task。這樣很方便,但也會(huì)有一個(gè)主要的缺點(diǎn):因?yàn)橹挥幸粋€(gè)成組的機(jī)制,需要來(lái)解決所有出現(xiàn)的情況。舉例來(lái)說(shuō),一個(gè)job需要存儲(chǔ)參數(shù),這些參數(shù)或者是對(duì)應(yīng)服務(wù)(service)或者是對(duì)應(yīng)批量工作(batch job)但不會(huì)是兩者同時(shí),而且用戶必須要寫(xiě)出workarounds當(dāng)job的抽象無(wú)法來(lái)解決某個(gè)情況的時(shí)候(比如一個(gè)DaemonSet對(duì)這個(gè)集群里的所有節(jié)點(diǎn)都去復(fù)制一個(gè)簡(jiǎn)單的pod)。
在Kubernetes里,pod生命周期的管理組件例如RC決定了哪個(gè)pod它們有責(zé)任要用標(biāo)簽選擇器,因此多個(gè)控制器都可能會(huì)認(rèn)為它們自己對(duì)于一個(gè)單一的pod有管轄權(quán)。通過(guò)適當(dāng)?shù)呐渲眠x擇來(lái)預(yù)防這樣的沖突就非常重要。但是標(biāo)簽的彈性也有額外的好處,比如說(shuō),控制器和pod的分離意味著可以孤立和啟用一些容器??紤]到一個(gè)負(fù)載均衡的服務(wù)使用一個(gè)標(biāo)簽選擇器去標(biāo)示一組pod去發(fā)送請(qǐng)求。如果這些pod中的一個(gè)行為異常,那這個(gè)pod的被Kubernetes服務(wù)負(fù)載均衡器識(shí)別出來(lái)的標(biāo)簽會(huì)被刪除、這個(gè)pod被隔離不再進(jìn)行服務(wù)。這個(gè)pod不再服務(wù)接受請(qǐng)求,但它會(huì)保持線上的狀態(tài),在原處可以被debug.同時(shí),管理pod的RC自動(dòng)實(shí)現(xiàn)服務(wù),為有問(wèn)題的pod創(chuàng)建一個(gè)復(fù)制的pod.
不要暴露raw stateBorg、Omega和Kubernetes之間一個(gè)關(guān)鍵的差別在于它們的API構(gòu)架。Borgmaster是一個(gè)單一的組件,它知道每一個(gè)API運(yùn)作的語(yǔ)義。它包含了諸如關(guān)于jobs、tasks和機(jī)器的狀態(tài)機(jī)器的集群管理的邏輯;它跑基于Paxos的復(fù)制存儲(chǔ)系統(tǒng)用來(lái)記錄master的狀態(tài)。反觀Omega,Omega除了存儲(chǔ)之外沒(méi)有集中的部件,存儲(chǔ)也是簡(jiǎn)單地匯集了被動(dòng)的狀態(tài)信息以及加強(qiáng)樂(lè)觀的并行進(jìn)程控制:所有的邏輯和語(yǔ)義都被推進(jìn)存儲(chǔ)的client里,直接讀寫(xiě)存儲(chǔ)的內(nèi)容。在實(shí)踐中,每一個(gè)Omega的部件為了存儲(chǔ)使用同樣的客戶端library,來(lái)打包或者解體數(shù)據(jù)結(jié)構(gòu)、重新嘗試活著加強(qiáng)語(yǔ)義的一致性。
Kubernetes選擇了一個(gè)中間地提供了像Omega部件結(jié)構(gòu)的彈性和可擴(kuò)容性,同時(shí)還能加強(qiáng)系統(tǒng)層面的無(wú)變化、政策和數(shù)據(jù)傳輸。它通過(guò)強(qiáng)制所有存儲(chǔ)接觸必須通過(guò)一個(gè)中央的API服務(wù)器來(lái)隱藏存儲(chǔ)的實(shí)現(xiàn)細(xì)節(jié)和給對(duì)象驗(yàn)證、版本控制提供服務(wù)來(lái)做到這些。在Omega里,client的部件互相之間是分離的,可以進(jìn)化或者多帶帶被替換(這對(duì)開(kāi)源環(huán)境而言尤其重要),但中央化對(duì)加強(qiáng)共同語(yǔ)義、不變性和政策會(huì)容易很多。
一些開(kāi)放性的難題有了八年的容器管理經(jīng)驗(yàn),我們感覺(jué)依然還有大量的問(wèn)題我們沒(méi)有很好的解決方案。這個(gè)部分描述了一些我們感到特別棘手的問(wèn)題,作為拋磚引玉吧。
配置在所有我們面對(duì)的問(wèn)題中,最多的心思和筆墨涉及到的都是關(guān)于管理配置,即一整套的提供給應(yīng)用的配置,而非硬生生寫(xiě)進(jìn)應(yīng)用里去。我們完全可以把整篇文章都拿來(lái)寫(xiě)這個(gè)主題(可能都說(shuō)不完)。下面這些是一些我們想要強(qiáng)調(diào)的內(nèi)容。
首先,應(yīng)用配置變成了一個(gè)關(guān)聯(lián)一切的抓手,來(lái)實(shí)現(xiàn)所有的東西,所有這些容器管理系統(tǒng)(尚且)不做的事情,包括:
樣板化簡(jiǎn)約(比如把tast重啟的政策調(diào)整到相適應(yīng)的負(fù)載工作量,例如服務(wù)或者批處理工作);
調(diào)整和驗(yàn)證應(yīng)用參數(shù)以及command-line參數(shù);
實(shí)現(xiàn)例如打包鏡像管理的缺失API抽象的替代解決方法;
應(yīng)用配置模版的library;
發(fā)布管理工具;
鏡像版本說(shuō)明。
為了解決這些要求、配置管理系統(tǒng)趨向于發(fā)明一個(gè)domain-specific的配置語(yǔ)言,最終具有圖靈完備性,起源于希望能夠在配置的數(shù)據(jù)里進(jìn)行計(jì)算(比如對(duì)一個(gè)服務(wù)調(diào)整給它的內(nèi)存,作為在一個(gè)服務(wù)里進(jìn)行分區(qū)的功能)。結(jié)果就產(chǎn)生一個(gè)難以理解的“配置是代碼”,大家都通過(guò)不在應(yīng)用當(dāng)中hardcode參數(shù)來(lái)盡量避免的這種情況。它并沒(méi)有減少操作上的復(fù)雜性或者使得配置更容易debug或改變,它只是把計(jì)算從一個(gè)真正的編程語(yǔ)言挪到了一個(gè)特殊領(lǐng)域。
我們相信最有效的方法是去接受這個(gè)需求,擁抱無(wú)所不在的程序配置和在計(jì)算和數(shù)據(jù)之間保持一個(gè)清楚的界線。代表數(shù)據(jù)的語(yǔ)言應(yīng)該是簡(jiǎn)單的、僅數(shù)據(jù)格式的,比如像JSON或者YAML,對(duì)這種數(shù)據(jù)的程序化修改應(yīng)該在一個(gè)真實(shí)的編程語(yǔ)言里,有被很好理解的語(yǔ)義和工具。有趣的是,同樣的在計(jì)算和數(shù)據(jù)之間的分離在前端開(kāi)發(fā)的不同領(lǐng)域是雷同的,比如像Angular在markup(數(shù)據(jù))和JavaScript(計(jì)算)之間是有清晰的劃分的。
依賴(lài)條件的管理起一個(gè)服務(wù)往往也意味著提供一系列相關(guān)的服務(wù)(監(jiān)控、存儲(chǔ)、CI/CD等等)。如果一個(gè)應(yīng)用對(duì)其他應(yīng)用有依賴(lài),其他這些依賴(lài)條件(和任何它們可能有涉及的依賴(lài)條件)能夠被集群系統(tǒng)自動(dòng)管理,是不是很好呢?
更麻煩的是,對(duì)依賴(lài)條件的實(shí)例化很少會(huì)像起一個(gè)新的備份這么簡(jiǎn)單,比如說(shuō),它可能會(huì)需要對(duì)現(xiàn)有的服務(wù)注冊(cè)一個(gè)新的消費(fèi)者(比如Bigtable as a service)然后通過(guò)這些間接的依賴(lài)環(huán)境來(lái)傳遞認(rèn)證、授權(quán)以及賬號(hào)信息。然而,基本上沒(méi)有系統(tǒng)會(huì)抓、保持或者透露這些依賴(lài)信息,所以在底層自動(dòng)化這些即便是非常常見(jiàn)的情況都是近乎不可能的。起來(lái)一個(gè)新的應(yīng)用對(duì)用戶來(lái)說(shuō)就很復(fù)雜,對(duì)開(kāi)發(fā)者而言來(lái)建新的服務(wù)就變難,經(jīng)常導(dǎo)致一些最佳實(shí)踐無(wú)法進(jìn)行,影響服務(wù)的可靠性。
一個(gè)標(biāo)準(zhǔn)的問(wèn)題是:如果是手動(dòng)更新,很難保持依賴(lài)信息的及時(shí)更新。而且同時(shí),能自動(dòng)地(比如跟蹤access)決定它的這種企圖也無(wú)法掌握需要了解結(jié)果的語(yǔ)義信息。(比如是否這個(gè)acess要給那個(gè)實(shí)例?或者任何一個(gè)實(shí)例就足夠了?)一個(gè)能夠改進(jìn)的可能是要求應(yīng)用枚舉它所依賴(lài)的服務(wù),然后讓底層拒絕對(duì)其他服務(wù)的接觸(我們?cè)谖覀兊腷uild system里對(duì)compiler imports這么做過(guò))。這個(gè)動(dòng)機(jī)是讓底層做有用的事情,比如自動(dòng)的setup、認(rèn)證和連接。
不幸的是,我們所觀察到的系統(tǒng)在表達(dá)、分析和使用系統(tǒng)依賴(lài)這方面的復(fù)雜性都太高,所以它們還沒(méi)有被夾到一個(gè)主流的容器管理系統(tǒng)里。我們依然希望Kubernetes可能可以成為一個(gè)這樣的平臺(tái),在這個(gè)平臺(tái)上有這樣的工具,但這么做是一個(gè)很大的挑戰(zhàn)。
結(jié)語(yǔ)十多年搭建容器管理系統(tǒng)的經(jīng)驗(yàn)教會(huì)了我們很多。而且我們把很多已有的經(jīng)驗(yàn)融入進(jìn)了Kubernetes,谷歌最近的這個(gè)容器管理系統(tǒng)。它的目標(biāo)是基于容器的能力來(lái)提供編程生產(chǎn)力方面的極大收獲,簡(jiǎn)化人工和自動(dòng)化系統(tǒng)管理。我們希望你會(huì)來(lái)加入我們來(lái)延伸和提高這個(gè)項(xiàng)目。
(如果需要轉(zhuǎn)載,請(qǐng)聯(lián)系我們哦,尊重知識(shí)產(chǎn)權(quán)人人有責(zé);)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/32448.html
摘要:這里我想從我在谷歌內(nèi)部使用容器,并基于容器研發(fā)大規(guī)模生產(chǎn)平臺(tái)的經(jīng)驗(yàn)中談?wù)劕F(xiàn)有和谷歌容器環(huán)境的差別,并通過(guò)的實(shí)際案例落地經(jīng)驗(yàn)總結(jié)下自身所帶來(lái)的一些謊言和誤區(qū)。 我與容器的緣分起源于我在 Google 內(nèi)部研發(fā)容器集群管理系: Cluster Management。谷歌內(nèi)部一切皆容器,搜索、視頻、大數(shù)據(jù)、內(nèi)部工具等核心業(yè)務(wù)都以容器的方式運(yùn)行在容器編排系統(tǒng) Borg 上。2014年,隨著公司...
摘要:因此,也是運(yùn)行谷歌的一種方式,所以本質(zhì)上來(lái)說(shuō),你注冊(cè)就是為了能夠訪問(wèn)一組指定的設(shè)計(jì)原則,這組原則會(huì)讓你的應(yīng)用程序有效運(yùn)作,像谷歌那樣輕松建立和管理您的應(yīng)用程序。 今天我們來(lái)聊聊,但不從技術(shù)細(xì)節(jié)角度,聊為什么容器、Kubernetes是值得使用和整合到你的項(xiàng)目堆棧中的。我們的目標(biāo)是給你們提供一個(gè)關(guān)于應(yīng)該如何思考你的底層構(gòu)架以及將它可視化問(wèn)題,從這個(gè)角度來(lái)談我們的話題:Kubernetes...
摘要:然而在中國(guó)和美國(guó),不同的語(yǔ)言和文化共通的卻是對(duì)女工程師的偏見(jiàn)和挑戰(zhàn)。因?yàn)楣雀枋且患壹夹g(shù)驅(qū)動(dòng)的公司,所以我可以做很多決定。我認(rèn)為這是一個(gè)傳遞途徑的問(wèn)題,最起碼在美國(guó)是這樣。谷歌本身是很重視這一點(diǎn)的。 非商業(yè)轉(zhuǎn)載請(qǐng)注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/203525 Dawn Chen是谷歌云平臺(tái)軟件工程師,目前負(fù)責(zé)Kub...
摘要:然而在中國(guó)和美國(guó),不同的語(yǔ)言和文化共通的卻是對(duì)女工程師的偏見(jiàn)和挑戰(zhàn)。因?yàn)楣雀枋且患壹夹g(shù)驅(qū)動(dòng)的公司,所以我可以做很多決定。我認(rèn)為這是一個(gè)傳遞途徑的問(wèn)題,最起碼在美國(guó)是這樣。谷歌本身是很重視這一點(diǎn)的。 非商業(yè)轉(zhuǎn)載請(qǐng)注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/203525 Dawn Chen是谷歌云平臺(tái)軟件工程師,目前負(fù)責(zé)Kub...
摘要:然而在中國(guó)和美國(guó),不同的語(yǔ)言和文化共通的卻是對(duì)女工程師的偏見(jiàn)和挑戰(zhàn)。因?yàn)楣雀枋且患壹夹g(shù)驅(qū)動(dòng)的公司,所以我可以做很多決定。我認(rèn)為這是一個(gè)傳遞途徑的問(wèn)題,最起碼在美國(guó)是這樣。谷歌本身是很重視這一點(diǎn)的。 非商業(yè)轉(zhuǎn)載請(qǐng)注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/203525 Dawn Chen是谷歌云平臺(tái)軟件工程師,目前負(fù)責(zé)Kub...
閱讀 2652·2021-11-11 16:55
閱讀 1288·2021-09-22 15:25
閱讀 1806·2019-08-29 16:26
閱讀 988·2019-08-29 13:21
閱讀 2315·2019-08-23 16:19
閱讀 2803·2019-08-23 15:10
閱讀 784·2019-08-23 14:24
閱讀 1857·2019-08-23 13:48