如何管理Kubernetes集群的容量與資源
譯文【51CTO.com快譯】眾所周知,系統(tǒng)資源并非無(wú)限的。在那些大型集群即服務(wù)的場(chǎng)景中,我們需要認(rèn)真地布局和規(guī)劃集群資源的配比。不過,在各種軟件項(xiàng)目中,開發(fā)人員往往會(huì)錯(cuò)誤地認(rèn)為虛擬化和容器化能夠讓資源看起來更像個(gè)巨大的池子,可用隨意使用。例如,他們?cè)趪L試運(yùn)行某個(gè)需要大量資源的應(yīng)用,尤其是在啟用了自動(dòng)擴(kuò)展功能的群集上時(shí),就可能看到如下圖所示的情況:
顯然,通過kubectl get,我們發(fā)現(xiàn)有數(shù)十個(gè)evicted pod,而實(shí)際上可能只想運(yùn)行5個(gè)pod。此時(shí),您可能非常希望通過對(duì)Kubernetes集群資源的管理,來自動(dòng)實(shí)現(xiàn)對(duì)于容量和資源的分配。
兩個(gè)示例
如上圖所示,假設(shè)我們手頭有一個(gè)帶有16個(gè)虛擬CPU和64GB RAM的Kubernetes集群。那么,我們可以在它上面流暢地運(yùn)行一個(gè)需要20GB內(nèi)存的AI容器嗎?
假設(shè)該集群中有4個(gè)worker,每個(gè)都需要有16GB的可用內(nèi)存(實(shí)際上,DaemonSet和系統(tǒng)服務(wù)都需要運(yùn)行一個(gè)節(jié)點(diǎn),并占用少量的資源,因此真實(shí)可用內(nèi)存可能會(huì)更少一些)。那么,在這種情況下,如果我們只分配16GB內(nèi)存給容器的話,我們將無(wú)法保證其流暢運(yùn)行。
其實(shí),不僅此類大容器的部署,我們?cè)谶M(jìn)行其他復(fù)雜的部署,甚至是采用Helm chart(請(qǐng)參見-- https://grapeup.com/blog/asp-net-core-ci-cd-on-azure-pipelines-with-kubernetes-and-helm/)之類開箱即用的產(chǎn)品時(shí),都必須始終考慮到資源的限制問題。
讓我們來看另一個(gè)示例--將Ceph部署到同一個(gè)集群中。我們的實(shí)現(xiàn)目標(biāo)是將1TB的存儲(chǔ)空間分成10個(gè)OSD(object storage daemons,對(duì)象存儲(chǔ)守護(hù)程序)和3個(gè)ceph MON(監(jiān)視器)。我們希望將其放置在兩個(gè)節(jié)點(diǎn)上,其余兩個(gè)則留給需要使用該存儲(chǔ)的部署。這將是一個(gè)高度可擴(kuò)展的架構(gòu)。
一般用戶首先能夠想到的做法是將OSD的數(shù)量設(shè)置為10,MON設(shè)置為3,將tolerations添加到Ceph的pod中,以及將taint匹配上Node 1和Node 2。而所有的ceph部署和pod都將nodeSelector設(shè)置為僅針對(duì)Node 1和2。
如下圖所示,Kubernetes會(huì)讓mon-1、mon-2和5個(gè)osd運(yùn)行在第一個(gè)worker上,讓mon-3和另5個(gè)osds運(yùn)行在第二個(gè)worker上。應(yīng)用程序可以快速地將大量的大體積文件保存到Ceph上。
如果我們還部署了儀表板,并創(chuàng)建了一個(gè)復(fù)制池,那么還可以直觀地看到1TB的可用存儲(chǔ)空間和10個(gè)OSD的狀態(tài)。
不過,在運(yùn)行了一段時(shí)間后,我們會(huì)發(fā)現(xiàn)真正可用的存儲(chǔ)空間只剩下了400GB,出現(xiàn)了許多evicted OSD pods,而且有4個(gè)OSDs正在同時(shí)運(yùn)行。對(duì)此,我們需要重新審視初始時(shí)的部署配置。
極限和范圍
平時(shí),就算我們運(yùn)行了13個(gè)Pod(其中可能有3個(gè)監(jiān)控器),也不會(huì)占用過多的資源,但是OSD則不然。由于Ceph在內(nèi)存中緩存了很大量的數(shù)據(jù),那么我們使用得越頻繁,它需要的資源也就越多。同時(shí),各種存儲(chǔ)容器的數(shù)據(jù)復(fù)制和平衡也需要消耗一定的空間。因此,在初次化部署之后,內(nèi)存的分配情況會(huì)如下圖所示:
而在數(shù)小時(shí)的持續(xù)運(yùn)行之后,該集群就會(huì)出現(xiàn)如下狀況:
可見,我們損失了幾乎50%的pod。而且這并非是最終狀態(tài),如果高吞吐量將目標(biāo)指向剩余的容器,那么我們很快會(huì)失去得更多。那么,這是否意味著我們需要給Ceph集群配置超過32GB的內(nèi)存呢?非也。只要我們正確地設(shè)置了限制(請(qǐng)參見--https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-requests-and-limits-of-pod-and-container),單個(gè)OSD就不能從其他pod處搶奪所有的可用內(nèi)存。
也就是說,在這種情況下,我們最簡(jiǎn)單的方法是:為mon整體分配并保留2GB的內(nèi)存,其中每個(gè)的極限為650MB;將一共30GB的內(nèi)存除以10個(gè)OSD(請(qǐng)見下圖):
由于我們?yōu)镺SD分配了15GB的內(nèi)存,并為每個(gè)Pod配置了650MB的內(nèi)存,因此第一個(gè)節(jié)點(diǎn)會(huì)需要:15 + 2 * 0.65 = 16.3GB。此外,我們同樣需要考慮到在同一節(jié)點(diǎn)上運(yùn)行的DaemonSet日志。因此,修正值應(yīng)該是:
服務(wù)質(zhì)量
如果我們還為Pod設(shè)置了一個(gè)與限制完全匹配的請(qǐng)求,那么Kubernetes將會(huì)以不同的方式來對(duì)待此類Pod,如下圖所示:
該配置將Kubernetes中的QoS設(shè)置為Guaranteed(否則是Burstable)。有Guaranteed的Pod是永遠(yuǎn)不會(huì)被evicte的。通過設(shè)置相同的請(qǐng)求和限制,我們可以確保Pod的資源使用情況,而無(wú)需顧及Kubernetes對(duì)其進(jìn)行移動(dòng)或管理。此舉雖然降低了調(diào)度程序(scheduler)的靈活性,但是能夠讓整個(gè)部署方式更具有一定的彈性。
自動(dòng)擴(kuò)展環(huán)境中的資源
對(duì)于關(guān)鍵性任務(wù)系統(tǒng)(mission-critical systems,請(qǐng)參見--https://grapeup.com/)而言,光靠估算所需的資源,來匹配群集的大小,并做好相關(guān)限制是遠(yuǎn)遠(yuǎn)不夠的。有時(shí)候,我們需要通過更加復(fù)雜的配置,以及非固定的集群容量,來實(shí)現(xiàn)水平擴(kuò)展和調(diào)整可用的worker數(shù)量。
假設(shè)資源會(huì)呈線性擴(kuò)展的話,那么我們可以同時(shí)規(guī)劃最小和最大群集的容量。而如果pod能夠被允許在群集擴(kuò)展時(shí),跟蹤那些按比例在水平方向和垂直方向的擴(kuò)展的話,那么它在按等比收縮時(shí),則可能會(huì)“逐出”其他的pod。為了緩解該問題,Kubernetes提出了兩個(gè)主要概念:Pod Priority和Pod Disruption Budget。
下面,讓我們從創(chuàng)建測(cè)試場(chǎng)景開始討論。這次我們不需要大量的節(jié)點(diǎn),只需要?jiǎng)?chuàng)建一個(gè)具有兩個(gè)節(jié)點(diǎn)組的集群:一個(gè)由常規(guī)實(shí)例組成(稱為持久性),一個(gè)由可搶占(preemptible/spot)實(shí)例組成。如下圖所示,當(dāng)VM(現(xiàn)有節(jié)點(diǎn))的CPU使用率超過0.7(即70%)時(shí),可搶占節(jié)點(diǎn)組將進(jìn)行擴(kuò)展。
可搶占實(shí)例的優(yōu)勢(shì)在于它們比具有相同性能的常規(guī)VM要容易實(shí)現(xiàn)得多。而唯一缺點(diǎn)是無(wú)法保證其生命周期。也就是說,當(dāng)云提供商出于維護(hù)目的,或在24小時(shí)之后決定在其他地方需要實(shí)例時(shí),該實(shí)例就可能會(huì)被“逐出”。因此,我們只能在其中運(yùn)行那些可容錯(cuò)的無(wú)狀態(tài)負(fù)載。
那么,集群中為什么只有一個(gè)持久性節(jié)點(diǎn)呢?這是為極端情況做準(zhǔn)備的。當(dāng)所有可搶占節(jié)點(diǎn)均未運(yùn)行時(shí),它將維護(hù)一個(gè)最少的容器集,以管理和保障應(yīng)用程序的可操作性。下表展示了此類例程的結(jié)構(gòu)。我們可以使用節(jié)點(diǎn)選擇器將redis master配置為能夠在持久性節(jié)點(diǎn)上運(yùn)行。
Pod Priority
下面,我們來看一個(gè)水平pod自動(dòng)擴(kuò)展器(Horizontal Pod Autoscaler,HPA)的例子。
前端:
后端:
視頻轉(zhuǎn)換器:
作為一款視頻轉(zhuǎn)換器,它的目標(biāo)是降低平均資源的占有率。也就是說,通過檢查擴(kuò)展策略,當(dāng)有多個(gè)轉(zhuǎn)換隊(duì)列時(shí),其CPU平均使用率可能會(huì)迅速達(dá)到25%,那么它就會(huì)產(chǎn)生新的自動(dòng)化擴(kuò)展。例如:如果在大約10分鐘的時(shí)間內(nèi),需要進(jìn)行50次視頻轉(zhuǎn)換,那么該轉(zhuǎn)換器就會(huì)擴(kuò)展出25個(gè)實(shí)例。那么,為了避免集群中的其他容器被evicte,我們可以創(chuàng)建一種優(yōu)先級(jí)類別(請(qǐng)參見-- https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption):優(yōu)先級(jí)較高的pod對(duì)于調(diào)度程序而言,具有更高的價(jià)值;而優(yōu)先級(jí)較低的pod,則可以被evicte。
因此,如果我們給予轉(zhuǎn)換器較低的優(yōu)先級(jí),那么就是默認(rèn)了前端和后端Pod更為重要。在最壞的情況下,該視頻轉(zhuǎn)換器可以從群集中逐出。
Pod Disruption Budget
作為更好的pod控制與調(diào)度方法,Pod Disruption Budget(PDB)使我們可以一次性配置最少數(shù)量的pod。由于有效地阻止了節(jié)點(diǎn)資源被耗盡,因此它比僅使用Pod Priority要更加嚴(yán)格。如果其他worker上沒有足夠的空間用來重新調(diào)度pod,它會(huì)保證副本的數(shù)量不少于可分配的預(yù)定。
上表展示了最基本的配置。其中,前端副本數(shù)不低于2。我們可以據(jù)此為所有Pod分配一個(gè)最小值,并確保始終至少有1到2個(gè)pod可以處理請(qǐng)求。
這是確保pod能夠自動(dòng)擴(kuò)展、集群可以伸縮的最簡(jiǎn)單、也是最安全的方法。只要我們配置了帶有中斷預(yù)定的最少容器集,就能夠在不會(huì)影響整體穩(wěn)定性的基礎(chǔ)上,滿足最小集群容量、以及各種請(qǐng)求的最低處理要求。
至此,我們已擁有了創(chuàng)建穩(wěn)定方案所需的全部必需組件。我們可以將HPA配置為與PDB相同的最小副本數(shù),以簡(jiǎn)化調(diào)度程序的工作。同時(shí),我們需要根據(jù)最大群集數(shù),來確保限制數(shù)與請(qǐng)求數(shù)不但相同,且不會(huì)evicte pod。具體配置如下表所示:
基于上述調(diào)度程序的靈活性,在前端和后端的負(fù)載過低,卻有大量數(shù)據(jù)需要轉(zhuǎn)換時(shí),該轉(zhuǎn)換器會(huì)自動(dòng)擴(kuò)展出19-21個(gè)實(shí)例。
自動(dòng)擴(kuò)展的注意事項(xiàng)
關(guān)于自動(dòng)擴(kuò)展,我們需要注意如下兩個(gè)方面:
首先,由于我們無(wú)法確定云服務(wù)提供商的虛擬機(jī)啟動(dòng)時(shí)長(zhǎng)(可能幾秒鐘,也可能需要幾分鐘),因此我們無(wú)法保障自動(dòng)擴(kuò)展肯定能夠解決峰值負(fù)載的問題。
其次,在集群縮減時(shí),對(duì)于那些正在運(yùn)行組件,我們需要通過反復(fù)測(cè)試,讓調(diào)度程序能夠快速地將負(fù)載移至其他worker處,以實(shí)現(xiàn)在不破壞應(yīng)用操作的前提下,有效地關(guān)閉虛擬機(jī)。
原標(biāo)題:Kubernetes Cluster Management: Size and Resources,作者:Adam Kozlowski
【51CTO譯稿,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文譯者和出處為51CTO.com】