本文整理自:淺談雲原生系統日誌收集在數棧的實踐
html
數棧是雲原生—站式數據中臺PaaS,咱們在github上有一個有趣的開源項目:FlinkX,歡迎給咱們點個star!star!star!
node
https://github.com/DTStack/flinkx
git
FlinkX是一個基於Flink的批流統一的數據同步工具,既能夠採集靜態的數據,好比MySQL,HDFS等,也能夠採集實時變化的數據,好比MySQL binlog,Kafka等,是全域、異構、批流一體的數據同步引擎,你們若是有興趣,歡迎來github社區找咱們玩~github
談到日誌收集,估計你們第一個想到的就是ELK這個比較成熟的方案,若是是特別針對雲原生上的,那麼將採集器稍微變一下爲 Fluentd 組成 EFK 便可。以上兩種方案其實沒有本質上的區別,採集器換了換而已。最終存儲、查詢等等採用的仍是 elasticsearch 這一套。docker
elasticsearch確實功能豐富、很是強大,可是代價也是極其昂貴的,elasticsearch 採用全文索引的方式,對存儲以及內存的要求比較高,而這些代價換來的功能對於平常日誌管理來講倒是不經常使用的。這些缺點在主機模式下實際上是能夠容忍的,但在雲原生模式下就顯得比較臃腫了。json
PLG 是 promtail+loki+grafana 的合稱,這是一套很是適合雲原生下日誌的採集方案。grafana 你們會比較熟悉,一個很是棒的可視化的框架,支持多種數據源。最多見的就是將prometheus的數據進行可視化展現。而loki就是今天咱們要談的主角,這個也是grafana 家的產品,promtail 則是 loki 的官方日誌採集器。api
與elk相比這一套方案很是輕量級,功能實用,使用起來簡單易用,而且在展現上採用 grafana 減小引入可視化的框架,展現終端上的統一也有利於用戶的使用。框架
(一) 日誌新貴loki運維
Loki是受Prometheus啓發的水平可擴展,高度可用的多租戶日誌聚合系統。它的設計具備很高的成本效益,而且易於操做。它不索引日誌的內容,而是爲每一個日誌流設置一組標籤。elasticsearch
與其餘日誌聚合系統相比,Loki
不對日誌進行全文本索引。經過存儲壓縮的,非結構化的日誌以及僅索引元數據,Loki更加易於操做且運行成本更低。
使用與Prometheus相同的標籤對日誌流進行索引和分組,從而使您可以使用與Prometheus相同的標籤在指標和日誌之間無縫切換。
特別適合存儲Kubernetes Pod日誌。諸如Pod標籤之類的元數據會自動被抓取並創建索引。
Grafana原生支持(須要Grafana v6.0以上)。
這段是loki 在 GitHub 上的介紹,能夠看出這是一款爲雲原生而打造的輕量級日誌聚合系統。目前社區很是活躍。並且採用 prometheus 相似的標籤的思想,與 grafana 打通進行可視化展現,不管是思想仍是用法都很是的「雲原生」。
(二) ♂️ 親兒子Promtail
promtail 是 loki 的官方日誌採集器,自己代碼就在 loki 項目中。原生支持journal、syslog、file、docker類型的日誌。採集器的本質無非都是根據模式找到要採集的文件,而後對着個文件進行相似tail的監控,再把寫入文件的內容發送給存儲端promtail 也是這樣,上面這些類型的本質也都是文件,只不過這些類型的文件的格式是公開穩定的規範,promtail 能夠預先對其進行進行更深解析與封裝。
(三) Promtail 服務發現
一、 找到文件做爲一個採集器,其第一步天然是要找到文件在哪裏,而後才能作下面的收集與打標籤推送等功能。普通靜態類型的日誌是很好發現的,直接將你在配置文件中寫的路徑信息進行匹配便可,好比 promtail 中path爲 "/var/log/*.log"即將 /var/log目錄下全部的以.log 結尾的後綴文件做爲要採集的對象便可。而要採集 k8s 模式內的日誌就稍顯麻煩。
首先咱們想一下k8s 上跑的服務的日誌究竟是在哪裏?
因此咱們須要將這/var/log/pods 做爲hostpath 掛載進 k8s 的容器內部,才能讓 promtail 訪問到這些日誌。
日誌promtail能夠訪問到了,可是還有一個問題仍是如何爲區分這些日誌,loki採用相似prometheus的思想,將數據打上標籤。也就是將日誌打上pod的標籤,那麼單單憑藉這個路徑天然是沒法知道該pod上有哪些標籤信息的。這裏就須要用到服務發現了。
promtail的服務發現是直接採用的prometheus的服務發現作的。熟悉prometheus 的同窗確定配置過prometheus的服務發現的配置,kubernetes_sd_configs與relabel_configs。
這裏promtail直接引入prometheus的代碼,與prometheus不一樣的是prometheus請求的資源對對象比較多,node、ingress、pod、deployment 等等都有,最終拼接的是metric的請求url,而promtail請求的對象爲pod,而且過濾掉了不在該主機上的 pod。
拿到該主機的pod的信息後,再根據namespace, pod 的 id 拼接路徑,因爲這個目錄已經掛載進去容器了,那麼promtail 就能夠關聯起容器的標籤與容器的日誌了。剩下的就是監控與推送了。
(四) PLG 最佳實踐
loki 官方推薦的最佳實踐爲採用 DamonSet部署 promtail 的方式,將 node 的 /var/lib/pods目錄掛載進容器內部,藉助prometheus 的服務發現機制動態的爲日誌加上標籤,不管是資源的佔用程度仍是部署維護難度都是很是低。這也是主流的雲原生日誌採集範式。
(一) 數棧日誌需求
(二) ️ 主機模式
數棧主機模式日誌聚合採用相似PLG DameonSet 的模式。每臺主機部署一臺 promtail,而後整個集羣部署一套服務端 loki 與可視化端grafana。
promtail 採用static_configs定義採集的日誌。可是promtail 畢竟仍是太年輕了,定位偏向於雲原生,因此針對主機功能還不夠完善,所以咱們作了一些二次開發知足咱們的需求:
一、logtail 模式
原生 promtail 並不支持從文件尾部開始收集,當 promtail 啓動後,會將監控的全部文件的內容都進行推送,這樣的狀況在雲原生並無太大問題.
主機模式下若是要監控的日誌已經存在而且有大量的內容的話,promtail 啓動會將文件的內容從頭開始推送,短期內形成大量的日誌往loki推送,很大的機率會被 loki 限流致使推送失敗。
因此最好的方式就是有相似 filebeat 的 logtail 的模式,及只推送服務啓動後的文件寫入的日誌。
這個地方咱們對此做了二次開發,增長一個logtail 模式的開關,若是該開關爲 true,這第一次啓動 promtail 的時候將不會從頭推送日誌。
二、path 支持多路徑
原生 promtail 不支持多路徑 path 參數只能寫一個表達式,可是現實的需求多是既要看業務的日誌還要看 gc 的日誌。
可是他們又是屬於同一類別的標籤。單個path的匹配沒法涵蓋其兩個,不改代碼的解決方法就是再爲其寫一個 target。
這樣作繁瑣且不利於維護。因此咱們這裏也對其作了二次開發
(三) 雲原生模式
傳統的雲原生模式採用 PLG 的主流模式就行了,可是數棧做爲一整套系統對企業交付的時候有諸多限制會致使demoset模式並不可用,最大的挑戰是權限,只有一個 namespace 的權限,不能掛載/var/lib/pods
在這種狀況下如何使用 PLG呢?
其實主要變化的地方在於promtail的使用,這裏首先要聲明的一點是,數棧的服務的日誌都爲文件輸出。
首先是選擇damonset 模式部署仍是sidecar模式部署,demonset模式的優勢是節省資源,缺點是權限有要求。sidecar模式與之相反,爲了適用更嚴格的交付條件,咱們選擇採用 sidecar 的模式進行採集。
sidecar 模式就是爲當每一個服務進行部署的時候就自動爲其添加一個log容器,該容器與服務容器共同掛載一個共同的空的數據卷,服務容器將日誌寫入該數據卷中,log容器對數據卷下的日誌進行採集。
一、⛳ promtail 在數棧如何動態配置標籤
經過sidecar的模式咱們讓log Container與Master Container共享一個日誌目錄,這樣就promtail容器內就能夠拿到了日誌的文件,可是promtail還不知道要採集哪些日誌,以及他的標籤是什麼。
由於你可能只想採集.log的日誌,也可能只想採集.json的日誌,或者都有的服務這個配置多是不一樣的,因此也不能寫死,那如何解決這個問題呢?
promtail 在 v2.10中新增長了一個feature ,就是能夠在配置文件中引用環境變量,經過這個特性咱們能夠將promtail的path參數寫成${LOG_PATH},而後將服務的logpath以環境變量的方式設置進去好比LOG_PATH=/var/log/commonlog/*.log
既然咱們能夠經過環境變量的方式在服務建立的時候設置path,那麼標籤咱們也能夠動態的設置進去。那麼咱們都需什麼維度的標籤呢?這個不一樣的公司確定有不一樣的維度,可是必須遵循的一個原則就是能夠惟一肯定該pod。通常的維度有deployment、podid、node等。這些標籤在建立的時候就經過環境變量注入進去,而podid 這些環境變量利用的是k8s 的 downward api 的方式注入的。
注意:這裏不可用使用 promtail 的服務發現機制配置標籤,由於promtail 的服務發現的原理是請求 APIServer 獲取全部pod 的標籤。而後利用路徑進行匹配,將標籤與日誌關聯。在沒有掛載宿主機/var/log/pods目錄到promtail 時,即便拿到了標籤也沒法與日誌進行關聯。
爲每一個服務增長一個Log Container若是手工操做的話實在是太繁瑣了,並且不利於維護。最好的方式就將本來的服務抽象爲是註冊一個CRD,而後編寫 k8s operator經過list&watch該類型的對象,在該對象建立的時候,動態的注入一個LogContainer,以及相應的環境變量和爲其掛載共同目錄。
這樣當該CR建立的時候,promtail就做爲sidecar注入了其中。而且讀到的環境變量就是operator 動態設置的環境變量,靈活度很是高。
(一) 數棧日誌收集優點
(二)✈️將來規劃
最後給你們分享一下數棧當前日誌模塊可視化的效果,是否是超級酷炫?