轉(zhuǎn)轉(zhuǎn)容器日志采集的演進之路
1 裸金屬時代
在裸金屬時代,轉(zhuǎn)轉(zhuǎn)業(yè)務(wù)日志的采集端由大數(shù)據(jù)部門二次開發(fā)的scribe+flume組成。當一臺服務(wù)器上部署了A服務(wù)后,如果需要對該服務(wù)進行日志采集,需要經(jīng)過以下幾個步驟。
- 由運維部門提交工單,申請在該服務(wù)器上,對A服務(wù)日志進行采集
- 工單審核通過
- 在該服務(wù)器上自動化部署日志采集組件scribe+flume
- 通過工單中該臺主機的日志采集申請數(shù)據(jù),渲染出scribe配置文件,指定該服務(wù)的日志輸出目錄為采集目錄
- scribe服務(wù)根據(jù)自身配置文件,采集目錄下的日志文件數(shù)據(jù),發(fā)送到flume的對應(yīng)端口,最后由flume將日志分發(fā)至kafka,hdfs等組件
在裸金屬時代,服務(wù)的部署節(jié)點的變化并不大。新服務(wù)上線,給該服務(wù)分配裸金屬服務(wù)器進行部署,一般情況下,很長一段時間,該服務(wù)的部署節(jié)點都不會發(fā)生任何變更。只有在活動大促期間對該服務(wù)的擴容,以及某臺裸金屬服務(wù)器硬件的損壞,才會導致部署在該主機上的服務(wù),產(chǎn)生部署節(jié)點上的變更。
也正是由于在裸金屬時代,服務(wù)部署節(jié)點的超強粘性,轉(zhuǎn)轉(zhuǎn)日志采集的workflow運轉(zhuǎn)正常。
裸金屬時代日志采集workflow
2 容器時代
2016年,容器技術(shù)在中國開枝散葉,鋪天蓋地的技術(shù)文獻在網(wǎng)絡(luò)上流轉(zhuǎn)。轉(zhuǎn)轉(zhuǎn)是在2018年開始邁入到容器時代。
裸金屬到容器時代的轉(zhuǎn)變并不容易,轉(zhuǎn)轉(zhuǎn)選擇了一條幾乎是“最穩(wěn)健”的路來完成這場技術(shù)革新。這條“最穩(wěn)健”的路有幾點要求。
- 服務(wù)部署形式變化對業(yè)務(wù)方“無感知”,延用裸金屬時代的發(fā)布系統(tǒng),兼容容器服務(wù)的發(fā)布與管理
- 服務(wù)器/容器終端登錄對業(yè)務(wù)方“無感知”,延用裸金屬時代的堡壘機登錄形式,兼容容器環(huán)境登錄
- 延用裸金屬時代的整體日志處理方式
- and so on
本篇文章我著重討論這場變革中的日志采集系統(tǒng)。由于日志處理體系是一個龐大且復雜的體系,在容器時代對其進行云原生革命,為了推進容器化,先要花大力氣打造日志采集基礎(chǔ)設(shè)施, 從時間和成本上,對于轉(zhuǎn)轉(zhuǎn)來說都是無法接受的。
容器服務(wù)運行特點與條件制約
- 服務(wù)容器跨節(jié)點調(diào)度頻繁
- 微服務(wù)框架已標準化日志輸出目錄
- 容器內(nèi)的服務(wù)僅有文本日志輸出,沒有stdout
- 原有的裸金屬時代日志采集流程無法動搖
- 容器運行后會將標準化的日志輸出路徑掛載到宿主機目錄
2.1 log-pilot + flume 二次開發(fā)方案
當時的大數(shù)據(jù)團隊分析了容器服務(wù)運行的特點,針對該特點,打造了一套基于裸金屬時代的日志采集兼容方案。在原有日志組件及功能都完全不變的前提下,基于log-pilot+flume二次開發(fā)了一套日志轉(zhuǎn)儲引擎。
利用log-pilot的容器自動發(fā)現(xiàn)功能,提取出需要采集日志的容器元數(shù)據(jù)信息,并渲染出一個 flume 的配置文件,由 flume 將容器內(nèi)的日志,采集后轉(zhuǎn)儲到本地宿主機的一個目錄下,最后由二次開發(fā)后的 log-pilot 更新宿主機上的scribe配置文件,并重啟 scribe 進程,這樣即對接上了之前裸金屬時代的后續(xù)日志采集流程。
log-pilot日志采集方案
為了兼容裸金屬時代不可動搖的日志采集地位,大數(shù)據(jù)部門貢獻了轉(zhuǎn)轉(zhuǎn)過渡到容器化的第一代日志采集系統(tǒng)。
該系統(tǒng)初期運轉(zhuǎn)良好,但隨著轉(zhuǎn)轉(zhuǎn)服務(wù)容器化率的提升,日志體量越來越大,這種日志的轉(zhuǎn)儲模式直接導致了日質(zhì)量接近翻番,不僅磁盤容量受到巨大考驗,日志保留周期從30天逐漸縮短到了3天,而且 CPU iowait 也開始飆升,集群節(jié)點每天的 iotuil 長期在 90% 以上,繁重的 IO 負擔已經(jīng)成了阻礙業(yè)務(wù)進一步容器化不容忽視的阻礙。在保留裸金屬時代日志采集流程不變的基礎(chǔ)上,運維針對容器場景做了進一步優(yōu)化。
2.2 ByteCompass
運維自研的“日志指南者”,主要目的為剔除掉 log-pilot + flume 這個日志轉(zhuǎn)儲組件。少了一次日志的讀取和寫入,磁盤空間和IO壓力會驟減。ByteCompass 為運維全自研組件,以 systemd 管理運行在宿主機。
bytecompass日志采集方案
ByteCompass 借鑒了 log-pilot 感知容器變化的原理,watch 了 dockerd 的 api 接口,實時接收容器變化的事件信息。當有容器新增時,判斷其是否帶有日志采集標識,如果有,則進一步從容器配置的環(huán)境變量信息中讀取日志采集的元數(shù)據(jù)信息,最后將該容器信息根據(jù)模板渲染成新的 scribe.conf 配置文件,直接覆蓋宿主機中的該文件,并對該宿主機的 scribe 進程執(zhí)行重啟操作。
經(jīng)過 ByteCompass 對日志采集的優(yōu)化,剔除掉了冗余的日志轉(zhuǎn)儲,無縫銜接了容器技術(shù)棧中的服務(wù)日志特征和裸金屬時代的日志采集流程。與裸金屬時代日志采集流程對比如下:
裸金屬時代與bytecompass日志采集對比
ByteCompass 改造后的日志采集,實現(xiàn)了集群節(jié)點平均 iowait 從 10% 降到 1%,波峰從 25%+ 降低到 3%-;ioutil 全天平均值下降到 7%以下,降幅達到92%;本地日志保留時間也從3天恢復到了7天以上。
3 云原生時代
在解決了磁盤瓶頸后,轉(zhuǎn)轉(zhuǎn)的容器化進程加速進行。容器時代為了兼容裸金屬時代遺留的用戶習慣,對容器環(huán)境做了很大程度上的妥協(xié)。隨著服務(wù)容器化的逐漸深入,轉(zhuǎn)轉(zhuǎn)開始從容器時代這個過渡階段,逐步開啟云原生時代。
以上裸金屬時代和容器時代的日志是按需采集,只有業(yè)務(wù)申請了日志采集,才會將日志采集走并做數(shù)據(jù)分析和處理。用戶查詢 info 及 error 日志排錯,依然是很原始的登錄到裸金屬服務(wù)器上或登錄到容器中,或通過日志查詢平臺,直接檢索容器服務(wù)所在物理機掛載到 hostPath 中的日志文件。
云原生時代給日志采集提出了更高的要求,在保留現(xiàn)有日志分析的基礎(chǔ)之上,還要實現(xiàn)全量日志的集中存儲與檢索。以及考慮到未來 k8s 版本對 dockerd 依賴的剔除和更靈活的宿主機擴縮容,轉(zhuǎn)轉(zhuǎn)運維開始規(guī)劃全新的日志采集系統(tǒng)以適應(yīng)云原生時代的需求。
由于轉(zhuǎn)轉(zhuǎn)容器默認會將日志目錄掛載到宿主機,開源通用的文本文件采集方案無法將 pod 元數(shù)據(jù)信息附加到日志中,所以轉(zhuǎn)轉(zhuǎn)運維依托于 filebeat 自研了一個 filebeat 的 “助手” --- fb-advisor
3.1 轉(zhuǎn)轉(zhuǎn)方案(hostPath volume場景) fb-advisor
轉(zhuǎn)轉(zhuǎn)日志采集方案
受益于轉(zhuǎn)轉(zhuǎn)內(nèi)部的容器規(guī)范,不管容器的日志是否需要采集,容器的日志目錄都是以 hostPath 機制掛載到宿主機目錄上的。fb-advisor 為轉(zhuǎn)轉(zhuǎn)自研組件,watch kube-apiserver 的 pod api,實時接收本節(jié)點的 pod 事件。如果為新增 pod 事件,則讀取 pod 元數(shù)據(jù)信息,識別 pod 中日志目錄掛載的宿主機路徑,將其保存在 filebeat 的配置文件,放在 config.d 目錄下。filebeat 配置自動 reload 即可。
日志采集后,集中生產(chǎn)到 kafka 中間件,再由自研的消費者將日志處理后完成數(shù)據(jù)的分發(fā),從而替換掉 scribe + flume “黃金組合”。
以下為與 ByteCompass 方案的對比
fb-advisor vs bytecompass
3.2 通用方案(hostPath volume場景)
該通用方案同時適用于 hostPath volume 場景和容器內(nèi)默認文件系統(tǒng)場景的文本文件日志的采集,并同時附加 pod 元數(shù)據(jù)信息。
filebeat 中的 add_kubernetes_metadata processor,是專門用來給日志附加 pod 元數(shù)據(jù)信息用的插件。
- in_cluster: 是否運行在容器環(huán)境中
- host: 主機名
- kube_config: kubeconfig 文件絕對路徑
- namespace: 監(jiān)聽的命名空間,如果不寫,默認監(jiān)聽所有命名空間
- default_indexers.enabled: 禁用默認的 indexers
- default_matchers.enabled: 禁用默認的 matchers
- sync_period: 指定列出歷史資源的超時時間
- indexers: 使用 pod 元數(shù)據(jù)為每個 pod 創(chuàng)建唯一標識符
- indexers.pod_uid: 使用 pod 的 UID 標識 pod 元數(shù)據(jù)
- matchers: 構(gòu)造與索引創(chuàng)建的標識符匹配的查找鍵
- matchers.logs_path: 使用從存儲在該字段中的日志路徑中提取的標識符查找 pod 元數(shù)據(jù)
- matchers.logs_path.logs_path: k8s 數(shù)據(jù)目錄絕對路徑
- matchers.logs_path.resource_type: 根據(jù) pod UID 為查找鍵進行查找
該通用方案中,add_kubernetes_metadata 負責連接 kube-apiserver 獲取元數(shù)據(jù)信息,并在日志采集路徑中 /var/lib/kubelet/pods/<pod UID>/volumes/<volume name>/... 提取 pod UID 信息,并以此為鍵,進行元數(shù)據(jù)查找,找到元數(shù)據(jù)后,將其元數(shù)據(jù)信息附加到日志條目中。
3.3 對比
對比轉(zhuǎn)轉(zhuǎn)方案和通用方案,主要區(qū)別在于轉(zhuǎn)轉(zhuǎn)方案的定制化程度更高,可以自由選擇需要附加的元數(shù)據(jù)信息,而通用方案默認會附加上容器所有的 label 信息。
從日志采集安全性來說,轉(zhuǎn)轉(zhuǎn)方案也略勝一籌,轉(zhuǎn)轉(zhuǎn)利用日志目錄掛載到宿主機的特性,將 filebeat 的日志采集路徑直接指向宿主機路徑。這樣的日志采集,脫離了 pod 數(shù)據(jù)目錄跟隨 pod 生命周期的特點,避免由于某些問題導致日志采集速率嚴重低于日志產(chǎn)出速率,且 pod 被重新調(diào)度后,數(shù)據(jù)目錄被清理而導致的日志數(shù)據(jù)丟失。
4 總結(jié)
云原生時代的日志采集方案百花齊放,沒有絕對通用的解決方案,沒有絕對完美的解決方案,只有依據(jù)自身實際特點,最合適的解決方案,希望本篇文章能帶給讀者關(guān)于日志采集方案中的一些不同思路。
轉(zhuǎn)轉(zhuǎn)的日志采集從裸金屬時代的 scribe + flume,到容器時代的 log-pilot + flume + scribe + flume,再到 ByteCompass + scribe + flume,最后到云原生時代的 filebeat + fb-advisor,徹底擺脫了裸金屬時代日志采集的影子,并且脫離了 dockerd 的依賴,開始朝著更加云原生的方向繼續(xù)披荊斬棘。
本篇文章僅介紹了日志采集的宏觀 workflow,內(nèi)部細節(jié)有其內(nèi)部特殊性,無法一一展現(xiàn),歡迎留言進行深入的細節(jié)討論。
關(guān)于作者
呂瑞,轉(zhuǎn)轉(zhuǎn)運維,主要負責轉(zhuǎn)轉(zhuǎn)容器技術(shù)方向