今天(而且不僅僅是)Kubernetes 中的日誌:期望與現實

今天(而且不僅僅是)Kubernetes 中的日誌:期望與現實

現在已經是 2019 年了,我們在 Kubernetes 中仍然沒有標準的日誌聚合解決方案。 在這篇文章中,我們希望透過實際實踐中的例子來分享我們的探索、遇到的問題和解決方案。

不過,首先我要保留一點,不同的客戶透過收集日誌所理解的東西是非常不同的:

  • 有人想查看安全和審核日誌;
  • 有人 - 整個基礎設施的集中日誌記錄;
  • 對於某些人來說,僅收集應用程式日誌就足夠了,不包括平衡器等。

以下是我們如何實現各種「願望清單」以及遇到的困難的片段。

理論:關於日誌記錄工具

日誌系統組件的背景知識

日誌記錄已經取得了長足的進步,因此開發了收集和分析日誌的方法,這就是我們今天使用的方法。 早在 1950 世紀 XNUMX 年代,Fortran 就引入了標準輸入/輸出流的模擬,這有助於程式設計師調試程式。 這些是第一批電腦日誌,使當時的程式設計師的生活變得更加輕鬆。 今天我們在它們中看到了日誌系統的第一個元件 - 日誌的來源或“生產者”.

電腦科學並沒有停滯不前:電腦網路出現了,第一個集群......由多台電腦組成的複雜系統開始工作。 現在,系統管理員被迫從多台電腦收集日誌,在特殊情況下,他們可以新增作業系統核心訊息,以便需要調查系統故障。 為了描述集中式日誌收集系統,在 2000 年代初發布了 RFC 3164,標準化了remote_syslog。 這就是另一個重要組件的出現方式: 日誌收集器 以及它們的儲存。

隨著日誌量的增加和網路技術的廣泛引入,出現了需要方便地向使用者展示哪些日誌的問題。 簡單的控制台工具(awk/sed/grep)已被更高級的工具取代 記錄瀏覽者 - 第三部分。

由於日誌量的增加,其他事情變得清晰:日誌是需要的,但不是全部。 而且不同的日誌需要不同程度的保存:有些可能一天之內就會遺失,而有些則需要保存5年。 因此,在日誌系統中新增了一個用於過濾和路由資料流的元件——我們稱之為 篩選.

儲存也實現了重大飛躍:從常規文件到關聯式資料庫,再到面向文件的儲存(例如Elasticsearch)。 所以儲存與收集器是分開的。

最終,日誌的概念已經擴展為一種我們想要保存為歷史的抽象事件流。 或者更確切地說,如果您需要進行調查或起草分析報告...

因此,在較短的時間內,日誌擷取已發展成為一個重要的子系統,堪稱大數據的子系統之一。

今天(而且不僅僅是)Kubernetes 中的日誌:期望與現實
如果以前普通的印刷品足以滿足「記錄系統」的需要,那麼現在情況已經發生了很大變化。

Kubernetes 和日誌

當 Kubernetes 來到基礎架構時,已經存在的日誌收集問題也沒有繞過。 在某些方面,它變得更加痛苦:基礎設施平台的管理不僅被簡化,同時也變得複雜。 許多舊服務已經開始遷移到微服務。 在日誌方面,這體現在越來越多的日誌來源、其特殊的生命週期以及需要透過日誌追蹤所有系統元件的關係…

展望未來,我可以說,不幸的是,現在 Kubernetes 還沒有一個可以與其他所有日誌選項相媲美的標準化日誌選項。 社區中最受歡迎的方案如下:

  • 有人展開堆疊 EFK (Elasticsearch、Fluentd、Kibana);
  • 有人正在嘗試最近發布的 洛基 或使用 記錄操作員;
  • 我們 (也許不只是我們?..) 我對自己的發展非常滿意—— 木屋...

通常,我們在 K8s 叢集中使用以下捆綁包(用於自架解決方案):

不過,我不會詳細介紹它們的安裝和配置說明。 相反,我將重點關注它們的缺點以及關於日誌總體情況的更全面的結論。

在 K8s 中使用日誌進行練習

今天(而且不僅僅是)Kubernetes 中的日誌:期望與現實

“日常日誌”,你們有多少人?

從相當大的基礎架構中集中收集日誌需要大量資源,這些資源將用於收集、儲存和處理日誌。 在各個專案的營運過程中,我們面臨著各種各樣的需求以及由此產生的營運問題。

讓我們試試看 ClickHouse

讓我們來看看一個項目的集中式存儲,該項目的應用程式生成日誌非常活躍:每秒超過 5000 行。 讓我們開始處理他的日誌,將它們加入 ClickHouse 中。

一旦需要最大即時性,具有 ClickHouse 的 4 核心伺服器的磁碟子系統就已經過載:

今天(而且不僅僅是)Kubernetes 中的日誌:期望與現實

這種類型的載入是因為我們試圖盡快在 ClickHouse 中編寫。 資料庫會透過增加磁碟負載來對此作出反應,這可能會導致以下錯誤:

DB::Exception: Too many parts (300). Merges are processing significantly slower than inserts

事實是, 合併樹表 ClickHouse中的(它們包含日誌資料)在寫入操作時有自己的困難。 插入其中的資料會產生一個臨時分割區,然後與主表合併。 這樣一來,記錄對磁碟的要求非常高,而且還受到上面通知的限制:1秒內不能合併超過300個子分割區(實際上這是300個插入)每秒)。

為了避免這種行為, 應該寫給 ClickHouse 盡可能大的片段,並且每 1 秒不超過 2 次。 然而,大量的寫入表明我們應該減少在 ClickHouse 中的寫入頻率。 這反過來又可能導致緩衝區溢位和日誌遺失。 解決方案是增加Fluentd緩衝區,但這樣記憶體消耗也會增加。

注意:我們的 ClickHouse 解決方案的另一個問題與我們的案例(木屋)中的分區是透過連接的外部表實現的這一事實有關 合併表。 這導致了這樣一個事實:當對大時間間隔進行採樣時,需要過多的 RAM,因為元表會迭代所有分區 - 即使是那些顯然不包含必要數據的分區。 然而,現在可以安全地宣布這種方法對於當前版本的 ClickHouse 來說已過時(c 18.16).

由此可見,並非每個專案都有足夠的資源在 ClickHouse 中即時收集日誌(更準確地說,它們的分佈並不合適)。 此外,您還需要使用 電池,我們稍後會返回。 上述案例是真實存在的。 當時我們無法提供適合客戶並允許我們以最小延遲收集日誌的可靠且穩定的解決方案...

彈性搜尋怎麼樣?

眾所周知,Elasticsearch 可以處理繁重的工作負載。 讓我們在同一個項目中嘗試一下。 現在負載看起來像這樣:

今天(而且不僅僅是)Kubernetes 中的日誌:期望與現實

Elasticsearch 能夠消化資料流,但是向其中寫入此類磁碟區會大大利用 CPU。 這是透過組織集群來決定的。 從技術上講,這不是問題,但事實證明,僅僅為了操作日誌收集系統,我們就已經使用了大約 8 個核心,並且系統中還有一個額外的高負載組件...

底線:此選項是合理的,但前提是專案很大並且其管理層準備在集中式日誌記錄系統上花費大量資源。

那麼一個自然的問題就出現了:

真正需要什麼日誌?

今天(而且不僅僅是)Kubernetes 中的日誌:期望與現實 讓我們嘗試改變方法本身:日誌應該同時提供資訊而不是覆蓋 каждое 系統中的事件。

假設我們有一個成功的線上商店。 哪些日誌很重要? 收集盡可能多的資訊(例如從支付網關收集資訊)是個好主意。 但並非產品目錄中影像切片服務的所有日誌對我們都至關重要:只有錯誤和進階監控就足夠了(例如,該元件產生的 500 個錯誤的百分比)。

所以我們得出的結論是 集中式日誌記錄並不總是合理的。 很多時候,客戶端希望將所有日誌收集到一個地方,儘管事實上,從整個日誌中,只需要有條件的 5% 對業務至關重要的訊息:

  • 有時,僅設定容器日誌和錯誤收集器(例如 Sentry)的大小就足夠了。
  • 錯誤通知和大型本地日誌本身通常足以調查事件。
  • 我們的專案僅使用功能測試和錯誤收集系統。 開發人員不需要這樣的日誌 - 他們可以從錯誤追蹤中看到一切。

來自生活的插畫

另一個故事可以作為一個很好的例子。 我們收到了一位客戶安全團隊的請求,該客戶已經在使用早在 Kubernetes 推出之前就開發的商業解決方案。

有必要將集中式日誌收集系統與企業問題偵測感測器QRadar「交朋友」。 該系統可以透過 syslog 協定接收日誌並從 FTP 檢索它們。 但是,無法立即將其與 Fluentd 的 Remote_syslog 插件集成 (事實證明, 我們並不孤單)。 事實證明,設定 QRadar 時出現的問題出在客戶安全團隊這邊。

結果,部分業務關鍵日誌被上傳到 FTP QRadar,另一部分透過遠端系統日誌直接從節點重新導向。 為此我們甚至寫了 簡單圖表 - 也許它將幫助某人解決類似的問題...由於最終的方案,客戶自己接收並分析了關鍵日誌(使用他最喜歡的工具),我們能夠降低日誌系統的成本,僅節省上個月。

另一個例子很能說明什麼是不該做的事。 我們的一位加工客戶 每個 來自使用者的事件,做成多行 非結構化輸出 日誌中的資訊。 正如您可能猜到的那樣,此類日誌的讀取和儲存都極其不方便。

日誌標準

這樣的例子得出的結論是,除了選擇日誌收集系統之外,您還需要 還自己設計日誌! 這裡有什麼要求?

  • 日誌必須採用機器可讀的格式(例如 JSON)。
  • 日誌應該緊湊,並且能夠更改日誌記錄的程度,以便調試可能的問題。 同時,在生產環境中,您應該運行具有以下日誌等級的系統 警告錯誤.
  • 日誌必須規範化,即在一個日誌物件中,所有行必須具有相同的欄位類型。

非結構化日誌可能會導致將日誌載入到儲存中時出現問題並導致其處理完全停止。 作為說明,以下是一個錯誤 400 的範例,許多人在 fluidd 日誌中肯定遇到過該錯誤:

2019-10-29 13:10:43 +0000 [warn]: dump an error event: error_class=Fluent::Plugin::ElasticsearchErrorHandler::ElasticsearchError error="400 - Rejected by Elasticsearch"

該錯誤表示您正在將一個類型不穩定的欄位傳送到具有現成映射的索引。 最簡單的例子是 nginx 日誌中帶有變數的字段 $upstream_status。 它可以包含數字或字串。 例如:

{ "ip": "1.2.3.4", "http_user": "-", "request_id": "17ee8a579e833b5ab9843a0aca10b941", "time": "29/Oct/2019:16:18:57 +0300", "method": "GET", "uri": "/staffs/265.png", "protocol": "HTTP/1.1", "status": "200", "body_size": "906", "referrer": "https://example.com/staff", "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36", "request_time": "0.001", "cache_status": "-", "upstream_response_time": "0.001, 0.007", "upstream_addr": "127.0.0.1:9000", "upstream_status": "200", "upstream_response_length": "906", "location": "staff"}
{ "ip": "1.2.3.4", "http_user": "-", "request_id": "47fe42807f2a7d8d5467511d7d553a1b", "time": "29/Oct/2019:16:18:57 +0300", "method": "GET", "uri": "/staff", "protocol": "HTTP/1.1", "status": "200", "body_size": "2984", "referrer": "-", "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36", "request_time": "0.010", "cache_status": "-", "upstream_response_time": "0.001, 0.007", "upstream_addr": "10.100.0.10:9000, 10.100.0.11:9000", "upstream_status": "404, 200", "upstream_response_length": "0, 2984", "location": "staff"}

日誌顯示伺服器 10.100.0.10 回應了 404 錯誤,並且請求被傳送到另一個內容儲存。 結果,日誌中的值變成了這樣:

"upstream_response_time": "0.001, 0.007"

這種情況非常普遍,甚至值得單獨討論 文件中的引用.

可靠性怎麼樣?

有時,所有日誌無一例外都至關重要。 因此,上面提出/討論的典型的 K8 日誌收集方案存在問題。

例如,Fluentd 無法從短期容器中收集日誌。 在我們的一個專案中,資料庫遷移容器存活了不到 4 秒,然後被刪除 - 根據相應的註釋:

"helm.sh/hook-delete-policy": hook-succeeded

因此,遷移執行日誌未包含在儲存中。 在這種情況下,政治可以提供幫助。 before-hook-creation.

另一個例子是 Docker 日誌輪轉。 假設有一個應用程式主動寫入日誌。 在正常情況下,我們設法處理所有日誌,但是一旦出現問題 - 例如,如上所述,格式不正確 - 處理就會停止,並且 Docker 會輪換檔案。 結果是關鍵業務日誌可能會遺失。

這就是原因 分離日誌流很重要,將最有價值的郵件直接發送到應用程式中以確保其安全。 此外,創造一些也不是多餘的 日誌的“累加器”,它可以在短暫的儲存不可用的情況下生存,同時保存關鍵訊息。

最後,我們一定不要忘記 正確監控任何子系統非常重要。 否則很容易遇到 fluidd 處於這種狀態的情況 CrashLoopBackOff 並且不發送任何內容,這可能會丟失重要資訊。

發現

在本文中,我們不會討論 Datadog 等 SaaS 解決方案。 這裡描述的許多問題已經被專門收集日誌的商業公司以這種或那種方式解決了,但由於各種原因並不是每個人都可以使用SaaS (主要是成本和遵守152-FZ).

集中式日誌收集乍看之下似乎是一項簡單的任務,但事實並非如此。 重要的是要記住:

  • 僅需詳細記錄關鍵組件,而可為其他系統配置監控和錯誤收集。
  • 生產中的日誌應保持最少,以免增加不必要的負載。
  • 日誌必須是機器可讀的、規範化的並且具有嚴格的格式。
  • 真正關鍵的日誌應該在單獨的流中發送,該流應該與主要日誌分開。
  • 值得考慮日誌累加器,它可以使您免於突發的高負載並使儲存空間上的負載更加均勻。

今天(而且不僅僅是)Kubernetes 中的日誌:期望與現實
這些簡單的規則如果應用於各處,將使上述電路正常工作 - 即使它們缺少重要組件(電池)。 如果您不遵守這些原則,該任務將很容易將您和基礎架構引導到系統的另一個高負載(同時無效)的元件。

聚苯乙烯

另請閱讀我們的博客:

來源: www.habr.com

添加評論