Kubernetes日誌採集最佳實踐

前言

上一期主要介紹Kubernetes日誌輸出的一些注意事項,日誌輸出最終的目的還是做統一的採集和分析。在Kubernetes中,日誌採集和普通虛擬機的方式有很大不同,相對實現難度和部署代價也略大,但若使用恰當則比傳統方式自動化程度更高、運維代價更低。


Kubernetes日誌採集難點

在Kubernetes中,日誌採集相比傳統虛擬機、物理機方式要複雜很多,最根本的原因是Kubernetes把底層異常屏蔽,提供更加細粒度的資源調度,向上提供穩定、動態的環境。因此日誌採集面對的是更加豐富、動態的環境,需要考慮的點也更加的多。

例如:

  1. 對於運行時間很短的Job類應用,從啟動到停止只有幾秒的時間,如何保證日誌採集的實時性能夠跟上而且數據不丟?
  2. K8s一般推薦使用大規格節點,每個節點可以運行10-100+的容器,如何在資源消耗盡可能低的情況下采集100+的容器?
  3. 在K8s中,應用都以yaml的方式部署,而日誌採集還是以手工的配置文件形式為主,如何能夠讓日誌採集以K8s的方式進行部署?

Kubernetes傳統方式日誌種類文件、stdout、宿主機文件、journal文件、journal日誌源業務容器、系統組件、宿主機業務、宿主機採集方式Agent(Sidecar、DaemonSet)、直寫(DockerEngine、業務)Agent、直寫單機應用數10-1001-10應用動態性高低節點動態性高低採集部署方式手動、Yaml手動、自定義


採集方式:主動 or 被動

日誌的採集方式分為被動採集和主動推送兩種,在K8s中,被動採集一般分為Sidecar和DaemonSet兩種方式,主動推送有DockerEngine推送和業務直寫兩種方式。

  • DockerEngine本身具有LogDriver功能,可通過配置不同的LogDriver將容器的stdout通過DockerEngine寫入到遠端存儲,以此達到日誌採集的目的。這種方式的可定製化、靈活性、資源隔離性都很低,一般不建議在生產環境中使用。
  • 業務直寫是在應用中集成日誌採集的SDK,通過SDK直接將日誌發送到服務端。這種方式省去了落盤採集的邏輯,也不需要額外部署Agent,對於系統的資源消耗最低,但由於業務和日誌SDK強綁定,整體靈活性很低,一般只有日誌量極大的場景中使用。
  • DaemonSet方式在每個node節點上只運行一個日誌agent,採集這個節點上所有的日誌。DaemonSet相對資源佔用要小很多,但擴展性、租戶隔離性受限,比較適用於功能單一或業務不是很多的集群。
  • Sidecar方式為每個POD單獨部署日誌agent,這個agent只負責一個業務應用的日誌採集。Sidecar相對資源佔用較多,但靈活性以及多租戶隔離性較強,建議大型的K8S集群或作為PAAS平臺為多個業務方服務的集群使用該方式。
Kubernetes日誌採集最佳實踐

總結下來:DockerEngine直寫一般不推薦;業務直寫推薦在日誌量極大的場景中使用;DaemonSet一般在中小型集群中使用;Sidecar推薦在超大型的集群中使用。詳細的各種採集方式對比如下:

DockerEngine業務直寫DaemonSet方式Sidecar方式採集日誌類型標準輸出業務日誌標準輸出+部分文件文件部署運維低,原生支持低,只需維護好配置文件即可一般,需維護DaemonSet較高,每個需要採集日誌的POD都需要部署sidecar容器日誌分類存儲無法實現業務獨立配置一般,可通過容器/路徑等映射每個POD可單獨配置,靈活性高多租戶隔離弱弱,日誌直寫會和業務邏輯競爭資源一般,只能通過配置間隔離強,通過容器進行隔離,可單獨分配資源支持集群規模本地存儲無限制,若使用syslog、fluentd會有單點限制無限制取決於配置數無限制資源佔用低,dockerengine提供整體最低,省去採集開銷較低,每個節點運行一個容器較高,每個POD運行一個容器查詢便捷性低,只能grep原始日誌高,可根據業務特點進行定製較高,可進行自定義的查詢、統計高,可根據業務特點進行定製可定製性低高,可自由擴展低高,每個POD單獨配置耦合度高,與DockerEngine強綁定,修改需要重啟DockerEngine高,採集模塊修改/升級需要重新發布業務低,Agent可獨立升級一般,默認採集Agent升級對應Sidecar業務也會重啟(有一些擴展包可以支持Sidecar熱升級)適用場景測試、POC等非生產場景對性能要求極高的場景日誌分類明確、功能較單一的集群大型、混合型、PAAS型集群




日誌輸出:Stdout or 文件

和虛擬機/物理機不同,K8s的容器提供標準輸出和文件兩種方式。在容器中,標準輸出將日誌直接輸出到stdout或stderr,而DockerEngine接管stdout和stderr文件描述符,將日誌接收後按照DockerEngine配置的LogDriver規則進行處理;日誌打印到文件的方式和虛擬機/物理機基本類似,只是日誌可以使用不同的存儲方式,例如默認存儲、EmptyDir、HostVolume、NFS等。

雖然使用Stdout打印日誌是Docker官方推薦的方式,但大家需要注意這個推薦是基於容器只作為簡單應用的場景,實際的業務場景中我們還是建議大家儘可能使用文件的方式,主要的原因有以下幾點:

  1. Stdout性能問題,從應用輸出stdout到服務端,中間會經過好幾個流程(例如普遍使用的JSON LogDriver):應用stdout -> DockerEngine -> LogDriver -> 序列化成JSON -> 保存到文件 -> Agent採集文件 -> 解析JSON -> 上傳服務端。整個流程相比文件的額外開銷要多很多,在壓測時,每秒10萬行日誌輸出就會額外佔用DockerEngine 1個CPU核。
  2. Stdout不支持分類,即所有的輸出都混在一個流中,無法像文件一樣分類輸出,通常一個應用中有AccessLog、ErrorLog、InterfaceLog(調用外部接口的日誌)、TraceLog等,而這些日誌的格式、用途不一,如果混在同一個流中將很難採集和分析。
  3. Stdout只支持容器的主程序輸出,如果是daemon/fork方式運行的程序將無法使用stdout。
  4. 文件的Dump方式支持各種策略,例如同步/異步寫入、緩存大小、文件輪轉策略、壓縮策略、清除策略等,相對更加靈活。

因此我們建議線上應用使用文件的方式輸出日誌,Stdout只在功能單一的應用或一些K8s系統/運維組件中使用。


CICD集成:Logging Operator

Kubernetes日誌採集最佳實踐

Kubernetes提供了標準化的業務部署方式,可以通過yaml(K8s API)來聲明路由規則、暴露服務、掛載存儲、運行業務、定義縮擴容規則等,所以Kubernetes很容易和CICD系統集成。而日誌採集也是運維監控過程中的重要部分,業務上線後的所有日誌都要進行實時的收集。

原始的方式是在發佈之後手動去部署日誌採集的邏輯,這種方式需要手工干預,違背CICD自動化的宗旨;為了實現自動化,有人開始基於日誌採集的API/SDK包裝一個自動部署的服務,在發佈後通過CICD的webhook觸發調用,但這種方式的開發代價很高。

在Kubernetes中,日誌最標準的集成方式是以一個新資源註冊到Kubernetes系統中,以Operator(CRD)的方式來進行管理和維護。在這種方式下,CICD系統不需要額外的開發,只需在部署到Kubernetes系統時附加上日誌相關的配置即可實現。


Kubernetes日誌採集方案

Kubernetes日誌採集最佳實踐

早在Kubernetes出現之前,我們就開始為容器環境開發日誌採集方案,隨著K8s的逐漸穩定,我們開始將很多業務遷移到K8s平臺上,因此也基於之前的基礎專門開發了一套K8s上的日誌採集方案。主要具備的功能有:

  1. 支持各類數據的實時採集,包括容器文件、容器Stdout、宿主機文件、Journal、Event等;
  2. 支持多種採集部署方式,包括DaemonSet、Sidecar、DockerEngine LogDriver等;
  3. 支持對日誌數據進行富化,包括附加Namespace、Pod、Container、Image、Node等信息;
  4. 穩定、高可靠,基於阿里自研的Logtail採集Agent實現,目前全網已有幾百萬的部署實例;
  5. 基於CRD進行擴展,可使用Kubernetes部署發佈的方式來部署日誌採集規則,與CICD完美集成。


安裝日誌採集組件

目前這套採集方案已經對外開放,我們提供了一個Helm安裝包,其中包括Logtail的DaemonSet、AliyunlogConfig的CRD聲明以及CRD Controller,安裝之後就能直接使用DaemonSet採集以及CRD配置了。安裝方式如下:

  1. 阿里雲Kubernetes集群在開通的時候可以勾選安裝,這樣在集群創建的時候會自動安裝上述組件。如果開通的時候沒有安裝,則可以手動安裝。
  2. 如果是自建的Kubernetes,無論是在阿里雲上自建還是在其他雲或者是線下,也可以使用這樣採集方案,具體安裝方式參考[自建Kubernetes安裝]()。

安裝好上述組件之後,Logtail和對應的Controller就會運行在集群中,但默認這些組件並不會採集任何日誌,需要配置日誌採集規則來採集指定Pod的各類日誌。


採集規則配置:環境變量 or CRD

除了在日誌服務控制檯上手動配置之外,對於Kubernetes還額外支持兩種配置方式:環境變量和CRD。

環境變量是自swarm時代一直使用的配置方式,只需要在想要採集的容器環境變量上聲明需要採集的數據地址即可,Logtail會自動將這些數據採集到服務端。這種方式部署簡單,學習成本低,很容易上手;但能夠支持的配置規則很少,很多高級配置(例如解析方式、過濾方式、黑白名單等)都不支持,而且這種聲明的方式不支持修改/刪除,每次修改其實都是創建1個新的採集配置,歷史的採集配置需要手動清理,否則會造成資源浪費。

Kubernetes日誌採集最佳實踐

CRD配置方式是非常符合Kubernetes官方推薦的標準擴展方式,讓採集配置以K8s資源的方式進行管理,通過向Kubernetes部署AliyunLogConfig這個特殊的CRD資源來聲明需要採集的數據。例如下面的示例就是部署一個容器標準輸出的採集,其中定義需要Stdout和Stderr都採集,並且排除環境變量中包含COLLEXT_STDOUT_FLAG:false的容器。基於CRD的配置方式以Kubernetes標準擴展資源的方式進行管理,支持配置的增刪改查完整語義,而且支持各種高級配置,是我們極其推薦的採集配置方式。

Kubernetes日誌採集最佳實踐

採集規則推薦的配置方式



實際應用場景中,一般都是使用DaemonSet或DaemonSet與Sidecar混用方式,DaemonSet的優勢是資源利用率高,但有一個問題是DaemonSet的所有Logtail都共享全局配置,而單一的Logtail有配置支撐的上限,因此無法支撐應用數比較多的集群。上述是我們給出的推薦配置方式,核心的思想是:

  1. 一個配置儘可能多的採集同類數據,減少配置數,降低DaemonSet壓力;
  2. 核心的應用採集要給予充分的資源,可以使用Sidecar方式;
  3. 配置方式儘可能使用CRD方式;
  4. Sidecar由於每個Logtail是單獨的配置,所以沒有配置數的限制,這種比較適合於超大型的集群使用。

實踐1-中小型集群

Kubernetes日誌採集最佳實踐

絕大部分Kubernetes集群都屬於中小型的,對於中小型沒有明確的定義,一般應用數在500以內,節點規模1000以內,沒有職能明確的Kubernetes平臺運維。這種場景應用數不會特別多,DaemonSet可以支撐所有的採集配置:

  1. 絕大部分業務應用的數據使用DaemonSet採集方式
  2. 核心應用(對於採集可靠性要求比較高,例如訂單/交易系統)使用Sidecar方式單獨採集

實踐2-大型集群

Kubernetes日誌採集最佳實踐

對於一些用作PAAS平臺的大型/超大型集群,一般業務在1000以上,節點規模也在1000以上,有專門的Kubernetes平臺運維人員。這種場景下應用數沒有限制,DaemonSet無法支持,因此必須使用Sidecar方式,整體規劃如下:

  1. Kubernetes平臺本身的系統組件日誌、內核日誌相對種類固定,這部分日誌使用DaemonSet採集,主要為平臺的運維人員提供服務;
  2. 各個業務的日誌使用Sidecar方式採集,每個業務可以獨立設置Sidecar的採集目的地址,為業務的DevOps人員提供足夠的靈活性。


分享到:


相關文章: