前文:
Logging Operator 的文章去年拖更很久了蔑担,原以為不會再有進度心墅,不過最近在自己的KubeGems項目中遇到處理日志可觀察性部分的需求時枷遂,又重新研究了下它漆枚,于是有了本系列的第三篇湿蛔。
Logging Operator是BanzaiCloud下開源的一個云原生場景下的日志采集方案榆骚。它在 2020 年 3 月的時候經(jīng)過重構(gòu)后的 v3 版本,底層憑借高效的 fluentbit 和插件豐富的 flunetd煌集,Logging Operator幾乎已經(jīng)完美的適配了 kubernetes 模式下的日志采集場景妓肢,未來可期。去年偶然間發(fā)現(xiàn)Rancher 在 2.5 版本之后也采用了 Logging Operator 作為統(tǒng)一的日志解決方案碉钠,足以說明它正在被一些以 Kubernetes 為核心的管理平臺接受,并集成至內(nèi)部(也包括小白的 KubeGems)栗弟。
本文作為前面兩篇的續(xù)篇污筷,主要跟大家談?wù)勛罱“子?Logging Operator 來解決用戶需求時的案例以及感受,所以我不打算花篇幅對其架構(gòu)和使用再做描述乍赫,感興趣的同學(xué)可以往前翻翻小白的文章瓣蛀。
關(guān)于指標(biāo)
應(yīng)用在容器化的過程中,由于容器文件系統(tǒng)的臨時性雷厂,開發(fā)者始終面臨自己的日志文件落盤和輸出 stdout 的兩難選擇惋增,當(dāng)研發(fā)將應(yīng)用日志管理的權(quán)利交給平臺時诈皿,意味著平臺要做的東西遠(yuǎn)比應(yīng)用一對一采集要復(fù)雜。在眾多需求中像棘,某天有SRE同學(xué)提問:“我們在阿里云中可以看到日志采集的實時速率稽亏,我們需要為此定制質(zhì)量監(jiān)控指標(biāo)”。這個問題也點醒了我避除,對于我們在做私有云時怎披,站在平臺外面對日志采集的管道內(nèi)部的觀察一直是處于信息缺失的盲區(qū)。好在 fluentbit 和 fluentd 都有獨立的prometheus 插件來暴露內(nèi)部的指標(biāo)瓶摆,不過在用 Logging Operator 后凉逛,它的指標(biāo)采集依托 prometheus operator, 且架構(gòu)足夠清晰群井,因此我們也可以有更多的選擇來滿足研發(fā)的需求状飞。
首先,我們在定義 logging 時可以讓 fluent bit(d)開啟 prometheus的采集
spec:
fluentdSpec:
metrics:
serviceMonitor: true
serviceMonitorConfig:
honorLabels: true // 打開honorLabels主要是為了保持組件原有的label书斜,避免標(biāo)簽被覆蓋诬辈。
fluentbitSpec:
metrics:
serviceMonitor: true
這里可以看到 Logging Operator 主要依靠
ServiceMonitor
來做采集端的服務(wù)發(fā)現(xiàn),這里需要集群內(nèi)部運行 Prometheus Operator 以支持該 CRD荐吉。如果集群內(nèi)部沒有改資源類型焙糟,也可以借助 Prometheus 自身的服務(wù)發(fā)現(xiàn)機制來完成指標(biāo)的發(fā)現(xiàn)和采集。
不過這里僅僅只聲明了采集端的指標(biāo)入口样屠,這里面默認(rèn)只包含了 Fluent bit(d)內(nèi)部基本的運行狀態(tài)穿撮,如果要進一步實現(xiàn)對日志速率的監(jiān)控,就得需要 Flunetd 出馬了痪欲。早些年谷歌的GKE上還在用 Fluentd 作為日志采集器時悦穿,偶然間胡亂看(有目的的抄襲)的一條 Prometheus 插件配置引起了我的興趣
<filter **>
@type prometheus
<metric>
type counter
name logging_entry_count
desc Total number of log entries generated by either application containers or system components
</metric>
<labels>
container: $.kubernetes.container_name
pod: $.kubernetes.pod_name
</labels>
</filter>
這條規(guī)則將匹配所有進入Fluentd的日志, 并進入到 Prometheus 這個 filter 進行計數(shù)處理业踢。并將統(tǒng)計后的指標(biāo)以logging_entry_count
命名栗柒,按照日志中的一些元數(shù)據(jù)信息作為指標(biāo)的 label,用于區(qū)分來至不同的容器知举。
由于需要解析日志的 kubernetes 元數(shù)據(jù)瞬沦,這里又需要 Fluentd 的
kubernetes-metadata-filter
插件來做容器元數(shù)據(jù)的提取。在 Logging Operator中 Kubernetes 的元數(shù)據(jù)在 Fluent Bit 中解析雇锡,無需再在 Fluentd 額外添加該插件
雖然現(xiàn)在谷歌 GKE 現(xiàn)在也將日志采集器換成 Fluent Bit蛙埂,但上面這條配置在 Logging Operator 中并不“過時”。有了前車之鑒遮糖,我們可以在租戶的日志采集器(Flow / ClusterFlow)中將 Prometheus 插件引入進來用于分析日志速率绣的。當(dāng)中最簡單的實踐如下:
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: default
namespace: demo
spec:
- prometheus:
labels:
container: $.kubernetes.container_name
namespace: $.kubernetes.namespace_name
node: $.kubernetes.host
pod: $.kubernetes.pod_name
metrics:
- desc: Total number of log entries generated by either application containers
or system components
name: logging_entry_count
type: counter
globalOutputRefs:
- containers-console
match:
- select:
labels:
what.you.want: collect
當(dāng)上述指標(biāo)入庫 Prometheus 之后,我們便可以通過這條語句查出當(dāng)前集群下日志采集器的應(yīng)用速率
sum by (pod) (rate(logging_entry_count[1m]))
此時欲账,如果云平臺是基于多租戶多環(huán)境架構(gòu)屡江,那么你甚至可以按照租戶環(huán)境、租戶級別分別來聚合日志的速率赛不。
上述僅僅是對日志總體速率的采集監(jiān)控惩嘉,如果我們需要對日志內(nèi)出現(xiàn)的特定的內(nèi)容或者對日志的byte 進行統(tǒng)計時,就需要結(jié)合其它的插件進行組合踢故。當(dāng)前 Logging Operator 支持的插件還遠(yuǎn)不如 Fluentd 豐富文黎,不過我們可以參照官方文檔惹苗,編寫需要的plugin集成至 Operator。Logging Operator Developers手冊
對于日志組件內(nèi)部的監(jiān)控和告警耸峭,Logging Operator 有一套自己的規(guī)則桩蓉,可以在 logging 這個 CR 中啟用這個功能
spec:
fluentbitSpec:
metrics:
prometheusRules: true
fluentdSpec:
metrics:
prometheusRules: true
這里的
prometheusRules
同樣是 Prometheus Operator 管理的資源,如果集群內(nèi)沒有此資源類型劳闹,可手動為 Prometheus 配置 Rules
回到最初的問題院究,如果需要將日志的采集速率作為應(yīng)用的量化指標(biāo)時,利用logging_entry_count
即可本涕。
關(guān)于采樣
大多數(shù)情況下业汰,日志架構(gòu)不應(yīng)該對業(yè)務(wù)日志采取一些不可控的策略,造成應(yīng)用日志的不完整菩颖,例如采樣样漆。在這里顯然我也不推薦你在現(xiàn)有的架構(gòu)中啟用此功能。不過有時候晦闰,或者是部分魔法師無法有效控制程序的“洪荒之力”而瘋狂輸出時氛濒,平臺對于這類俏皮的應(yīng)用時就可以采樣的方案,畢竟保證整個日志通道的可用性是平臺第一優(yōu)先要考慮因素鹅髓。
Logging Operator 在日志采樣方面舞竿,采用了Throttle這個插件限速器,用一句話總結(jié)這個插件就是為每個進入到 filter 日志的管道引入了漏桶算法窿冯,讓其丟棄到超過速率限制的日志骗奖。
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: default
namespace: demo
spec:
- throttle:
group_bucket_limit: 3000
group_bucket_period_s: 10
group_key: kubernetes.pod_name
globalOutputRefs:
- containers-console
match:
- select:
labels:
what.you.want: collect
- group_key: 日志采樣的聚合 key,通常我們按照pod 名稱來做聚合醒串,亦或直接填寫kubenretes.metadata 的其它值聚合也行
- group_bucket_period_s: 采樣的時間范圍执桌,默認(rèn) 60s
- group_bucket_limit: 采樣期間的日志桶最大容量
日志的采樣速率由公式group_bucket_limit / group_bucket_period_s
計算,當(dāng)group_key
中的日志速率超過值時則會丟到后續(xù)日志芜赌。
由于 Throttle 并沒有采用令牌桶的算法仰挣,所以它不會有 burst 來應(yīng)對突發(fā)日志量的采集。
關(guān)于日志落盤
前面說到缠沈,所有基于容器的應(yīng)用程序膘壶,日志的最佳實踐是將日志定向到stdout
、stderr
中洲愤,但并不是所有“魔法師”都會遵循此約定颓芭,日志文件落盤仍然是當(dāng)下多數(shù)研發(fā)的選擇。雖然理論上來說容器的標(biāo)準(zhǔn) (錯誤)輸出也是將日志流集中重定到/var/log/containers
下的日志文件上柬赐,但仍然受限于運行時配置或者其他硬盤原因帶來不可控的因素亡问。
對于日志落盤的場景,當(dāng)前業(yè)界也無統(tǒng)一的解決方案肛宋,但歸總起來其實也就2個實現(xiàn)方式:
-
sidecar 方案
此方案是將日志采集器跟隨應(yīng)用容器一同運行在pod 當(dāng)中州藕,通過 volume 共享日志路徑的方式采集束世。常見的是方式是為 kubernetes 開發(fā)一套單獨的控制器,并采用
MutatingWebhook
在pod 啟動階段將 sidecar 的信息注入床玻。sidecar 的方案優(yōu)勢在于為每個應(yīng)用的 sidecar 配置相對獨立毁涉,但劣勢除占用過多資源外,采集器的更新迭代需跟隨應(yīng)用的生命周期笨枯,對于持續(xù)維護不太優(yōu)雅薪丁。
-
node agent 方案
此方案將日志采集器以
DaemonSet
的方式運行在每個 Node 當(dāng)中遇西,然后在操作系統(tǒng)層面進行集中采集馅精。通常此方案需要平臺的研發(fā)需要做一定路徑策略,將固定hostpath
的 vulume 掛載給容器用于應(yīng)用日志落盤時使用粱檀。除此之外洲敢,我們知道所有 Kubernetes 默認(rèn)的存儲類型或者第三方的遵循 CSI 標(biāo)準(zhǔn)的存儲,都會將Volume掛載到/var/lib/kubelet/pods/<pod_id>/volumes/kubernetes.io~<type>/<pvc_id>/mount
目錄下茄蚯,所以對于 node agent 更加優(yōu)雅一點的方案是在 node agent 中賦予調(diào)用 Kubernetes API 的權(quán)限压彭,讓其知曉被采集容器日志映射在主機下的路徑。node agent的方案的優(yōu)勢在于配置集中管理渗常,采集器跟應(yīng)用容器解耦壮不,互不影響。缺點在于采集器存在吞吐不足的風(fēng)險皱碘。
可以看到上述兩個方案中询一,不管哪一個都與 Logging Operator 沾不上關(guān)系。確實癌椿,當(dāng)下社區(qū)對此場景下還沒有一個行之有效的方案健蕊,不過按照其思路,我們可以將日志文件轉(zhuǎn)成標(biāo)準(zhǔn)(錯誤)輸出流來變相處理這個問題踢俄。
用tail
來舉個直觀的例子來說明上述的方案缩功。
...
containers:
- args:
- -F
- /path/to/your/log/file.log
command:
- tail
image: busybox
name: stream-log-file-[name]
volumeMounts:
- mountPath: /path/to/your/log
name: mounted-log
...
雖然tail
是一個極其簡單粗暴的方式,且無法解決日志輪轉(zhuǎn)等問題都办,但它的確為Logging Operator提供了一個新的日志落盤場景下的方案嫡锌。雖然看上去與 sidecar 如出一轍,不過最大的區(qū)別在于琳钉,此方案能與 Logging Operator 現(xiàn)有的日志管道無縫兼容世舰,日志被采集后仍然能在 flow 階段進行處理。
總結(jié)
Logging Operator 站在自動化運維的角度確實有效解決了 Kubernetes 場景下日志架構(gòu)復(fù)雜和應(yīng)用日志采集難的問題槽卫,雖然當(dāng)下對落盤日志的支持還不夠全面跟压。但隨著接入的用戶逐漸成長,現(xiàn)在的問題在將來或許還有更好的解決方案歼培。不過震蒋,當(dāng)下它的確不失為最好的云原生日志架構(gòu)之一茸塞。
關(guān)注公眾號【云原生小白】,回復(fù)「入群」加入Loki學(xué)習(xí)群