返回文章列表

Kubernetes 日誌管理與 Fluentd 組態實戰

本文探討 Kubernetes 環境下的日誌管理挑戰,並提供使用 Fluentd 和 Fluent Bit 收集、轉發和分析日誌的實戰。文章涵蓋了日誌儲存位置、存取許可權、安全性考量以及 DaemonSet 組態最佳化等關鍵議題,並搭配實際案例和程式碼片段,演示如何組態

DevOps 容器技術

Kubernetes 環境的日誌分散於各節點,不易集中管理和查詢。透過 kubectl logs 命令雖可檢視個別 Pod 日誌,但缺乏全域性視角。此外,容器的 ephemeral 特性導致日誌檔案容易遺失,需要額外機制確保日誌持久化。本文將探討如何利用 Fluentd 和 Fluent Bit 構建 Kubernetes 日誌收集系統,解決日誌分散、許可權管理、安全性以及組態最佳化等問題,並提供實戰組態案例和程式碼片段。

Kubernetes 環境下的日誌管理挑戰

在 Kubernetes 環境中進行日誌管理時,我們面臨著多項挑戰。首先,日誌的儲存位置和存取許可權是主要問題。在預設情況下,Kubernetes 將日誌儲存在 /var/log/containers//var/log/pods/ 目錄下,但這些目錄下的檔案實際上是符號連結,指向 /var/lib/docker/containers/ 目錄下的真實日誌檔案。

存取主機日誌

要存取主機日誌,我們可以使用 minikube ssh 命令進入 Minikube 主機環境。透過這個命令,我們可以檢視 /var/log/containers/ 目錄下的內容,發現這些檔案都是符號連結,指向 /var/log/pods/ 目錄下的檔案。

minikube ssh
ls -al /var/log/containers

內容解密:

  • minikube ssh 命令允許我們進入 Minikube 主機環境。
  • ls -al /var/log/containers 命令用於檢視 /var/log/containers/ 目錄下的內容,並顯示詳細資訊,包括符號連結的目標。

進一步檢視 /var/log/pods/ 目錄,我們發現每個 Pod 的日誌都儲存在一個單獨的目錄下,並且檔名按照一定的規則遞增。

Fluent Bit 在 Kubernetes 中的應用

在 Kubernetes 環境中,除了使用 Fluentd 外,還可以考慮使用 Fluent Bit。Fluent Bit 具有較小的記憶體佔用和更快的處理速度,適合用於容器化環境中的日誌收集。

Fluent Bit 可以將日誌事件推播到專門的 Fluentd 節點或日誌分析平台(如 Elasticsearch),並在這些平台上進行進一步的處理和分析。

日誌存取許可權問題

在存取 /var/lib/docker/containers/ 目錄下的日誌檔案時,我們遇到了許可權限制的問題。需要使用 sudo 命令才能檢視該目錄下的內容。

sudo ls -al /var/lib/docker/containers/

內容解密:

  • sudo 命令用於提升許可權,以存取受限制的目錄。
  • ls -al /var/lib/docker/containers/ 命令用於檢視 /var/lib/docker/containers/ 目錄下的內容,並顯示詳細資訊。

這表明在組態日誌收集工具時,需要確保其具有足夠的許可權來存取這些日誌檔案。

安全性考量

Minikube 的日誌存取安全性較為寬鬆,一旦能夠存取一個日誌檔案,就可以存取所有日誌檔案。在生產環境中,這種安全性是不可接受的。因此,需要採取更為嚴格的安全措施,例如使用 sidecar 模式來控制日誌的可見性。

組態 Kubernetes 日誌 DaemonSet

在概述了相關概念後,我們可以合理地假設可以複製組態 YAML 以建立用於日誌記錄的 Kubernetes DaemonSet。我們可以在組態中利用 Fluentd 提供的現有 Docker 映象。YAML 組態需要提供特定的環境變數值並掛載正確的檔案系統部分。如果我們希望 DaemonSet 也應用一些自定義組態,則需要將額外的組態檔案對映到系統中。

與其設定許多環境值來控制當前的 Fluentd 組態,不如看看如何將 Fluentd 指向替代的組態檔案並注入修改後的組態。這也讓我們有機會解決 Docker 檔案中的內容佈局問題,這可能會影響下游應用程式。

準備 Fluentd 組態以供使用

使用自定義的 Fluentd 組態,我們可以透過修改 Docker 構建來佈署它。然而,一種更優雅的方法是利用 Kubernetes 組態的功能。這意味著,如果我們希望更改組態,只需重新佈署組態更改,而無需更改 Docker 映象和隨後的重新佈署步驟。這是可能的,因為 Fluentd Docker 檔案透過環境變數和適當放置的額外組態檔案來組態 Fluentd,這些檔案可以透過 includes 陳述式取得。

使用 Kubernetes ConfigMap 佈署組態

我們需要使用 Kubernetes ConfigMap 將 Fluentd 組態佈署到 Kubernetes 中。首先,我們需要建立 ConfigMap。ConfigMap 可以包含在我們的核心 Kubernetes YAML 檔案中,也可以單獨佈署。後一種方法更可取,因為我們可以使用 Fluentd dry-run 功能驗證組態,然後再佈署。

minikube kubectl -- create configmap fluentd-conf --from-file=Fluentd/custom.conf --namespace=kube-system

驗證 ConfigMap 佈署

可以使用儀錶板檢視組態並選擇 Config Maps(從左側選單)。然後,在儀錶板的中心部分,將看到所有 ConfigMap,包括我們的 fluentd-conf。可以透過點選 ConfigMap 的名稱來顯示其內容。

Fluentd 組態檔案

<system>
  Log_Level debug
</system>
<source>
  @type tail
  path /var/log/containers/*.log
  read_from_head true
  read_lines_limit 25
  tag deamonset
  path_key sourcePath
  emit_unmatched_lines true
  <parse>
    @type none
  </parse>
</source>
<match *>
  @type forward
  <buffer>
    buffer_type memory
    flush_interval 2s
  </buffer>
  <server>
    host "#{ENV['FLUENT_FOWARD_HOST']}"
    port "#{ENV['FLUENT_FOWARD_PORT']}"
  </server>
</match>

將內容傳遞給容器

Kubernetes 提供了多種方式將內容分享到容器中作為掛載路徑。ConfigMap 是不可變的(只讀),這非常適合我們的場景。ConfigMap 的內容可以透過環境變數、命令列值和檔案來消費,具體取決於所使用的選項。

建立 Kubernetes 佈署組態

讓我們修改並佈署標準的 Fluentd 儲存函式庫 DaemonSet 到我們的 minikube 環境中。首先,我們需要下載檔案並進行一些調整。

wget https://raw.githubusercontent.com/fluent/fluentd-kubernetes-daemonset/master/fluentd-daemonset-forward.yaml

然後,我們需要進行以下新增和修改:

  1. 設定我們要轉發日誌事件的 Fluentd 節點的位置。
  2. REMOTE_ENDPOINT 文字替換為主機的地址或 IP。

修改後的 YAML 組態

# 請根據實際情況修改以下值
env:
  - name: FLUENT_FOWARD_HOST
    value: "192.168.1.2"
  - name: FLUENT_FOWARD_PORT
    value: "24224"

組態 Kubernetes 日誌收集 DaemonSet

在 Kubernetes 環境中佈署 Fluentd 以收集日誌,需要對 DaemonSet 的組態進行一些調整。以下是具體步驟和相關說明。

修改環境變數與組態

  1. 調整 FLUENT_FOWARD_PORT:將預設的 18080 埠更改為 28080,以符合 Fluentd 節點組態中的埠設定。
  2. 新增 FLUENTD_SYSTEMD_CONF 環境變數:將其值設為 "FALSE",以避免使用 systemd 相關組態。
  3. 覆寫 FLUENTD_CONF 環境變數:指向透過 ConfigMap 提供的自定義 custom.conf 檔案。
  4. 新增 securityContext:將 privileged 屬性設為 true,以解決先前遇到的許可權問題。
  5. 掛載 ConfigMap:在 volumeMounts 中新增 config-volume,並將其掛載到 /fluentd/etc/custom/ 路徑下。
  6. 參照 ConfigMap:在 volumes 中新增 config-volume,並與 volumeMounts 中的名稱對應,參照名為 fluentd-conf 的 ConfigMap。

修改後的 DaemonSet 組態檔案

以下是修改後的 DaemonSet 組態檔案範例(部分內容):

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: kube-system
spec:
  selector:
    matchLabels:
      k8s-app: fluentd-logging
  template:
    metadata:
      labels:
        k8s-app: fluentd-logging
    spec:
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1-debian-forward
        env:
        - name: FLUENT_FOWARD_HOST
          value: "192.168.1.2"
        - name: FLUENT_FOWARD_PORT
          value: "28080"
        - name: FLUENTD_SYSTEMD_CONF
          value: "FALSE"
        - name: FLUENTD_CONF
          value: "custom/custom.conf"
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
        - name: config-volume
          mountPath: /fluentd/etc/custom/
        securityContext:
          privileged: true
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
      - name: config-volume
        configMap:
          name: fluentd-conf

內容解密:

  1. apiVersionkind:定義了 Kubernetes 資源的版本和型別,這裡使用的是 apps/v1 版本的 DaemonSet。
  2. metadata:提供了 DaemonSet 的後設資料,包括名稱和名稱空間。
  3. spec:定義了 DaemonSet 的規格,包括選擇器、範本和容器組態。
  4. env:設定了環境變數,如 FLUENT_FOWARD_HOSTFLUENT_FOWARD_PORT,用於組態 Fluentd 的轉發目標。
  5. volumeMountsvolumes:定義了容器內部的掛載點和對應的外部儲存卷,包括日誌檔案和 ConfigMap。

佈署 DaemonSet

在佈署 DaemonSet 之前,請確保本地的 Fluentd 例項已經啟動並準備好接收日誌事件。使用以下命令佈署 DaemonSet:

minikube kubectl -- apply -f Kubernetes/fluentd-daemonset.yaml --namespace=kube-system

可以使用下載包中的指令碼(deploy-deamonset.bat.sh)來簡化佈署過程,該指令碼會刪除現有的佈署並推播新的組態。

驗證佈署結果

佈署完成後,可以透過 Kubernetes 儀錶板檢視 DaemonSet 的狀態和相關 Pod 的日誌。如果沒有立即看到日誌,可以重新佈署 LogSimulator 組態來產生日誌事件。

圖示說明

此圖示展示了 Fluentd DaemonSet 的架構和日誌收集流程:

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 圖示說明

rectangle "日誌" as node1
rectangle "轉發" as node2
rectangle "輸出" as node3

node1 --> node2
node2 --> node3

@enduml

此圖示說明瞭 Kubernetes 叢集中的日誌如何透過 Fluentd DaemonSet 收集並轉發到 Fluentd 節點,最終儲存在日誌儲存中。

使用 Docker 和 Kubernetes 管理日誌的挑戰與解決方案

8.6.5 環境清理

在執行 Kubernetes 和下載各種 Docker 映像檔及 minikube 資源後,你會想要清除或重置環境。Minikube 提供了一個簡單卻優秀的功能,可以透過單一命令完全清除環境,以釋放資源或重置並重新驗證所有設定。這個命令是:

minikube delete

8.7 Kubernetes 設定實戰

我們已經建立了一個基本的設定,讓我們能夠在 Kubernetes 環境中檢視日誌事件。然而,這個設定還不夠完善,為了達到企業級的就緒狀態,我們需要改進這個設定。你的挑戰是找出必要的變更,並修改提供的設定。

8.7.1 解答

你應該識別出的變更包括以下幾點:

  • Tail 來源沒有記錄其在檔案中的追蹤位置,因此重啟可能會導致日誌事件的重複。
  • 需要將記錄的 pos_file 對應到掛載點,以便在 Pod 重啟時不會遺失位置資訊。
  • Tail 設定需要解決日誌輪替被管理的問題。
  • 應該透過設定提供和控制額外的 Kubernetes 監控指標和 Prometheus 資訊。
  • Kubernetes 核心元件(在 kube-system 名稱空間中)的日誌應該與託管應用程式的日誌分開標記,並且接收端應該區分這些標記。
  • 利用 Kubernetes 外掛程式為日誌事件加上額外的元資料標記。
  • 調整 Fluentd 的快取機制,使其更適合生產環境,並考慮 Kubernetes 提供的資源。
  • 將日誌級別從 debug 調整為 info。

8.8 更多需要關注的 Kubernetes 監控與日誌

8.8.1 節點監控

到目前為止,我們主要關注容器相關的核心日誌。但是,你可能還希望監控 Kubernetes 節點的健康狀況。有多種方法可以實作這一點,包括在原生節點上使用 Fluentd 或 Fluent Bit,以及監控伺服器的原始統計資料。不過,在某些環境中,這可能是不允許的。Kubernetes 也提供了一個額外的 DaemonSet,稱為 Node Problem Detector。

Node Problem Detector 是一個可選的 minikube 外掛程式,有些雲端供應商提供的預設 Kubernetes 叢集也採用了這種方式。因此,需要啟用 DaemonSet。Node Problem Detector 會監控核心日誌檔案,並根據設定報告特定的問題,這些設定可以透過 ConfigMap 修改,就像我們之前修改 Fluentd 設定一樣。Detector 包含一個 exporter 元件,可以將資訊傳送到不同的端點,包括 Kubernetes API 伺服器和 Stackdriver,這些都與我們的 Fluentd Daemon 相關。

建立自定義外掛程式

在本章中,我們將介紹建立輸入和輸出外掛程式的過程,這些外掛程式利用了 Redis 的列表功能。我們將更深入地瞭解 Redis 以及使用它的原因。

本章涵蓋以下主題:

  • 為 Redis 開發自定義的 Fluentd 外掛程式
  • 使用 Fluentd 公用程式加速開發
  • 實作 Fluentd 外掛程式生命週期方法
  • 測試和封裝自定義的 Fluentd 外掛程式
  • 為自定義外掛程式建立檔案
# 以下是一個簡單的 Ruby 程式碼範例,用於示範如何建立自定義的 Fluentd 外掛程式。
class CustomPlugin < Fluent::Plugin::Output
  # 在這裡實作外掛程式的邏輯
end

程式碼解密:

  1. 類別定義class CustomPlugin < Fluent::Plugin::Output 定義了一個名為 CustomPlugin 的新類別,它繼承自 Fluent::Plugin::Output。這是建立輸出外掛程式的基本結構。
  2. 外掛程式邏輯實作:在類別內部,你需要實作外掛程式的具體邏輯,例如如何處理和輸出日誌事件。
  3. 註冊外掛程式:在完成類別定義後,需要註冊這個外掛程式,以便 Fluentd 可以識別和使用它。

透過這種方式,你可以根據自己的需求建立自定義的 Fluentd 外掛程式,以擴充套件其功能。