作者簡(jiǎn)介
Darren Shepherd把沼,Rancher Labs聯(lián)合創(chuàng)始人及首席架構(gòu)師。在加入Rancher之前吁伺,Darren是Citrix的高級(jí)首席工程師饮睬,他在那里從事CloudStack、OpenStack篮奄、Docker的工作捆愁,并構(gòu)建下一代基礎(chǔ)設(shè)施編排技術(shù)。在加入Citrix之前窟却,Darren曾在GoDaddy工作昼丑,他設(shè)計(jì)并領(lǐng)導(dǎo)一個(gè)團(tuán)隊(duì)實(shí)施公有和私有IaaS云。
本文轉(zhuǎn)自Rancher Labs
2020年年初夸赫,Rancher開(kāi)源了海量集群管理項(xiàng)目Fleet菩帝,為大量的Kubernetes集群提供集中的GitOps式管理。Fleet最重要的目標(biāo)是能夠管理100萬(wàn)個(gè)分布于不同地理位置的集群憔足。當(dāng)我們?cè)O(shè)計(jì)Fleet架構(gòu)時(shí)胁附,我們希望使用標(biāo)準(zhǔn)的Kubernetes controller架構(gòu)。這意味著我們可以擴(kuò)展Kubernetes的數(shù)量比之前要多很多滓彰。在本文中控妻,我將介紹Fleet的架構(gòu)、我們用于測(cè)試擴(kuò)展規(guī)模的方法和我們的發(fā)現(xiàn)揭绑。
為什么是100萬(wàn)個(gè)集群弓候?
隨著K3s用戶量爆發(fā)式增長(zhǎng)(目前Github Star已經(jīng)超過(guò)15,000),邊緣Kubernetes也開(kāi)始迅猛發(fā)展他匪。一些企業(yè)已經(jīng)采用了邊緣部署模型菇存,其中每個(gè)設(shè)備都是單節(jié)點(diǎn)集群“蠲郏或者你可能會(huì)看到使用3個(gè)節(jié)點(diǎn)的集群來(lái)提供高可用性(HA)依鸥。關(guān)鍵點(diǎn)在于我們需要處理的是大量小型集群,而不是一個(gè)有很多節(jié)點(diǎn)的大型集群〉可颍現(xiàn)如今贱迟,幾乎任何地方的工程師都在使用Linux,他們都希望使用Kubernetes來(lái)管理工作負(fù)載絮供。雖然大多數(shù)K3s的邊緣部署少于10,000個(gè)節(jié)點(diǎn)衣吠,但達(dá)到100萬(wàn)個(gè)節(jié)點(diǎn)并非不可能。而Fleet將滿足你的規(guī)模擴(kuò)展要求壤靶。
Fleet架構(gòu)
Fleet架構(gòu)的關(guān)鍵部分如下:
Fleet使用兩階段pull方法
Fleet是一組由標(biāo)準(zhǔn)K8S API交互驅(qū)動(dòng)的K8S Controller
Fleet agent不需要一直保持連接
Fleet agent本身是另一組Kubernetes controller
要從git中進(jìn)行部署缚俏,F(xiàn)leet Manager首先要復(fù)制并存儲(chǔ)git中的內(nèi)容,然后Fleet manager決定需要使用git中的內(nèi)容更新哪個(gè)集群,并創(chuàng)建部署記錄供agent讀取忧换。當(dāng)agent可以讀取時(shí)恬惯,agent將check in以讀取部署集群,部署新的資源并報(bào)告狀態(tài)包雀。
擴(kuò)展規(guī)模測(cè)試方法
我們使用兩種方法來(lái)模擬100萬(wàn)個(gè)集群宿崭。首先,我們部署了一組大型VM(m5ad.24xlarge - 384 GiB RAM)才写。每個(gè)VM使用k3d運(yùn)行10個(gè)K3s集群。然后這10個(gè)集群每個(gè)都運(yùn)行750個(gè)agent奖蔓,每個(gè)agent都代表著一個(gè)下游的集群赞草。總的來(lái)說(shuō)吆鹤,每個(gè)VM模擬7500個(gè)集群厨疙。平均來(lái)看,部署一個(gè)VM疑务、在Fleet注冊(cè)所有集群并達(dá)到穩(wěn)定狀態(tài)大約需要花費(fèi)40分鐘沾凄。在兩天的時(shí)間里,我們以這種方式啟動(dòng)虛擬機(jī)知允,直到達(dá)到10萬(wàn)個(gè)集群撒蟀。在最初的10萬(wàn)個(gè)集群中,我們發(fā)現(xiàn)了大部分的擴(kuò)展問(wèn)題温鸽。在解決了這些問(wèn)題之后保屯,擴(kuò)展變得相當(dāng)可預(yù)測(cè)。以這一速度涤垫,模擬剩下的90萬(wàn)個(gè)集群將會(huì)花費(fèi)很長(zhǎng)的時(shí)間以及相當(dāng)可觀的資金姑尺。
然后,我們采用第二種方法:運(yùn)行一個(gè)模擬器蝠猬,它可以執(zhí)行100萬(wàn)個(gè)集群會(huì)進(jìn)行的所有API調(diào)用切蟋,而不需要下游的Kubernetes集群或部署Kubernetes資源。取而代之的是榆芦,模擬器進(jìn)行API調(diào)用以注冊(cè)新集群柄粹、發(fā)現(xiàn)新部署并報(bào)告它們的成功狀態(tài)。使用這種方法歧杏,我們?cè)谝惶靸?nèi)實(shí)現(xiàn)了從0到100萬(wàn)個(gè)模擬集群镰惦。
Fleet manager是一個(gè)運(yùn)行在Kubernetes集群上的controller,運(yùn)行在3個(gè)大型虛擬機(jī)(m5ad.24xlarge - 384 GiB RAM)和一個(gè)RDS(db.m5.24xlarge)實(shí)例上犬绒。實(shí)際上旺入,我們使用K3s來(lái)運(yùn)行Fleet Manager集群。我們這樣做是因?yàn)镵ine已經(jīng)在其中集成了。我將在后面解釋什么是Kine以及為什么使用它茵瘾。盡管K3s針對(duì)的是小規(guī)模的集群礼华,但它可能是最容易大規(guī)模運(yùn)行的Kubernetes發(fā)行版,我們使用它是因?yàn)槠浜?jiǎn)單易用拗秘。值得注意的是圣絮,在EKS這樣的托管提供商上,我們無(wú)法大規(guī)模運(yùn)行Fleet雕旨,稍后我會(huì)解釋這一點(diǎn)扮匠。
發(fā)現(xiàn)1:調(diào)整服務(wù)賬戶和費(fèi)率限制
我們遇到的第一個(gè)問(wèn)題完全出乎意料。當(dāng)一個(gè)Fleet agent注冊(cè)到Fleet Manager時(shí)凡涩,它會(huì)使用一個(gè)臨時(shí)的集群注冊(cè)令牌(token)棒搜。然后,該令牌被用來(lái)為該集群/agent創(chuàng)建新的身份和憑證活箕。集群注冊(cè)令牌和該agent的憑證都是服務(wù)賬戶力麸。我們注冊(cè)集群的速度受到controller-manager為服務(wù)賬戶創(chuàng)建令牌的速度的限制。經(jīng)過(guò)研究育韩,我們發(fā)現(xiàn)我們可以修改controller-manager的默認(rèn)設(shè)置來(lái)提高我們創(chuàng)建服務(wù)賬戶的速度(-concurrent-serviceaccount-token-syncs=100)和每秒API請(qǐng)求的總體數(shù)量(-kube-api-qps=10000)克蚂。
發(fā)現(xiàn)2:etcd不能在此規(guī)模下運(yùn)行
Fleet是作為Kubernetes Controller編寫(xiě)的。因此筋讨,將Fleet擴(kuò)展到100萬(wàn)個(gè)集群意味著要在Kubernetes中管理數(shù)千萬(wàn)個(gè)對(duì)象埃叭。正如我們所了解的,etcd并沒(méi)有能力管理這么大的數(shù)據(jù)量版仔。Etcd的主要空間有8GB的限制游盲,默認(rèn)設(shè)置為2GB。關(guān)鍵空間包括當(dāng)前的值和它們之前尚未被垃圾收集的值蛮粮。在Fleet中益缎,一個(gè)簡(jiǎn)單的集群對(duì)象大約需要6KB。對(duì)于100萬(wàn)個(gè)集群然想,我們至少需要6GB莺奔。但是一個(gè)集群一般包含10個(gè)左右的Kubernetes對(duì)象,加上每個(gè)部署一個(gè)對(duì)象变泄。所以在實(shí)際操作中令哟,我們更有可能需要超過(guò)100萬(wàn)個(gè)集群10倍的內(nèi)存空間。
為了繞過(guò)etcd的限制妨蛹,我們使用了Kine屏富,這使得使用傳統(tǒng)的RDBMS運(yùn)行任何Kubernetes發(fā)行版成為可能。在這個(gè)規(guī)模測(cè)試中蛙卤,我們運(yùn)行了RDS db.m5.24xlarge實(shí)例狠半。我們沒(méi)有嘗試對(duì)數(shù)據(jù)庫(kù)進(jìn)行適當(dāng)?shù)拇笮≌{(diào)整噩死,而是從最大的m5實(shí)例開(kāi)始。在測(cè)試結(jié)束時(shí)神年,我們?cè)贙ine中擁有大約2000萬(wàn)個(gè)對(duì)象已维。這意味著以這種規(guī)模運(yùn)行Fleet不能在EKS這樣的托管提供商上進(jìn)行已日,因?yàn)樗腔趀tcd的,也不會(huì)為我們的需求提供足夠可擴(kuò)展的數(shù)據(jù)存儲(chǔ)堂鲜。
這個(gè)測(cè)試似乎并沒(méi)有把數(shù)據(jù)庫(kù)push得很厲害。誠(chéng)然占婉,我們使用了一個(gè)非常大的數(shù)據(jù)庫(kù)泡嘴,但很明顯我們還有很多垂直擴(kuò)展的空間逆济。單條記錄的插入和查找繼續(xù)以可接受的速度進(jìn)行磺箕。我們注意到奖慌,隨機(jī)列出大量對(duì)象(最多一萬(wàn)個(gè))將會(huì)花費(fèi)30秒到一分鐘的時(shí)間。但一般來(lái)說(shuō)松靡,這些查詢(xún)會(huì)在不到1秒的時(shí)間內(nèi)完成简僧,或者在非常粗暴的測(cè)試下5秒也可以完成雕欺。因?yàn)檫@些耗時(shí)很長(zhǎng)的查詢(xún)發(fā)生在緩存重載期間,所以對(duì)系統(tǒng)整體影響不大屠列,我們將在后面討論。盡管這些緩慢的查詢(xún)并沒(méi)有對(duì)Fleet造成明顯的影響夏志,但我們還是需要進(jìn)一步調(diào)查為什么會(huì)出現(xiàn)這種情況苛让。
發(fā)現(xiàn)3:增加監(jiān)控緩存大小
當(dāng)controller加載緩存時(shí),首先會(huì)列出所有對(duì)象狱杰,然后從列表的修訂版開(kāi)始監(jiān)控。如果有非常高的變化率并且列出對(duì)象花費(fèi)了很長(zhǎng)的時(shí)間食棕,那么你很容易陷入這樣的情況:你完成了列表但無(wú)法啟動(dòng)監(jiān)控,因?yàn)锳PI Server的監(jiān)控緩存中沒(méi)有這個(gè)修訂版例隆,或者已經(jīng)在etcd中被壓縮了抢蚀。作為一個(gè)變通辦法,我們將監(jiān)控緩存設(shè)置為一個(gè)非常高的值(–default-watch-cache-size=10000000)唱逢。理論上屋休,我們認(rèn)為我們會(huì)遇到Kine的壓實(shí)問(wèn)題(compact),但我們沒(méi)有劫樟,這需要進(jìn)一步調(diào)查。一般來(lái)說(shuō)奶陈,Kine在壓實(shí)(compact)的頻率上要低很多附较。但在這種情況下,我們懷疑我們添加記錄的速度超過(guò)了Kine壓實(shí)的速度徐勃。這并不糟糕早像。我們并不希望堅(jiān)持要保持一致的變化率,這只是因?yàn)槲覀冋诳焖僮?cè)集群扎酷。
發(fā)現(xiàn)4:加載緩慢的緩存
Kubernetes controller的標(biāo)準(zhǔn)實(shí)現(xiàn)是將你正在處理的所有對(duì)象緩存在內(nèi)存中法挨。對(duì)于Fleet,這意味著我們需要加載數(shù)百萬(wàn)個(gè)對(duì)象來(lái)建立緩存凡纳。對(duì)象列表的默認(rèn)分頁(yè)大小為500荐糜。加載100萬(wàn)個(gè)對(duì)象需要2000個(gè)API請(qǐng)求葛超。如果你假設(shè)我們可以每秒鐘進(jìn)行一次列表調(diào)用延塑、處理對(duì)象并開(kāi)啟下一頁(yè),這意味著加載緩存需要30分鐘左右侥涵。不幸的是宋雏,如果這2000個(gè)API請(qǐng)求中的任何一個(gè)失敗,這個(gè)過(guò)程就會(huì)重新開(kāi)始磨总。我們嘗試將頁(yè)面大小增加到10,000個(gè)對(duì)象蚪燕,但看到整體加載時(shí)間并沒(méi)有明顯加快。我們開(kāi)始一次列出1萬(wàn)個(gè)對(duì)象之后馆纳,我們就遇到了一個(gè)問(wèn)題厕诡,Kine會(huì)隨機(jī)花費(fèi)超過(guò)1分鐘的時(shí)間來(lái)返回所有對(duì)象营勤。然后Kubernetes API Server會(huì)取消請(qǐng)求,導(dǎo)致整個(gè)加載操作失敗葛作,不得不重新啟動(dòng)。我們通過(guò)增加API請(qǐng)求超時(shí)(-request-timeout=30m)來(lái)解決這個(gè)問(wèn)題绪穆,但這不是一個(gè)可接受的解決方案虱岂。保持較小的頁(yè)面大小可以確保請(qǐng)求的速度更快,但請(qǐng)求的數(shù)量增加了失敗幾率难菌,并導(dǎo)致整個(gè)操作重啟蔑滓。
重啟Fleet controller將需要花費(fèi)45分鐘的時(shí)間遇绞。這一重啟時(shí)間同樣適用于kube-apiserver和kube-controller-manager摹闽。這意味著你需要非常小心褐健。這也是我們發(fā)現(xiàn)運(yùn)行K3s不如運(yùn)行RKE等傳統(tǒng)發(fā)行版的一點(diǎn)。K3s將api-server和controller-manager結(jié)合到同一個(gè)進(jìn)程中铝量,這使得重啟api-server或controller-manager的速度比原本應(yīng)有的速度慢慢叨,而且更容易出錯(cuò)。模擬一場(chǎng)災(zāi)難性的故障拍谐,需要完全重啟所有服務(wù)轩拨,包括Kubernetes,這一切花了幾個(gè)小時(shí)才恢復(fù)上線亡蓉。
加載緩存所需的時(shí)間和失敗的幾率是迄今為止我們發(fā)現(xiàn)的擴(kuò)展Fleet的最大問(wèn)題。今后淋肾,這是我們要解決的首要問(wèn)題爸邢。
結(jié) 論
通過(guò)測(cè)試,我們證明了Fleet的架構(gòu)可以擴(kuò)展到100萬(wàn)個(gè)集群碌尔,更重要的是券敌,Kubernetes可以作為一個(gè)平臺(tái)來(lái)管理更多的數(shù)據(jù)。Fleet本身與容器沒(méi)有任何直接的關(guān)系颈走,可以看成只是一個(gè)簡(jiǎn)單的應(yīng)用咱士,在Kubernetes中管理數(shù)據(jù)轧钓。這些發(fā)現(xiàn)為我們開(kāi)啟了一個(gè)可能性锐膜,即把Kubernetes更多的當(dāng)作一個(gè)通用的編排平臺(tái)來(lái)寫(xiě)代碼道盏。當(dāng)考慮到你可以很容易地將一套controller與K3s捆綁在一起,Kubernetes就變成了一個(gè)很好的自成一體的應(yīng)用server荷逞。
在擴(kuò)展規(guī)模方面种远,重新加載緩存所需的時(shí)間令人擔(dān)憂,但絕對(duì)是可控的坠敷。我們將繼續(xù)在這方面進(jìn)行改進(jìn)膝迎,使運(yùn)行100萬(wàn)個(gè)集群不僅是可行的,而且是簡(jiǎn)單的限次。因?yàn)樵赗ancher Labs,我們喜歡簡(jiǎn)單拖陆。