K8S的日誌採集,沒有我們想的那麼簡單!
相比傳統的主機日誌採集,在Kubernetes叢集中,採集容器日誌有一些差異,使用方式上也有所區別。因此我們羅列了一些常規的部署和使用方式以供參考。
1.從主機到容器
在傳統的使用虛擬機器/雲主機/物理機的時代,業務程式部署在固定的節點上,業務日誌直接輸出到宿主機上,運維只需要手動或者使用自動化工具把日誌採集Agent部署在節點上,加一下Agent的配置,就可以開始採集日誌了。而在Kubernetes環境中,就沒這麼簡單了:
「動態遷移」:在Kubernetes叢集中經常存在Pod主動或者被動的遷移,頻繁的銷燬、建立,我們無法和傳統的方式一樣人為的給每個服務下發日誌採集配置。
「日誌儲存方式多樣性」:容器的日誌儲存方式有很多不同的型別,例如stdout、hostPath、emptyDir、pv等。
「Kubernetes元資訊」:由於日誌資料採集後會被集中儲存,所以查詢日誌時,需要根據namespace、pod、container、node,甚至包括容器的環境變數、label等維度來檢索、過濾,此時要求Agent感知並預設在日誌裡注入這些元資訊。
以上都是有別於傳統日誌採集配置方式的需求和痛點,究其原因,還是因為傳統的方式脫離了Kubernetes,無法感知Kubernetes,無法和Kubernetes整合。
2. 在Kubernetes下的日誌形態
為了採集容器日誌,我們先來看一下市面上一般都有哪些解決方案。
2.1 採集的日誌型別
首先,需要提及的是,在雲原生的12要素裡,推薦業務容器將日誌輸出到stdout中,而不是採用列印日誌檔案的方式。當然,實際情況是,我們很難這麼做,原因大概有:
需要業務方修改日誌配置,比較難以推廣
有些複雜的業務對日誌檔案有分類,比如審計日誌、訪問日誌等,一般會輸出為獨立的日誌檔案,日誌採集需根據不同的檔案分類進行不同的處理
所以正常情況下,我們需要同時採集:
「標準輸出stdout」
「日誌檔案」
2.2 Agent部署方式
採集容器日誌,Agent有兩種部署方式:
「DaemonSet」:每個節點部署一個Agent
「Sidecar」:每個Pod增加一個Sidecar容器,執行日誌Agent
兩種部署方式的優劣都顯而易見:
資源佔用:DaemonSet每個節點上一個,而Sidecar每個Pod裡一個,容器化形態下,往往一個Node上可能會跑很多的Pod,此時DaemonSet的方式遠小於Sidecar,而且節點上Pod個數越多越明顯
侵入性:Sidecar的方式,Agent需要注入到業務Pod中,不管是否有平臺封裝這一過程,還是採用Kubernetes webhook的方式預設注入,仍然改變了原本的部署方式
穩定性:日誌採集在大部分的情況下,需要保障的是穩定性,最重要的是不能影響業務,如果採用Sidecar的方式,在Agent發生異常或者oom等情況,很容易對業務容器造成影響。另外,Agent比較多的時候,在連線數等方面會對下游服務比如Kafka造成一定的隱患。
隔離性:DaemonSet情況下,節點所有的日誌都共用同一個Agent,而Sidecar方式,只會採集同一個Pod內的業務日誌,此時Sidecar的隔離性理論上會好一些
效能:Sidecar由於只會採集該Pod裡的日誌,壓力相對較小,極端情況下,達到Agent的效能瓶頸比DaemonSet方式機率也會小很多
❝Tip:正常情況下,優先使用DaemonSet的方式採集日誌,如果單個Pod日誌量特別大,超過一般Agent傳送吞吐量,可以單獨對該Pod使用Sidecar的方式採集日誌。❞
2.3 採集方式
DaemonSet + Stdout
如果使用容器執行時的是docker,正常情況下我們可以在節點的docker路徑中找到容器的stdout的日誌,預設為/var/lib/docker/containers/{containerId}/{containerId}-json.log。在Kubernetes 1.14版本之前,kubelet會在/var/log/pods/<podUID>/<containerName>/<num>.log建立一個軟連結到stdout檔案中。類似如下所示:
在Kubernetes 1.14版本之後,改成了/var/log/pods/<namespace>_<pod_name>_<pod_id>/<container_name>/<num>.log的形式。
所以,對於Agent採集標準輸出日誌來說,也就是採集節點上的這些日誌檔案。一種簡單粗暴的採集方式是,使用DaemonSet部署日誌Agent,掛載/var/log/pods目錄,Agent的配置檔案使用類似/var/log/pod.log去通配日誌檔案,採集節點上所有的容器標準輸出。
❝「Tip:這也是我最初的解決方案,想到這就臉紅!」❞
但是這樣的侷限在於:
無法注入更多元資訊比如一些pod的label/env等,特別是在k8s1.14版本之前,甚至無法在採集的path裡獲取到namespace/pod等資訊
很難針對單個服務配置特殊的配置,比如某個檔案需要使用特殊的多行日誌採集,需要配置適合服務自身的日誌格式切分等
會採集很多不必要的容器日誌,造成採集、傳輸、儲存壓力
當然現在的一些日誌Agent比如Filebeat/Fluentd都針對性的做了支援,比如可以將namespace/pod等資訊注入日誌中,但仍然沒有解決大部分的問題。
所以,這種方式只適合簡單的業務場景,後續也難以滿足其他更多的日誌需求。
DaemonSet + 日誌檔案
如果Pod裡不僅僅是輸出stdout,還包括日誌檔案,就需要考慮到掛載日誌檔案到節點上,同時採用DaemonSet部署的Agent也需要掛載相同的目錄,否則採用容器化部署的Agent無法檢視到相應的檔案,更無法採集。業務Pod掛載日誌路徑的方式有以下幾種:
「(1) emtpyDir」
emtpyDir的生命週期跟隨Pod,Pod銷燬後其中儲存的日誌也會消失。
優點:使用簡單,不同Pod都使用自己的emtpyDir,有一定的隔離性。
缺點:日誌如果採集不及時,在Pod消耗後,存在丟失的可能性。
使用emptyDir掛載的日誌檔案,一般在節點的路徑如下:/var/lib/kubelet/pods/${pod.UID}/volumes/kubernetes.io~empty-dir/${volumeName}
「(2) hostPath」
生命週期和Pod無關,Pod遷移或者銷燬,日誌檔案還保留在現有磁碟上。
優點:生命週期和Pod無關,即使Pod銷燬,日誌檔案依然在節點磁碟上,假設Agent沒有采集日誌,仍然可以找到日誌檔案
缺點:預設無隔離性,需要控制掛載的日誌路徑;另外,Pod遷移節點後,殘留的日誌檔案長期積累容易佔據磁碟,同時日誌佔據的磁碟無法控制使用的配額
為了解決隔離性,避免多個Pod列印日誌到相同的路徑和檔案中,我們需要使用 subPathExpr 欄位從 Downward API 環境變數構造 subPath 目錄名。該 VolumeSubpathEnvExpansion 功能從 Kubernetes1.15 開始預設開啟,在1.17 GA。
「(3) Pv」
Pv的訪問模式包括:
ReadWriteOnce(RWO):讀寫許可權,並且只能被單個Node掛載。
ReadOnlyMany(ROX):只讀許可權,允許被多個Node掛載。
ReadWriteMany(RWX):讀寫許可權,允許被多個Node掛載。
對於大部分的業務來說,都是Deployment無狀態部署,需要掛載同一個Pv共享;對於一些中介軟體等有狀態服務,一般會使用StatefulSet部署,每個Pod會使用獨立的Pv。
優點:儲存日誌不容易丟失;
缺點:有一定的使用和運維複雜度;多個Pod共享同一個Pv時存在隔離性問題;很多的日誌Agent對採集雲盤上的日誌檔案支援不夠成熟,可能存在一些隱患;
雖然同樣可以在Node上找到使用Pv掛載的對應日誌檔案,但是Pv根據不同的底層實現,在Node上的路徑會有一定的區別。目前市面上大部分日誌Agent均對這些掛載方式沒有感知,所以你能做的和上面使用stdout的方式類似,也就是簡單粗暴的讓Agent將路徑都掛載,使用通配的方式採集所有的日誌,使用上的侷限和stdout的方式同樣一致。
另外,鑑於一些Agent對採集docker stdout有一定的支援,所以還存在一些使用上變種,比如利用webhook注入一個sidecar,讀取Pod裡的日誌檔案,轉換成sidecar的stdout,然後採集sidecar的stdout日誌,這裡不再詳述。
來自 “ 木訥大叔愛運維 ”, 原文作者:Loggie;原文連結:https://mp.weixin.qq.com/s/PQSXkne0GenoF7Lb7sloyQ,如有侵權,請聯絡管理員刪除。
相關文章
- 安全開發Java:日誌注入,並沒那麼簡單Java
- MySQL鎖這塊石頭似乎沒有我想的那麼重MySql
- 想問下大家Mac有沒有什麼好用的檢視日誌的工具Mac
- 為什麼我們說區塊鏈沒有那麼容易?區塊鏈
- 在遊戲裡新增簡單模式,沒有想象中那麼簡單遊戲模式
- 日誌採集/分析
- 做一名優秀的開發者可沒有說的那麼簡單
- 日誌採集框架Flume框架
- 執行緒池沒你想的那麼簡單(續)執行緒
- 團隊級敏捷真的沒你想的那麼簡單敏捷
- 應用日誌採集是什麼意思?批次採集應用日誌軟體用哪個?怎麼操作?應用日誌
- 遊戲中殊死戰鬥的競技場,或許沒有你想的那麼簡單遊戲
- 簡單ELK配置實現生產級別的日誌採集和查詢實踐
- 執行緒的生命週期,真的沒那麼簡單執行緒
- 世嘉的霧遊戲有沒有那麼奇葩?遊戲
- Kubernetes日誌採集
- 想拿到BAT的前端開發崗offer,並沒有想象中的那麼難!BAT前端
- 雲端計算網路,沒那麼簡單
- 日誌服務之使用Nginx模式採集日誌Nginx模式
- GO的日誌庫log竟然這麼簡單!Go
- POCO相簿的照片批量採集下載的簡單方法有嗎?
- 轉轉容器日誌採集的演進之路
- flume日誌採集,hbase資料儲存,hive查詢輸出(簡單整合)Hive
- 想問問深圳的大佬同行們,有沒有內推的崗位
- 直擊痛點,詳解 K8s 日誌採集最佳實踐K8S
- 復刻或重製老遊戲,可能並沒有想象中那麼簡單遊戲
- logstash採集Java日誌文字檔案配合grok收集到elasticsearch簡單示例JavaElasticsearch
- 做一個優秀的程式設計師沒那麼簡單程式設計師
- 簡單的C#日誌類C#
- 傲野:如果測試沒有夢想,那跟鹹魚有什麼區別?
- 日誌服務 HarmonyOS NEXT 日誌採集最佳實踐
- ELK太重?試試KFC日誌採集
- KubeSphere 多行日誌採集方案深度探索
- 親愛的商界精英們,開發一個iOS應用沒有那麼容易iOS
- DG沒有應用日誌應用日誌
- Javascript之其實我覺得原型鏈沒有難的那麼誇張!JavaScript原型
- 簡單的方式搭建k8s叢集K8S
- 針對Fluent-Bit採集容器日誌的補充