作者 | 彭南光(光南)
來源 | 阿里巴巴雲原生公眾號
千里之堤,潰於蟻穴。
緒論
不知道大家是否經歷過這樣的情景:突然被用戶告知系統出現問題,然后一臉懵地惶惶然排查修復;或是等到自己發現系統出現故障時,實際已經對用戶造成了嚴重的惡劣影響。
所謂千里之堤,潰於蟻穴。用戶信任的建立是長期而艱難的,然而要摧毀這種信任卻很簡單。一旦出現上述問題,不僅極大影響用戶使用體驗,同時會給用戶留下一個這個產品/團隊不可靠的印象,喪失用戶對產品/團隊長期好不容易積累下來的信用資本,未來再想建立這樣的信任關系就很難了。
這也是為什么我們說快速發現問題的能力如此重要的原因,只有先做到快速發現問題,才能談怎樣排查問題、如何解決問題。
那么怎樣才能在復雜的大規模場景中,做到真正先於用戶發現問題呢?下面我會帶來我們在管理大規模 ASI 集群過程中對於快速發現問題的一些經驗和實踐,希望能對大家有所啟發。
注:ASI 是 Alibaba Serverless infrastructure 的縮寫,是阿里巴巴針對雲原生應用設計的統一基礎設施。有興趣可以閱讀:《揭開阿里巴巴復雜任務資源混合調度技術面紗》。
背景
1. 復雜的場景和曾面臨的困境
我們所管理的大規模 ASI 集群場景非常復雜,這為我們的工作帶來了極大挑戰,任何一個場景處理不慎就有可能導致意料之外的傷害擴大化。
-
從組件維度看,我們目前有幾百個組件,每年有幾萬次的組件變更。頻繁的組件變更如何在穩定性和效率之間取得權衡,怎樣讓變更時更穩定,怎樣讓灰度更確信,從而降低爆炸半徑?
-
從集群維度看,目前有上千個集群和海量節點,碰到的集群/節點問題較多,監控鏈路覆蓋比較繁復,怎樣讓集群運行時更加可信?
-
從二方用戶和業務場景看,我們支持了大量的集團二方用戶,同時業務場景也非常復雜,怎樣保證各有特色的業務場景都能得到一致的細心關照?
2. 問題預判和解決思路
基於長期的集群管理經驗,我們有如下預設:
-
數據監控作為正向鏈路,無法無死角覆蓋所有場景。即使鏈路中各個節點的監控數據正常,也不能 100% 保證鏈路可用。
- 集群狀態每時每刻都在變化,各個組件也在不停地更新升級,同時鏈路上的每個系統也在不停的變更,監控數據的覆蓋永遠是正向的追趕,只能逼近 100% 全覆蓋而無法完全達到。
- 即使整個集群鏈路中所有組件/節點的監控數據都正常,也不能保證集群鏈路 100% 可用。就如同業務系統一樣,看上去都是可用的,沒有問題暴露。但只有通過全鏈路壓測實際探測過整個鏈路后,才能得到實際可用的結論。
- 你要正向證明一個東西可用,需要舉證無數的例子。而如果要反向證明不可用,一個反例就夠了。數據監控鏈路只能逼近全覆蓋,而無法保證真正全覆蓋。
-
大規模場景下,數據無法達到 100% 的完全一致性。
- 當集群規模足夠大時,數據的一致性問題將會愈加顯現。比如全局風控組件是否全集群鏈路覆蓋?相關流控配置是否全集群鏈路推平?pod 主容器時區是否與上層一致?集群客戶端節點證書是否有即將過期?等等問題,一旦疏忽,將有可能釀成嚴重的故障。
只有彌補上述兩類風險點,才能有底氣真正做到先於用戶發現問題。我們解決上述兩類風險的思路分別是:
- 黑盒探測
- 所謂黑盒探測,既模擬廣義上的用戶行為,探測鏈路是否正常。
- 定向巡檢
- 所謂巡檢,既檢查集群異常指標,找到已有或可能將存在的風險點。
基於以上思路,我們設計並實現了 KubeProbe 探測/巡檢中心,用於彌補復雜系統的正向監控的不足,幫助我們更好、更快地發現系統風險和線上問題。
設計
黑盒探測和定向巡檢
1)黑盒探測
不知道你是否也經歷過一條鏈路上各個系統監控數據都正常,但是實際鏈路流程就是跑不通。或者因為系統變化快,監控覆蓋不到 100% 的場景總是會有遺漏,導致影響到了用戶卻沒有報警,對用戶沒有實質影響卻報警頻發從而疲於奔命。
如果一個系統開發者自己都不使用自己的系統,那么怎么可能先於用戶發現系統問題呢?所以要先於用戶發現系統問題,首先我們自己就得先成為用戶,而且一定是使用最多,了解最深,無時無刻不在使用和感知系統狀況的用戶。
所謂黑盒探測,就是讓自己成為自己的用戶,模擬廣義"用戶"的行為去對集群/組件/鏈路等待待測對象做探測。注意,這里的"用戶"並不僅僅是狹義上使用系統的同學,而是廣義用戶。比如,etcd 的"用戶"是 APIServer,而 ASI 的"用戶"可能是某個通過 APIServer 操作集群的同學,也可能是 Normandy 發起的發布/擴容/縮容操作。
我們希望 KubeProbe 能在 變更時(監聽到集群狀態發生變化/組件變更/組件發布/系統升級等等事件)/運行時(周期,高頻)/故障恢復時(手動),通過周期/事件觸發/手動觸發,執行各種不同類型的黑盒探測,第一時間感知組件/集群/鏈路的可用性。
以 etcd 集群的可用性來舉例,我們可以實現一個探測用例,邏輯是對 etcd 做 create/get/delete/txn 等等操作,並記錄每個操作的成功率/消耗時間,當成功率低於 100% 或消耗時間超過容忍閾值后,觸發報警。我們將周期高頻運行這個 etcd 的探測用例,同時對於 etcd 集群的任何變更都會發出一個事件 event 觸發這個 etcd 探測立即運行,這樣就能盡量確保第一時間發現 etcd 可用性故障了。同時,當 etcd 集群因為某些原因不可用了,我們也可以通過手動觸發等其他方式做探活,也能第一時間得到是否恢復的信息。
2)定向巡檢
在大規模集集群/系統場景下,數據一致性是一定會面臨的難題。數據不一致,將導致一些隱患,可能會在未來引發某些確定性的故障。
相比於黑盒探測面對的未知故障場景,定向巡檢的目標是對集群的已知風險點做掃描。
我們希望 KubeProbe 能夠定期對整個集群/鏈路做定向的巡檢,找出這些數據不一致的點,判斷數據不一致是否可能引發風險,從而能夠防患於未然,治未病。
比如 etcd 冷熱備多集群覆蓋不全,可能導致集群遇到故障無法快速恢復。那么我們就定期對 etcd 的冷熱備覆蓋情況做定向巡檢,找出沒有覆蓋推平的集群,並告警。比如 集群風控系統沒有全集群鏈路覆蓋,限流配置沒有全集群鏈路推平,可能導致某些故障場景引發集群全面崩潰,我們定期對風控配置全網掃描,判斷是否可能導致故障,找出這些隱藏的已知風險點並告警。
實現
1. 架構
1)基本架構
KubeProbe 的基本實現架構大致如下圖,KubeProbe 中心端配置集群/集群組與巡檢/探測用例/用例集之間的關聯關系,負責對集群做具體某次探測實例下發。某個具體的巡檢/探測用例下發到具體某個集群將使用用例的鏡像創建一個 pod,這個 pod 里會執行若干巡檢/探測邏輯,當執行完成后會回調中心端回寫本次巡檢/探測結果。其具體結果在中心端統一展示/告警,並提供給其他消費者消費(如支持 ASIOps 平台的發布阻斷)。
2)高頻架構
除了上述的基本架構之外,我們對於高頻探測用例(既探測周期短,觸發頻率需要非常頻繁,甚至保持無縫探測的場景)設計了一套集群內的分布式常駐探測架構,該架構通過集群內的 ProbeOperator 組件 watch 自定義對象 probeConfig 的變化,在集群內創建一個常駐的探測 pod,將持續無間斷的運行探測邏輯,實現接近無縫的持續探測,並將結果通過去噪/令牌桶限流等處理后,上報中心端,共給其他消費者消費。
2. KubeProbe 探測/巡檢用例管理
所有的探測/巡檢用例都使用統一的 git 倉庫管理,由我們提供一個統一的 client 庫,client 庫最核心提供的方法主要有兩個。
KPclient "gitlab.alibaba-inc.com/{sigma-inf}/{kubeProbe}/client"
// 報告成功
// 此方法會向KubeProbe報告本次巡檢結果為成功
KPclient.ReportSuccess()
os.Exit(0)
// 報告失敗
// 報告方法會向KubeProbe報告本次巡檢結果為失敗,並且失敗信息為 `我失敗啦`
KPclient.ReportFailure([]string{"我失敗啦!"})
os.Exit(1)
我們可以通過提供好的 Makefile 將這個用例打包成鏡像,錄入 KubeProbe 中心端就可以對集群做配置和下發了。將具體巡檢/探測邏輯和 KubeProbe 中心管控端解耦,可以靈活而又簡便的讓更多的二方用戶接入自己的特殊巡檢/探測邏輯。
目前已經使用的探測/巡檢用例包括:
- 通用探測:模擬 pod / deployment / statefulset 生命周期探測集群整條管控鏈路。
- etcd 黑盒探測:模擬 etcd 的基本操作,探測元集群中各 etcd 狀態。
- 金絲雀探測(感謝質量技術同學的大力支持):模擬用戶使用 ASI 的部署場景,實現金絲雀應用的全鏈路模擬發布/擴容/縮容。
- Virtual cluster 探測:探測 vc 虛擬集群的管控鏈路狀態。
- 聯邦鏈路探測:探測聯邦控制器相關鏈路的狀態。
- 節點通用探測:在集群每個節點上模擬調度一個探測 pod,探測節點側鏈路狀態。
- ASI 客戶端/服務端證書巡檢:檢查客戶端/服務端證書有效性以及到期時間是否已超過告警閾值。
- 全局風控限流巡檢:檢查各 ASI 集群是否已經推平並開啟 KubeDefender 全局限流風控配置。
- ······
3. KubeProbe 中心端管控
編寫完成探測/巡檢用例,並打包上傳好鏡像后,就需要在 KubeProbe 中心端注冊這個用例模版,即將鏡像注冊進 KubeProbe 中心端的數據庫中。
我們可以通過"渲染配置"參數傳入一些指定的 env 環境變量到巡檢/探測 pod 中,用於執行不同的業務邏輯,實現同一個用例模版生成多個用例。
最后通過統一的配置管控將用例和集群做綁定,配置對應的參數,執行各種下發邏輯。
同時,我們還在 KubeProbe 中心端做了大量權限安全管控,臟數據資源清理以及提效增速的工作(比如采用完全以 ownerreferences 的巡檢/探測用例資源自動清理能力等等),這里不再贅述。
4. 打通發布 / 變更阻斷
我們打通了 KubeProbe 探測與發布變更的關聯,當對應集群中有任何變更發生時(如某組件在做發布),我們會自動通過相應的事件觸發此集群綁定的所有巡檢/探測用例,檢查集群狀態是否正常。如果探測失敗,則會將變更阻斷,降低爆炸半徑,提升集群變更時穩定性。
5. 為什么不使用 Kuberhealthy
社區有一個 Operator 叫 Kuberhealthy 也可以做類似的事情,我們曾經也考慮采用,並且深度使用過 Kuberhealthy 和參與 kuberhealthy 的社區貢獻,最終得出不適合的結論,主要原因是對大規模集群的支持較弱,同時高頻調用時主流程卡死問題比較嚴重,不支持事件/手動單次觸發特性,不支持統一上報數據中心等等,最終選擇了自研自建的方式,目前來看是一個比較正確的選擇。
一點小結果
KubeProbe 上線以來,實現探測/巡檢用例幾十個,在集團數百個 ASI 集群中運行千萬余次,主動發現集群故障和問題百余次,其中某些小故障一旦沒有發覺很有可能升級成為大故障,有效降低了系統風險。同時打通了變更/發布系統,提升了變更穩定性。並且在特殊故障時,多次先於業務方提前發現問題,更早地推動解決問題,客觀降低了故障損失。
下面是一個具體例子:
- 我們會接收到每個集群中各個組件的發布事件,由發布事件觸發我們會在對應集群中運行相關的巡檢/探測,比如調度一個定向的 pod 到某個節點組件發布的節點上去。我們發現 kube-proxy 的發布會導致節點的短暫不可用,調度上去的 pod 無法創建成功,從簡單的返回/日志/集群事件上看不出具體的問題,並且持續復現。經過深入排查,得知是 kube-proxy 的問題,存在 netns 泄露。運行久了會泄露,當 kube-proxy 重啟的時候,內核要清理 netns,會卡一段時間來清理,導致節點一段時間鏈路不通,pod 可以調度上去但是運行不起來,從而后續推進了 kube-proxy 的問題修復。
發現問題之后
1. KubeProbe 和數據監控的告警區別
KubeProbe 所面對的場景和數據監控不同,更多偏向於鏈路探測。
比如,監控告警一般的告警可能如下:
- xx容器內存使用率 99%
- webhook 雙副本全部掛掉了
- apiserver 三副本全部宕機了
這些告警,往往內容中就包含了具體的故障點,而 KubeProbe 的鏈路探測告警就有很多不一樣,比如:
- Statefulset 鏈路探測失敗,Failed to create pod sandbox: rpc error: code = Unknown
- etcd 全流程黑盒探測失敗,context deadline exceeded
- CloneSet 擴容失敗,connect: connection refused
這些 KubeProbe 的告警往往比較難從字面看出到底這次巡檢/探測是為什么失敗了,我們往往需要根據相關的用例返回日志,巡檢/探測 pod 日志,KubeProbe 相關集群事件綜合排查,定位失敗原因。
2. 根因定位
我們以比較混沌的 KubeProbe 探測失敗告警作為線索,構建了一套 KubeProbe 自閉環的根因定位系統,將問題排查的專家經驗下沉進系統中,實現了快速和自動的問題定位功能,一個簡單的定位規則如下:
我們會通過普通的根因分析樹以及對失敗巡檢探測事件/日志的機器學習分類算法(持續開發投入中),為每一個 KubeProbe 的探測失敗 Case 做根因定位,並通過 KubeProbe 內統一實現的問題嚴重性評估系統(目前這里的規則仍比較簡單),為告警的嚴重性做評估,從而判斷應該如何做后續的處理適宜,比如是否自愈,是否電話告警等等。
3. Oncall 和 ChatOps
有了上面提到的根因定位以及告警嚴重性評估系統,我們使用了 nlp 告警機器人,實現了一套自動化的 Oncall 系統以及 ChatOps,展示一些使用的 case 如下,通過 ChatOps 和 Oncall 機器人,極大的降低了問題處理的復雜度,盡量用技術的手段解決重復的問題。
我們仍在路上
以上是我們在管理大規模 Kubernetes 集群中的一點經驗,也解決了一些常見的問題,希望能對大家有所幫助。同時,這些工作在阿里雲海量規模的場景下還需要持續打磨,我們仍在路上,並且將持續在路上。