从日志入手,保障 Kubernetes 稳定性
作者 | 悟鵬、沉醉
來源 | 阿里巴巴云原生
頭圖 | 下載于視覺中國
不論對于軟件的用戶還是開發(fā)者,日志都是很重要的信息源。日志可以用來表征軟件的運行狀態(tài),在軟件運行不符合預期時提供豐富的信息,也可以用在開發(fā)階段調(diào)試軟件,方便定位問題。
軟件的生命周期涉及到開發(fā)和運行兩個階段,日志的生成是在軟件的開發(fā)階段,日志的使用集中在軟件的運行階段。
在開發(fā)階段規(guī)范化日志,有助于運行階段通過標準化方法分析日志、配置日志監(jiān)控和告警。
在運行階段通過標準化方法使用日志,有助于低成本把握程序的運行態(tài)行為,及時感知異常,促進開發(fā)階段的迭代效率。
在軟件的生命周期中,運行階段時長占比會遠大于開發(fā)階段,即對日志的使用時長會遠大于開發(fā)階段寫日志邏輯的時長。在開發(fā)階段應用良好的日志規(guī)范,會對軟件生命周期的正常運行和快速迭代帶來很大幫助:
復雜度分析
程序中的元素可以抽象為兩部分:自身邏輯,依賴。兩類元素之間的交互為:自身邏輯閉環(huán),自身邏輯與依賴交互。
從長期角度來看,交互環(huán)節(jié)出問題的概率會比自身邏輯出問題的概率高,因此要重點關注交互環(huán)節(jié)的日志邏輯。
同時,對日志的管理需要意識到 誰會使用這些日志,通常有 4 類角色:
用戶
維護者
安全人員
審計人員
用戶從黑盒角度使用軟件,通過日志了解軟件當前的運行狀態(tài),關注重點是軟件正常的狀態(tài)。
維護者從白盒角度使用軟件,開發(fā)角色通過日志調(diào)試軟件,SRE 角色通過日志及時感知軟件的異常狀態(tài),并通過日志上下文分析異常原因。
安全人員通過分析日志,了解惡意登錄、異常刪除等風險。
審計人員通過審計日志、應用日志,確認業(yè)務、架構(gòu)的合規(guī)性。
根據(jù)上述不同的使用場景,我們可以梳理出幾類日志類別,進一步增強開發(fā)和運行階段對日志的理解:
類別 | 語義 |
應用日志 | 應用白盒層面的信息,用來理解應用內(nèi)部狀態(tài)變化 |
審計日志 | 應用黑盒層面的信息,用來理解應用服務狀態(tài) |
開發(fā)階段
1. 最佳實踐
理解了日志使用者關注的重點后,開發(fā)階段寫日志時,推薦使用如下最佳實踐:
使用 structured logs
不使用 format strings
使用 info 和 error 表征日志級別
info 又可細化為多個級別:0~10,信息的重要性依次降低 (也可以參考《Kubernetes: sig-instrumentation/logging.md》)
0:用戶想要看到的信息
1:維護者關注的白盒行為信息
10:維護者調(diào)試用的信息
使用具有過濾器能力的 log lib,通過 logger 自動過濾敏感信息
參見《KEP: Kubernetes system components logs sanitization》
日志通過 stdout/stderr 輸出,關閉不必要的文本日志
避免額外的磁盤占用、IO 消耗、日志清理任務的維護等
對于 golang,可以考慮使用klog 作為 logger 實現(xiàn)。
2. FAQ
1)為什么使用 structured logs?
structured logs 是一種結(jié)構(gòu)化的日志格式,結(jié)構(gòu)如下,其中 msg 表征通用的事件,多對的 k=v 用來具化事件:
msg k=v k=v ... k=v
示例:
"Pod status updated" pod="kube-system/kubedns" status="ready"
對于開發(fā)階段,structured logs 通過固化的結(jié)構(gòu)和字段語義,協(xié)助開發(fā)者思考程序邏輯狀態(tài),有助于進一步控制程序復雜度和理解程序邏輯。
對于運行階段,structured logs 中的 k 天然具備索引的屬性,便于進行查詢和分析。也可以考慮將 msg 規(guī)范化,增加事件語義,通過限制 msg 語義來增強 msg 的作用。
2)為什么不使用 debug/warning/critical/fatal?
通過減少日志類型,降低使用和維護負擔。
debug 可以融入到 info 級別。
warning/critical 對于用戶和維護者都是模糊的詞,對于要采取的行動通常不具備指導意義。warning/critical 和 error 類似,表征程序運行過程中出現(xiàn)了預期外的現(xiàn)象,此時程序要么自動處理,要么交由外部人工介入判斷。若由程序自動處理,那么用戶和維護者感知到這類現(xiàn)象即可,info 可以滿足。若需要交由外部人工介入,那么 error 就可以滿足。對于問題的嚴重性,可放在運行階段,通過異常具體的信息來表征,如 ServiceUnavailable、Unauthorized 等。
fatal 是將 error 和 panic 兩類邏輯封裝了起來,在開發(fā)過程中可能會帶來執(zhí)行邏輯上的不清晰,如決定是否 panic 的邏輯需要放在最頂層邏輯中,若在頂層邏輯之下調(diào)用 fatal,可能會帶來資源泄露、程序運行復雜度增加等問題。
3)為什么不使用 format strings?
format strings 是形如如下的結(jié)構(gòu):
klog.V(4).Infof("Got a Retry-After %ds response for attempt %d to %v", seconds, retries, url)
這種結(jié)構(gòu)將通用事件和具體內(nèi)容耦合在一起,不利于開發(fā)階段降低理解程序邏輯的成本,也不便于使用階段通過標準化的方式進行查詢、分析,增加日志的使用成本。
一種改善方式:
klog.V(4).InfoS("got a retry-after response when requesting url", "attempt", retries, "after seconds", seconds, "url", url)
4)為什么要使用具有過濾器能力的 log lib?
開發(fā)過程中,可能會由于疏忽而將敏感信息輸出到日志中,如密碼、token 等信息。為了避免敏感信息泄露,需要加強 code review,同時也可以考慮在 logger 中配置過濾器,自動進行敏感信息的過濾,參見《KEP: Kubernetes system components logs sanitization》。
對于 golang,可以考慮使用klog 作為 logger 實現(xiàn),并配合Kubernetes/component-base: sanitization?進行使用。
運行階段
1. 最佳實踐
運行階段是對日志的使用,包括如下 4 個階段:
采集
查詢
分析
告警
由于日志服務對程序的運行以及后續(xù)的運營極為重要,建議采用托管型的日志產(chǎn)品來滿足運行階段對日志的使用需求,如阿里云的 SLS 產(chǎn)品。
若在多個 region 部署集群,且集群的組件相同,在使用日志產(chǎn)品時,需要確保每個 region 中日志項目名稱規(guī)則的一致性。以阿里云 SLS 產(chǎn)品為例,若需要分別收集多個 region 的日志,則 project、logstore 的名稱需要在多個 region 中保持相同的規(guī)則,目的是便于通過統(tǒng)一的方法對不同集群的日志做查詢和分析。
通常情況下,日志產(chǎn)品會提供上述 4 個階段的服務,具體的使用方法可以參見對應日志產(chǎn)品的文檔,下述針對告警做重點分析。
告警
告警要滿足如下目標:
覆蓋面全
關鍵告警及時感知
基于開發(fā)階段的日志規(guī)范,可對 error 級別的告警做統(tǒng)一告警,將告警信息統(tǒng)一到低優(yōu)先級的通知渠道,如表征普通告警的釘釘群。
若要及時感知到關鍵告警,需要從如下 2 個方面入手:
定義「關鍵告警」特征
分級告警,與相應的通知渠道結(jié)合
定義「關鍵告警」的特征是個長期、持續(xù)完善的過程,有 通用關鍵告警 和 業(yè)務關鍵告警。
通用關鍵告警 與業(yè)務耦合度小,如機器級別的關鍵告警 (宕機、內(nèi)存壓力大、load 過高等)、托管服務的關鍵告警 (master 組件 panic/OOM、master 組件內(nèi)存壓力大等),這部分告警配置可以作為基礎服務,作為集群交付的一部分。
業(yè)務關鍵告警 與業(yè)務耦合度大,需要與業(yè)務長期維護,重點關注「業(yè)務交互環(huán)節(jié)」的告警。
通知渠道通常會有如下幾類:
IM 群 (如釘釘群等)
短信
電話
webhook
這些通知渠道對人觸達的及時性不同,電話觸達性最好,短信其次,然后是 IM 群。webhook 本質(zhì)上是條通道,可以對接不同的 IM 群或短信、電話渠道。
推薦如下三種告警級別:
告警級別 | 語義 | 通知渠道 |
一級 | 立即處理 | 一級告警 IM 群、短信、電話 |
二級 | 需要重點關注,但不用立即處理 | 二級告警 IM 群、短信 |
三級 | 通用異常,用來盡可能覆蓋異常、幫助進行告警溯源 | 三級告警 IM 群 |
配置告警是個長期、不斷迭代的過程,為了有助于告警有效性的迭代,配置每條告警時,可以考慮使用如下表格,規(guī)范化每條告警的配置,并深入思考告警配置的有效性:
關鍵問題 | 分析 | 備注 |
集群級別? | ||
組件級別? | ||
異常信息源? | ||
精確異常 特征? | ||
模糊異常 特征? | ||
爆炸半徑? | ||
告警級別? | ||
已覆蓋的范圍 (集群/組件)? |
2. FAQ
如何預先配置未模擬出的異常?
業(yè)務依賴的 OpenAPI/SDK/Lib 等通常都會有錯誤碼列表,如阿里云:API 錯誤中心、Lib 中的 errors 文件等。可以基于該已知信息,枚舉依賴的 OpenAPI / SDK 中對業(yè)務有明顯負面影響的狀態(tài)碼做分級告警,如 ServiceUnavailable / Forbbiden / Unauthorized 等。
參考鏈接:
klog
logr
blog: Lets talk about logging
阿里云 SLS 產(chǎn)品官網(wǎng)
阿里云:API 錯誤中心
Kubernetes: sig-instrumentation/logging.md
KEP: Kubernetes system components logs sanitization
Kubernetes/enhancements: Kubernetes system components logs sanitization #1753
Kubernetes: component-base
總結(jié)
以上是生活随笔為你收集整理的从日志入手,保障 Kubernetes 稳定性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 腾讯智慧出行和现代汽车集团创新中心(北京
- 下一篇: 最良心的 chrome 插件可以良心到什