本篇文章為大家展示了如何使用Admission Webhook機(jī)制實(shí)現(xiàn)多集群資源配額控制,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
成都創(chuàng)新互聯(lián)公司主營松滋網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶APP軟件開發(fā),松滋h5小程序開發(fā)搭建,松滋網(wǎng)站營銷推廣歡迎松滋等地區(qū)企業(yè)咨詢
集群分配給多個(gè)用戶使用時(shí),需要使用配額以限制用戶的資源使用,包括 CPU 核數(shù)、內(nèi)存大小、GPU 卡數(shù)等,以防止資源被某些用戶耗盡,造成不公平的資源分配。
大多數(shù)情況下,集群原生的 ResourceQuota
機(jī)制可以很好地解決問題。但隨著集群規(guī)模擴(kuò)大,以及任務(wù)類型的增多,我們對配額管理的規(guī)則需要進(jìn)行調(diào)整:
ResourceQuota
針對單集群設(shè)計(jì),但實(shí)際上,開發(fā)/生產(chǎn)中經(jīng)常使用 多集群環(huán)境。
集群大多數(shù)任務(wù)通過比如deployment
、mpijob
等 高級資源對象進(jìn)行提交,我們希望在高級資源對象的 提交階段就能對配額進(jìn)行判斷。但 ResourceQuota
計(jì)算資源請求時(shí)以 pod
為粒度,從而無法滿足此需求。
基于以上問題,我們需要自行進(jìn)行配額管理。而 Kubernetes 提供了動(dòng)態(tài)準(zhǔn)入的機(jī)制,允許我們編寫自定義的插件,以實(shí)現(xiàn)請求的準(zhǔn)入。我們的配額管理方案,就以此入手。
進(jìn)入 K8s 集群的請求,被 API server 接收后,會(huì)經(jīng)過如下幾個(gè)順序執(zhí)行的階段:
認(rèn)證/鑒權(quán)
準(zhǔn)入控制(變更)
格式驗(yàn)證
準(zhǔn)入控制(驗(yàn)證)
持久化
請求在上述前四個(gè)階段都會(huì)被相應(yīng)處理,并且依次被判斷是否允許通過。各個(gè)階段都通過后,才能夠被持久化,即存入到 etcd 數(shù)據(jù)庫中,從而變?yōu)橐淮纬晒Φ恼埱?。其中,?準(zhǔn)入控制(變更)階段,mutating admission webhook
會(huì)被調(diào)用,可以修改請求中的內(nèi)容。而在 準(zhǔn)入控制(驗(yàn)證)階段,validating admission webhook
會(huì)被調(diào)用,可以校驗(yàn)請求內(nèi)容是否符合某些要求,從而決定是否允許或拒絕該請求。而這些 webhook
支持?jǐn)U展,可以被獨(dú)立地開發(fā)和部署到集群中。
雖然,在 準(zhǔn)入控制(變更)階段,webhook
也可以檢查和拒絕請求,但其被調(diào)用的次序無法保證,無法限制其它 webhook
對請求的資源進(jìn)行修改。因此,我們部署用于配額校驗(yàn)的 validating admission webhook
,配置于 準(zhǔn)入控制(驗(yàn)證)階段調(diào)用,進(jìn)行請求資源的檢查,就可以實(shí)現(xiàn)資源配額管理的目的。
在 K8s 集群中使用自定義的 validating admission webhook
需要部署:
ValidatingWebhookConfiguration
配置(需要集群啟用 ValidatingAdmissionWebhook) ,用于定義要對何種資源對象(pod
, deployment
, mpijob
等)進(jìn)行校驗(yàn),并提供用于實(shí)際處理校驗(yàn)的服務(wù)回調(diào)地址。推薦使用在集群內(nèi)配置 Service
的方式來提供校驗(yàn)服務(wù)的地址。
實(shí)際處理校驗(yàn)的服務(wù),通過在 ValidatingWebhookConfiguration
配置的地址可訪問即可。
單集群環(huán)境中,將校驗(yàn)服務(wù)以 deployment
的方式在集群中部署。多集群環(huán)境中,可以選擇:
使用 virtual kubelet,cluster federation 等方案將多集群合并為單集群,從而退化為采用單集群方案部署。
將校驗(yàn)服務(wù)以 deloyment
的方式部署于一個(gè)或多個(gè)集群中,但要注意保證服務(wù)到各個(gè)集群網(wǎng)絡(luò)連通。
需要注意的是,不論是單集群還是多集群的環(huán)境中,處理校驗(yàn)的服務(wù)都需要進(jìn)行資源監(jiān)控,這一般由單點(diǎn)實(shí)現(xiàn)。因此都需要 進(jìn)行選主。
API server:集群請求入口,調(diào)用 validating admission webhook
以驗(yàn)證請求
API:準(zhǔn)入服務(wù)接口,使用集群約定的 AdmissionReview 數(shù)據(jù)結(jié)構(gòu)作為請求和返回
Quota usage service:請求資源使用量接口
Admissions:準(zhǔn)入服務(wù)實(shí)現(xiàn),包括 deployment
和 mpijob
等不同資源類型準(zhǔn)入
Resource validator:對資源請求進(jìn)行配額校驗(yàn)
Quota adapter:對接外部配額服務(wù)供 validator 查詢
Resource usage manager:資源使用管理器,維護(hù)資源使用情況,實(shí)現(xiàn)配額判斷
Informers:通過 K8s 提供的 watch 機(jī)制監(jiān)控集群中資源,包括 deployment
和 mpijob
等,以維護(hù)當(dāng)前資源使用
Store:存放資源使用數(shù)據(jù),可以對接服務(wù)本地內(nèi)存實(shí)現(xiàn),或者對接 redis 服務(wù)實(shí)現(xiàn)
以用戶創(chuàng)建 deployment
資源為例:
用戶創(chuàng)建 deployment
資源,定義中需要包含指定了應(yīng)用組信息的 annotation
,比如 ti.cloud.tencent.com/group-id: 1
,表示申請使用應(yīng)用組 1
中的資源(如果沒有帶有應(yīng)用組信息,則根據(jù)具體場景,直接拒絕,或者提交到默認(rèn)的應(yīng)用組,比如應(yīng)用組 0
等)。
請求由 API server收取,由于在集群中正確配置了 ValidatingWebhookConfiguration
,因此在準(zhǔn)入控制的驗(yàn)證階段,會(huì)請求集群中部署的 validating admission webhook
的 API,使用 K8s 規(guī)定的結(jié)構(gòu)體AdmissionReviewRequest
作為請求,期待 AdmissionReviewResponse
結(jié)構(gòu)體作為返回。
配額校驗(yàn)服務(wù)收到請求后,會(huì)進(jìn)入負(fù)責(zé)處理 deployment
資源的 admission的邏輯,根據(jù)改請求的動(dòng)作是 CREATE 或 UPDATE 來計(jì)算出此次請求需要新申請或者釋放的資源。
從 deployment
的 spec.template.spec.containers[*].resources.requests
字段中提取要申請的資源,比如為 cpu: 2
和 memory: 1Gi
,以 apply 表示。
Resource validator查找 quota adapter獲取應(yīng)用組 1
的配額信息,比如 cpu: 10
和 memory: 20Gi
,以 quota 表示。連同上述獲取的 apply,向 resource usage manager申請資源。
Resource usage manager一直在通過 informer監(jiān)控獲取 deployment
的資源使用情況,并維護(hù)在 store中。Store可以使用本地內(nèi)存,從而無外部依賴?;蛘呤褂?Redis
作為存儲(chǔ)介質(zhì),方便服務(wù)水平擴(kuò)展。
Resource usage manager收到 resource validator的請求時(shí),可以通過 store查到應(yīng)用組 1
當(dāng)前已經(jīng)占用的資源情況,比如 cpu: 8
和 memory: 16Gi
,以 usage 表示。檢查發(fā)現(xiàn) apply + usage <= quota 則認(rèn)為沒有超過配額,請求通過,并最終返回給 API server。
以上就是實(shí)現(xiàn)資源配額檢查的基本流程。有一些細(xì)節(jié)值得補(bǔ)充說明:
校驗(yàn)服務(wù)的接口 API必須采用 https 暴露服務(wù)。
針對不用的資源類型,比如 deployment
、mpijob
等,都需要實(shí)現(xiàn)相應(yīng)的 admission以及 informer。
每個(gè)資源類型可能有不同的版本,比如 deployment
有 apps/v1
、apps/v1beta1
等,需要根據(jù)集群的實(shí)際情況兼容處理。
收到 UPDATE 請求時(shí),需要根據(jù)資源類型中 pod
的字段是否變化,來判斷是否需要重建當(dāng)前已有的 pod
實(shí)例,以正確計(jì)算資源申請的數(shù)目。
除了 K8s 自帶的資源類型,比如 cpu
等,如果還需要自定義的資源類型配額控制,比如 GPU 類型等,需要在資源請求約定好相應(yīng)的 annotations
,比如 ti.cloud.tencent.com/gpu-type: V100
在 resource usage manager進(jìn)行使用量、申請量和配額的判斷過程中,可能會(huì)出現(xiàn) 資源競爭、配額通過校驗(yàn)但實(shí)際 資源創(chuàng)建失敗等問題。接下來我們會(huì)對這兩個(gè)問題進(jìn)行解釋。
由于并發(fā)資源請求的存在:
usage 需要能夠被在資源請求后即時(shí)更新
usage 的更新需要進(jìn)行并發(fā)控制
在上述步驟 7 中,Resource usage manager校驗(yàn)配額時(shí),需要查詢應(yīng)用組當(dāng)前的資源占用情況,即應(yīng)用組的 usage 值。此 usage 值由 informers負(fù)責(zé)更新和維護(hù),但由于從資源請求被 validating admission webhook
通過,到 informer能夠觀察到,存在時(shí)間差。這個(gè)過程中,可能仍有資源請求,那么 usage 值就是不準(zhǔn)確的了。因此,usage 需要能夠被在資源請求后即時(shí)更新。
并且對 usage 的更新需要進(jìn)行并發(fā)控制,舉個(gè)例子:
應(yīng)用組 2
的 quota 為 cpu: 10
,usage 為 cpu: 8
進(jìn)入兩個(gè)請求 deployment1
和 deployment2
申請使用應(yīng)用組 2
,它們的 apply 同為 cpu: 2
需要首先判斷 deployment1
, 計(jì)算 apply + usage = cpu: 10
,未超過 quota 值,因此 deployment1
的請求允許通過。
usage 被更新為 cpu: 10
再去判斷 deployment2
,由于 usage 被更新為 cpu: 10
,則算出 apply + usage = cpu: 12
,超過了 quota 的值,因此不允許通過該請求。
上述過程中,容易發(fā)現(xiàn) usage 是關(guān)鍵的 共享變量,需要順序查詢和更新。若 deployment1
和 deployment2
不加控制地同時(shí)使用 usage 為 cpu: 8
,就會(huì)導(dǎo)致 deployment1
和 deployment2
請求都被通過,從而實(shí)際超出了配額限制。這樣,用戶可能占用 超過配額規(guī)定的資源。
可行的解決辦法:
資源申請進(jìn)入隊(duì)列,由單點(diǎn)的服務(wù)依次消費(fèi)和處理。
將共享的變量 usage 所處的臨界區(qū)上鎖,在鎖內(nèi)查詢和更新 usage 的值。
由于資源競爭的問題,我們要求 usage 需要能夠被在資源請求后即時(shí)更新,但這也帶來新的問題。在 4. 準(zhǔn)入控制(驗(yàn)證)階段之后,請求的資源對象會(huì)進(jìn)入 5. 持久化階段,這個(gè)過程中也可能出現(xiàn)異常(比如其他的 webhook
又拒絕了該請求,或者集群斷電,etcd 故障等)導(dǎo)致任務(wù)沒有實(shí)際提交成功到集群數(shù)據(jù)庫。在這種情況下,我們在 驗(yàn)證階段,已經(jīng)增加了 usage 的值,就把沒有實(shí)際占用配額的任務(wù)算作占用了配額。這樣,用戶可能占用 不足配額規(guī)定的資源。
為了解決這個(gè)問題,后臺(tái)服務(wù)會(huì)定時(shí)全局更新每個(gè)應(yīng)用組的 usage 值。這樣,如果出現(xiàn)了 驗(yàn)證階段增加了 usage 值,但任務(wù)實(shí)際提交到數(shù)據(jù)庫失敗的情況,在全局更新的時(shí)候,usage 值最終會(huì)重新更新為那個(gè)時(shí)刻應(yīng)用組在集群內(nèi)資源使用的準(zhǔn)確值。
但在極少數(shù)情況下,全局更新會(huì)在這種時(shí)刻發(fā)生:某最終會(huì)成功存入 etcd 持久化的資源對象創(chuàng)建請求,已經(jīng)通過
webhook
驗(yàn)證,但尚未完成 持久化的時(shí)刻。這種時(shí)刻的存在,導(dǎo)致全局更新依然會(huì)帶來用戶占用 超過配額的問題。 比如,在之前的例子中,deployment1
更新了 usage 值之后,恰巧發(fā)生了全局更新。此時(shí)deployment1
的信息恰好尚未存入 etcd,所以全局更新會(huì)把 usage 重新更新為舊值,這樣會(huì)導(dǎo)致dployment2
也能被通過,從而超過了配額限制。 但通常,從 驗(yàn)證到 持久化的時(shí)間很短。低頻的全局更新情況下,此種情況 幾乎不會(huì)發(fā)生。后續(xù),如果有進(jìn)一步的需求,可以采用更復(fù)雜的方案來規(guī)避這個(gè)問題。
ResourceQuota
的工作方式K8s 集群中原生的配額管理 ResourceQuota
針對上述 資源申請競爭和 資源創(chuàng)建失敗問題,采用了類似的解決方案:
即時(shí)更新解決申請競爭問題
檢查完配額后,即時(shí)更新資源用量,K8s 系統(tǒng)自帶的樂觀鎖保證并發(fā)的資源控制(詳見 K8s 源碼中 checkQuotas 的實(shí)現(xiàn)),解決資源競爭問題。
checkQuotas
中最相關(guān)的源碼解讀:
// now go through and try to issue updates. Things get a little weird here: // 1. check to see if the quota changed. If not, skip. // 2. if the quota changed and the update passes, be happy // 3. if the quota changed and the update fails, add the original to a retry list var updatedFailedQuotas []corev1.ResourceQuota var lastErr error for i := range quotas { newQuota := quotas[i] // if this quota didn't have its status changed, skip it if quota.Equals(originalQuotas[i].Status.Used, newQuota.Status.Used) { continue } if err := e.quotaAccessor.UpdateQuotaStatus(&newQuota); err != nil { updatedFailedQuotas = append(updatedFailedQuotas, newQuota) lastErr = err } }
這里 quotas
是經(jīng)過校驗(yàn)后的配額信息,其中 newQuota.Status.Used
字段則記錄了該配額的資源使用情況。如果針對該配額的資源請求通過了,運(yùn)行到這段代碼時(shí),Used
字段中已經(jīng)被加上了新申請資源的量。隨后,Equals
函數(shù)被調(diào)用,即如果 Used
字段未變,說明沒有新的資源申請。否則,就會(huì)運(yùn)行到 e.quotaAccessor.UpdateQuotaStatus
,立刻去把 etcd 中的配額信息按照 newQuota.Status.Used
來更新。
定時(shí)全局更新解決創(chuàng)建失敗問題
定時(shí)全局更新資源使用量(詳見 K8s 源碼中 Run 的實(shí)現(xiàn)),解決可能的資源創(chuàng)建失敗問題 。
Run
中最相關(guān)的源碼解讀:
// the timer for how often we do a full recalculation across all quotas go wait.Until(func() { rq.enqueueAll() }, rq.resyncPeriod(), stopCh)
這里 rq
為 ResourceQuota
對象對應(yīng) controller 的自引用。這個(gè) Controller 運(yùn)行 Run
循環(huán),持續(xù)地控制所有 ResourceQuota
對象。循環(huán)中,不間斷定時(shí)調(diào)用 enqueueAll
,即把所有的 ResourceQuota
壓入隊(duì)列中,修改其 Used
值,進(jìn)行全局更新。
上述內(nèi)容就是如何使用Admission Webhook機(jī)制實(shí)現(xiàn)多集群資源配額控制,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
網(wǎng)站名稱:如何使用AdmissionWebhook機(jī)制實(shí)現(xiàn)多集群資源配額控制
文章源于:http://bm7419.com/article46/iioshg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App開發(fā)、網(wǎng)站設(shè)計(jì)、云服務(wù)器、、網(wǎng)站建設(shè)、建站公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)