成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Kubernetes 跨集群 Pod 可用性保護

云計算 云原生
多集群部署微服務帶來了可擴展性和容災性等優勢,但也引入了全局層面的脆弱性——中心控制平面的任何問題都會級聯影響所有被管理集群,造成災難性后果。其中最嚴重的場景之一是由于Pod刪除導致的服務容量丟失。

多集群部署微服務帶來了可擴展性和容災性等優勢,但也引入了全局層面的脆弱性——中心控制平面的任何問題都會級聯影響所有被管理集群,造成災難性后果。其中最嚴重的場景之一是由于Pod刪除導致的服務容量丟失。這在Kubernetes復雜的事件鏈中可能由多種原因引發,例如:

  • 意外刪除所有Deployment的owner資源類型的CRD
  • 集群拓撲配置錯誤,導致用其他集群的spec覆蓋當前集群
  • 多集群滾動更新實現缺陷,同時在所有集群觸發更新
  • 聯邦主集群的etcd磁盤損壞,導致Deployment對象從索引中移除
  • 多個集群同時獨立進行Pod驅逐操作,并發度不受控

雖然這些問題均可單獨解決,但成因多樣且在持續變化的基礎設施中難以窮舉。更便捷的方式是采用端到端處理:只要全局要求未滿足就阻止Pod刪除。因此我們開發了Podseidon項目——當跨集群的最小可用性要求不滿足時,拒絕刪除請求的準入webhook。

圖片

01、整體設計

Podseidon引入PodProtector CRD,其spec與原生PodDisruptionBudget相近:

apiVersion: podseidon.kubewharf.io/v1alpha1
kind: PodProtector
spec:
selector:
matchLabels: {app: www}
minAvailable: 8
minReadySeconds: 30

為與現有工作負載集成,Podseidon提供可定制插件的控制器 podseidon-generator,用于從Deployment等根屬主工作負載自動生成并同步PodProtector。部署在每個集群的podseidon-aggregator控制器將集群內Pod當前狀態聚合寫入PodProtector的status字段,而各集群并配置了準入驗證 webhook podseidon-webhook,在可用性底線未能滿足時拒絕Pod的刪除請求。

圖片

同步路徑 vs 最終一致性

Pod刪除事件有兩種數據源:list-watch與準入webhook,各有優劣:


List-watch

準入 webhook

及時性

異步,通常滯后~100ms

同步,UpdateStatus成功時相對其他 webhook 實例具備原子性

準確性

代表過去某時刻的真實快照

可能包含被其他原因拒絕的刪除事件

相對實際狀態

≤ 實際刪除數,可能遺漏最新事件

≥ 實際刪除數,可能誤計被拒事件

舉個圖表化的例子:

圖片

(實際的pod刪除過程涉及多個步驟,但為了討論簡單起見,我們假設在成功執行DELETE請求并設置deletionTimestamp后,pod 會立即被刪除)

list-watch 低于實際值,這意味著突然大量刪除事件會被錯誤地允許爆發,所以這并非一個安全的選擇。但是使用來自webhook的事件計數也不可行,因為它會無限制地偏離實際狀態。

相反,我們結合了兩個數據源:webhook 存儲已批準的 pod 刪除的歷史記錄,aggregator將其視圖時間之前的歷史記錄壓縮為最終正確的狀態。PodProtector 對象同時包含來自aggregator最后觀察到的狀態以及其后來自 webhook 的增量歷史,后者作為臨時緩沖等待aggregator進行權威聚合。當刪除突發過大,無法在單個 PodProtector 對象內存儲(因為可能包含上萬副本Deployment的每個副本的條目)時,最早的Pod刪除事件將被壓縮到某個時間范圍內,避免超大PodProtector對象影響存儲集群性能。

示例時間線:

圖片

因此,分歧的 webhook 線會定期校準到實際線。考慮之前的示例,其中aggregator每秒報告一秒前的狀態,校準后的線與實際線更接近:

圖片

除了壓縮刪除歷史之外,aggregator還會將擴縮容、數據面等非刪除事件導致的可用性變化同步到基線值。由于 Podseidon 僅旨在防止控制平面導致的不可用,這些狀態變化的延遲相對可以接受。使用此雙數據源方案,可以平衡正確性和及時性的要求。

Aggregator 快照時間推斷

為準確截斷準入歷史并保留當前快照后的增量刪除事件,需從aggregator的pod list-watch事件中獲取事件時間戳,然而Kubernetes原生未提供該功能。

最理想的方案本應使webhook與aggregator共用同一時鐘,但由于刪除請求無法通過mutating webhook修改對象字段,這個想法并不可行。故此,我們需通過其他不可靠渠道推斷快照時間戳,包括:

  • clock:使用aggregator系統時間
  • status:使用Pod字段(creationTimestamp、deletionTimestamp、conditions等)

這些方法均存在偏差:

圖片

  • 受webhook響應延遲和watch延遲影響,aggregator系統時間會晚于準入webhook錄入PodProtector準入歷史的時間
  • Pod字段時間數據源不一致,部分早于、部分晚于webhook響應,但無watch延遲問題。尤其當status.conditions推斷的快照時間早于webhook準入時間時,可能導致快照無法清除引發自身觸發刪除事件的準入記錄。此外,部署于不同機器的組件間可能存在系統時鐘偏差。

在字節跳動的實踐中,我們部署的定制版kube-apiserver會在etcd存儲的GuaranteedUpdate調用中添加annotation。

其值為當前apiserver系統時間戳(功能上就是個lastUpdateTimestamp)。這使得準入歷史時間戳與推斷的快照時間之間的延遲更可預測,在生產環境中驗證該方案,余下的競態問題機率較小可忽略。對于標準Kubernetes,推薦采用aggregator系統時間方案 (clock),至少避免了快照無法清除自身觸發事件的問題。

不過理論上,即使忽略時鐘偏差,當watch延遲過高時,clock仍可能導致假陰性(錯誤允許pod刪除):

圖片

在00:01之后,pod X和pod Y被允許刪除,此時PodProtector狀態中包含兩個準入歷史記錄條目{X: 00:00}及{Y: 00:01}。在00:02時,aggregator收到pod X 刪除的watch事件(延遲了2秒)。通過其informer中的新緩存狀態,它觀察到00:02時的快照包含pod Y而不包含pod X,因此PodProtector狀態中的兩個準入歷史條目都被清除了。實際上這是預期的行為,因為這符合我們的假設:如果在00:02發生事件而前面沒有收到pod Y的刪除事件,則意味著pod Y實際上并未被刪除;但事實上,該請求仍在處理中,只是時間參照系不一致導致誤判。雖然aggregator最終會在00:04更新,正確地排除X和Y影響的pod數,但如果webhook在00:03收到另一個其他pod的刪除請求(下稱pod Z),則會被錯誤允許準入,因為系統假定只有pod X被刪除而pod Y未被刪除,從而導致最后一個不可用配額同時被 pod Y 和 pod Z 重復使用。

在災難性事件中,大量 pod 在短時間內被刪除時,這個問題尤其顯著。假設有個控制器在同一個Deployment下,在 10 毫秒內并發100個刪除不同pod的請求:由于webhook推送了100次準入歷史,臨時不可用配額下降了 100;但如果aggregator在觀察到首個刪除事件后、觀察到后續事件之前過快進行對賬,其中99個會立即被撤銷。如果前面的控制器再對其他pod激增99個刪除請求,不可用約束便會突破近雙倍了。

為緩解此問題,Podseidon 提供了兩個配置項,可全局配置或針對單個PodProtector進行覆蓋:

  • maxConcurrentLag限制限制單個PodProtector中準入歷史的最大條目數。當該值小于maxUnavailable閾值時,可以確保aggregator單次最多清除maxConcurrentLag個條目。然而,將其設置得過小會導致PodProtector緩沖擠擁,引致更多假陽性(誤拒絕)返回值,從而可能損害發布、縮容等操作的效率,尤其是當頻繁失敗觸發控制器退避邏輯的更長間隔時尤其顯著。
  • aggregationRateMillis為aggregator添加從接收pod事件到執行聚合的延遲,限制同一PodProtector的聚合頻率。如果一個PodProtector最近沒有新的 pod 事件,收到第一個事件后會先等待aggregationRateMillis,以容許更多激增性事件進入informer,然后再執行聚合;每次聚合后至少aggregationRateMillis內不會對同一PodProtector進行重聚合。雖然聚合觸發有所延遲,但聚合過程使用的是最新的快照,而非事件接收時的快照。這有助于緩解由上述相同對象突然大量刪除引起的競態條件問題(除非我們不幸接收到在第一個事件后正好過了aggregationRateMillis毫秒才開始發生刪除激增)。然而,將該值設置得過高可能會導致更多由于控制器響應變慢帶來的誤拒絕,例如在正常的滾動更新過程中,當新版本的pod X狀態切成可用,可以把舊版本的pod Y下線時:

圖片

雖然這可能會導致偶爾的誤判拒絕,但replicaset controller或GC controller的重試退避通常能夠在第二次嘗試時成功刪除。

圖片

一個生產機房內的實際pod刪除準入率。在有開啟Podseidon保護的pod刪除中,拒絕率

甚低,基本對用戶無影響。

觸發最終壓縮

Kubernetes 的一個重要特性是系統必須具備自愈能力,狀態最終趨向spec的要求。然而,上述算法單獨使用時無法實現這一目標:當webhook插入了錯誤的刪除事件時,aggregator不會主動將其移除,而需等待kube-apiserver發送新的pod事件才能清除該記錄。這可能會在低副本場景中導致死鎖——pod刪除請求被webhook攔截,webhook正在等待aggregator清除先前無效的刪除事件以釋放不可用配額,而aggregator則在等待apiserver發送事件,但由于pod刪除被阻塞,apiserver根本沒有事件可發送。

為解決這一問題,我們利用了單list-watch流中pod事件的強序特性:每個快照都是一個原子視圖,涵蓋了快照之前所有由list-watch選擇器覆蓋對象的所有事件。換句話說,如果我們在t?收到一個pod X的事件,在t?到t?之間沒有其他事件,然后在t?收到pod Y的事件,我們就可以確認自t?事件以來,pod X 沒有發生新變化。因此,aggregator可以維護一個待處理池,追蹤所有尚未完全壓縮準入歷史的PodProtector對象,并在收到list-watch流任意pod事件時嘗試對這些對象進行對賬。即使這些事件來自于未被 PodProtector 選擇器選中的 pod,更新了的全局快照時間也能觸發更多準入歷史壓縮。

這問題在大規模集群中便解決了,在這些集群中,每秒可能會有數百或數千次由真正的pod生命周期或數據面事件自然觸發pod 更新。然而,對于每秒不到一 pod事件的小型集群,更新事件頻率過低,可能數分鐘才自然觸發一遍對帳,對用戶造成可見的影響,如滾動或縮容操作明顯減慢。為解決此問題,可能會想到幾種方案:

  • 為準入歷史增設到期時間——這實際上違背了Podseidon的設計目的。在一些極端災難事件中,watch請求很可能會中斷并觸發relist,從而在此期間引起非常高的watch時延(在大規模集群中relist可能需要長達數分鐘),甚至無法重新建立新的一致性快照。增設到期時間在這種情況下實際上會使Podseidon webhook失去原來的作用。
  • 如果一段時間內沒有事件則進行relist——但這樣的時間周期該設多長?relist過程本身也會導致長時間沒有事件,可能會使情況更糟。而且pod list是個很重的操作,頻繁的relist可能沖擊kube-apiserver的性能。
  • 在一個dummy pod上觸發事件——這聽起來可能不太優雅,但這是我們找到最切實可行的方案。通過循環更新一個會在list-watch流中發送的dummy pod(例如切換pod注解),我們可以確保watch流的最小理論事件率,從而在正常情況下將無效準入歷史條目的存續時間限制在這一時間下。

因此,只有第三種方案是可行的。podseidon-aggregator中嵌入了一個循環組件來執行該方案,可以通過 CLI 選項啟用。

圖片

根據直方圖指標推算出某機房中不同大小的集群發送watch事件前后間的最大時間間隔

這個強一致性要求意味著,每個list-watch流的準入歷史和聚合狀態必須獨立存儲(我們稱之為“cell”)。在aggregator需要使用多個reflector(如多個命名空間、獨立標簽選擇算符等)場景中,它們必須在不同的aggregator實例中執行,且webhook必須配置以識別每個準入請求所對應的cell。

PodProtector批量更新

由于每個刪除請求都需要在托管PodProtector對象的集群("core集群")中預留不可用配額,每次準入都會對core集群進行一個獨立的compare-and-swap更新。這種設計在架構上并不合理,因為拆分多集群本來的目標就是將apiserver負載從O(mn)(m為部署數量,n為每個部署的副本數)降低到core集群O(m)。況且,對同一PodProtector對象進行多次并發更新很可能導致沖突退避,在最壞情況下會給apiserver帶來O(mn2)的負載壓力。

通過RetryBatch機制,對同一對象的請求進行緩沖和批量處理,可緩解這個問題。當某個PodProtector的更新請求正在處理時,所有其他更新嘗試都會被暫存在RetryBatch通道中等待下次請求時同時批量處理。在下次請求時,所有緩沖請求都會基于最新版本的PodProtector執行操作:在配額可用時扣除配額,并向apiserver提交更新后的PodProtector狀態。這些請求在發生沖突時可帶到再下一批次里重試,若配額不足或準入請求超時則會被直接拒絕。

圖片

此方案顯著降低了core集群apiserver的請求量。在字節跳動生產環境中,使用3個webhook副本的配置,批量處理比率約為1:2。理論上,請求速率不應超過正常多集群部署狀態聚合器的狀態更新速率乘以webhook實例數量。

圖片

某機房集群聯邦中開啟Podseidon保護的Pod的刪除準入請求率和實際core集群的PodProtector更新請求率(包括沖突)

02、各種多集群范式的適配

Podseidon對集群管理系統保持中立性。它既可用于單集群部署,也可應用于單主多成員聯邦架構,亦可支持去中心化集群網。

通用配置涉及兩種集群類型:"core"與"worker"。托管PodProtector的集群稱為"core"集群,運行受PodProtector保護pod的集群則稱為"worker"集群。若某集群同時具備這兩種資源,則可兼具兩種類型;也可以同時存在多個核心或工作集群。

圖片

各組件的部署拓撲如下:

  • Generator:每個core集群部署一組實例
  • Aggregator:每個worker集群部署一組實例,連接所有core集群
  • Webhook:全網部署一組實例供所有worker集群使用,連接所有core集群

也可為每個worker集群部署集群內webhook,但這會降低RetryBatch效果,增加core集群控制面負載。

03、受保護場景

憑借端到端設計特性,Podseidon能在多種場景下防止pod被意外刪除。雖然無法杜絕所有問題,但有效地強化了Kubernetes控制面中的單點故障環節:

  • Etcd數據損壞

    core集群根負載對象(如Deployments)丟失:若根對象未顯式設置deletionTimestamp,Podseidon generator不會刪除PodProtector對象。為確保該機制可靠運行,請盡量從根對象而非派生對象創建PodProtector

    core/worker 集群中間對象丟失(如ReplicaSets):盡管這些對象可能被篡改,但只要PodProtector有效,它們就無法影響實際pod

    worker集群pod丟失:參見下文"Kubelet適配"章節

    core集群PodProtector丟失:當前版本未受保護;參見下文"潛在改進"章節

    worker集群ValidatingWebhookConfiguration丟失:無法保護,因這是apiserver與etcd間的直連鏈路(可另外添加apiserver內置準入插件加固webhook存在性檢查)

  • 顯式pod刪除(示例可參見文首):Podseidon全面覆蓋

04、系統集成

Kubelet適配

盡管Podseidon能阻止worker集群中的顯式pod刪除,還有最后一個環節仍需解決:當worker集群發生etcd損壞或配置錯誤(如kubelet連接錯誤apiserver,而該集群恰好有同名節點)時,pod可能被意外移除。由于該問題存在于kubelet與apiserver的直接交互中,保護實際容器不被刪除的唯一可靠方案是修改kubelet代碼。具體而言,kubelet被改造為:僅當明確查看到帶有deletionTimestamp的pod時才會停止容器;若所有者pod憑空消失則保持容器運行。該方案雖然會影響強制刪除等機制,但通過充分的監控和限制強制刪除使用姿勢,實踐證明能有效減少人為誤操作的風險。

05、類似項目

PodUnavailableBudget

OpenKruise提供的類似組件PodUnavailableBudget采用相似原理拒絕超出可用預算的pod刪除操作。Podseidon擴展了多集群支持,提升了吞吐量和性能,并深入強化了容災特性。

06、潛在改進

  • PodProtector informer健壯性:當core集群的PodProtector被異常清除時,webhook實例內存中仍存有副本。通過在generator刪除前顯式標記PodProtector失效并向webhook實例廣播該事件,可在etcd損壞等場景下依然維持有效保護。
  • 多樣化保護條件:除pod就緒狀態外,Podseidon可整合Scheduled或Initialized等pod狀態。雖然滾動控制器聚焦用戶容器報告的就緒狀態,但用戶行為可能導致就緒狀態突變,使監控復雜度提升。采用其他狀態或pod階段能為控制平面穩定性監控提供更可靠的SLI指標

07、使用Podseidon

Podseidon 已在 GitHub 上開源,歡迎大家使用。


責任編輯:龐桂玉 來源: 字節跳動技術團隊
相關推薦

2012-02-13 23:20:18

linux集群高可用

2024-02-27 09:48:25

Redis集群數據庫

2024-08-13 15:42:19

2012-06-21 09:52:55

2023-11-01 07:55:44

K8sKubernetes

2012-08-02 16:46:51

2017-08-24 17:05:06

2013-03-21 11:09:48

網絡管理高可用性集群系統網絡虛擬化基礎架構

2009-06-14 17:53:28

ibmdwWebSphere

2010-11-29 16:22:32

虛擬化高可用性

2012-02-22 09:58:59

虛擬化桌面虛擬化Citrix Xend

2012-09-07 09:57:14

2013-11-19 17:50:33

Linux輔助軟件

2009-04-16 15:34:35

SQL Server

2011-02-17 08:49:49

WebHTMLCSS

2014-05-14 09:43:01

SUSE私有云

2013-08-28 10:30:39

vSphere

2012-09-04 13:43:31

SQL Server

2021-05-24 09:15:42

Go熔斷熔斷器

2023-12-05 09:31:46

數據庫架構
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91精品国产一二三 | 国产成人精品一区 | 精品久久国产 | 亚洲区一区二 | 国产欧美一区二区三区在线看 | 超碰网址| 性一爱一乱一交一视频 | 黄色男女网站 | 成人国产精品一级毛片视频毛片 | 人人干人人看 | 成人在线视频一区二区三区 | 欧美精品成人 | 91亚洲国产成人久久精品网站 | 亚洲精品乱码久久久久久按摩观 | 91在线观看| 久久6视频 | 亚洲精品9999 | 国产视频一视频二 | 男女免费观看在线爽爽爽视频 | 国内91在线 | 五月网婷婷 | 9999视频 | 三a毛片| 国产精品久久久久久久久久久免费看 | 伊人在线视频 | 国产乱码精品一区二区三区中文 | 夜夜草| 成人免费一区二区三区视频网站 | 日韩高清一区 | 91久久久精品国产一区二区蜜臀 | 久久精品一区二区三区四区 | 日韩精品成人网 | 日韩欧美视频在线 | 精品亚洲一区二区三区 | 欧美国产91 | 久久精品国产免费一区二区三区 | 国产日韩欧美另类 | 国产成人午夜精品影院游乐网 | 午夜影院污 | 国产区视频在线观看 | 久久久精品久 |