返回文章列表

Kubernetes 日誌收集與 Fluentd 最佳實踐

本文探討如何在 Kubernetes 叢集中使用 Fluentd 和 DaemonSet 進行高效的日誌收集和管理,涵蓋了日誌模擬器的使用、minikube 環境設定、Fluentd DaemonSet 佈署、Kubernetes 中繼資料處理以及 Docker 映象管理等關鍵導向,並提供最佳實踐和組態範例。

DevOps 容器化

Kubernetes 提供多種機制檢查容器健康狀態,但要確保系統穩定執行,還需收集 Kubernetes 內部程式的日誌,例如 Kubelet 的錯誤日誌。Fluentd DaemonSet 可有效收集這些日誌,並將其轉發到目標系統,如 Elasticsearch。本文將示範如何使用 minikube 建立單節點 Kubernetes 叢集,佈署 LogSimulator 產生日誌,並使用 Fluentd DaemonSet 收集日誌。過程中會詳細說明 DaemonSet 的 YAML 設定檔、容器映像設定、主機目錄掛載,以及如何透過 Kubernetes 儀錶板監控 Pod 狀態和日誌輸出。此外,還會探討如何使用 Helm 簡化 Fluentd 佈署,以及如何利用 Kubernetes 中繼資料過濾器豐富日誌資訊。最後,將分享一些 Kubernetes 與 Docker 日誌管理的最佳實踐,例如環境變陣列態、Docker 映象多架構構建,以及 Fluentd 組態檔案的 include 機制。

使用 Kubernetes 示範日誌記錄

需要收集 Kubernetes 程式日誌,並瞭解 Kubelet 等內部容器程式是否正在記錄錯誤。Kubernetes 提供了許多機制來檢查容器的健康狀態。然而,瞭解 Kubernetes 中的所有事物是否正常運作對於判斷容器是否被正確管理或節點是否正在慢慢失效至關重要。如果應用程式將事件記錄到主控台並傳送到 Kubernetes,那麼我們該如何檢索這些事件?

簡化佈署到 Kubernetes

為了簡化佈署到 Kubernetes 的過程,Kubernetes 生態系統中開發了多種工具,例如 Helm (https://helm.sh)和 Rancher (https://rancher.com)。其中,Helm 是較為主流的解決方案,甚至被稱為 Kubernetes 的套件管理器。

由於 Helm 的流行,Fluentd 的提交者開發了 Helm 設定檔(稱為 charts)來支援 Fluentd 的佈署。這些 charts 將佈署所需的設定細節進行整合和定義,然後由 Helm 使用範本和指令碼完成剩餘的工作。Fluentd GitHub 儲存函式庫(https://github.com/fluent/helm-charts)中提供的 DaemonSet chart 提供了一個基本的起點,讓您可以根據自己的需求進行組態。如果您經常參與 Kubernetes 佈署的開發,那麼建議您研究 Helm 並利用 Fluentd charts。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
spec:
  selector:
    matchLabels:
      name: fluentd
  template:
    metadata:
      labels:
        name: fluentd
    spec:
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

內容解密:

  1. apiVersionkind 指定了 Kubernetes 資源的版本和型別,在此範例中是 DaemonSet
  2. metadata 部分定義了 DaemonSet 的名稱,這裡是 fluentd
  3. spec 部分描述了 DaemonSet 的期望狀態,包括選擇器、範本和容器定義。
  4. selectortemplate.metadata.labels 確保 DaemonSet 管理具有相應標籤的 Pod。
  5. containers 部分定義了在 Pod 中執行的容器,此處使用的是 fluent/fluentd-kubernetes-daemonset:v1 映象。
  6. volumeMounts 將主機上的目錄掛載到容器內的特定路徑,用於存取日誌檔案。
  7. volumes 部分定義了主機上的路徑,並將其與容器中的掛載點對應起來,以便 Fluentd 可以讀取所需的日誌檔案。

此 Plantuml 圖表描述了 Fluentd 在 Kubernetes 中的佈署架構:

@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
rectangle "輸出" as node4

node1 --> node2
node2 --> node3
node3 --> node4

@enduml

此圖示展示了 Fluentd DaemonSet 如何管理 Pod、讀取主機上的日誌檔案、處理日誌資料並將其輸出到目標系統(如 Elasticsearch)。

使用 Docker 和 Kubernetes 驅動日誌記錄

為瞭解決日誌記錄的問題,我們將佈署一個包含 LogSimulator 的 pod,該 pod 組態為將日誌事件導向 stdout。日誌事件將透過容器機制傳播,並讓 Fluentd 在 Kubernetes 層攔截它們,從而捕捉 Kubernetes 和容器內部日誌。這可能反映了十二要素應用程式(https://12factor.net/logs)所描述的推薦設定。但是,在許多方面,它代表了一種最壞情況,因為我們必須投入精力來推導上下文(區分 stdout 中的多個日誌事件,它們可能來自平台或容器與應用程式等)並重構日誌事件。

8.4.1 Kubernetes 設定

為了演示 Kubernetes 組態,我們將使用 minikube。Minikube 是 Kubernetes 的一個縮減版本,旨在保持盡可能緊湊的足跡。如果您尚未按照附錄 A 中的說明安裝 minikube,那麼現在是最佳時機。完成後,您的環境將如圖 8.4 所示。

圖 8.4 使用 minikube 確保主機環境不受幹擾的作業系統和虛擬化及容器化層

使用以下命令在 Windows 上啟動 minikube:

minikube start --vm-driver hyperv --hyperv-virtual-switch "Primary Virtual Switch"

Linux 上的等效命令是:

minikube start --vm-driver docker

這將建立一個單節點的 Kubernetes「叢集」,精簡到最小組態。下載包中包含 Linux shell 和 Windows 批處理指令碼,這些指令碼將執行此命令(使其比每次記住或複製命令更容易)。

然後,我們可以使用以下命令在 Windows 或 Linux 上啟動儀錶板:

minikube dashboard

此命令啟動一個前台程式,該程式將佈署必要的 pod 以執行儀錶板 UI 並提供儀錶板頁面 URL。開啟儀錶板頁面後,我們可以使用 UI 左側選單導航,檢視目前佈署的 DaemonSets、Deployments 和 Pods(作為選單的 Workloads 部分)。正如您在圖 8.5 中看到的那樣,目前沒有佈署任何 DaemonSets。您將找到基本的 hello-minikube 佈署和相關的 pod 正在執行。

圖 8.5 在 minikube 上執行的 Kubernetes 儀錶板,目前僅顯示預設名稱空間,而不是 kube 系統或大多數 DaemonSets 將被佈署的位置

簡化導航至所有名稱空間

可以透過將 Kubernetes 標誌旁邊的下拉選單設定為 All Namespaces 而不是 default(如圖 8.5 所示)來簡化 UI 導航;這將使檢視詳細資訊變得更容易。否則,您可能會在導航 UI 時感到困惑,不知道為什麼看不到預期的資訊,例如 Fluentd DaemonSets。在我們的環境中,顯示所有內容(即所有名稱空間)不會造成問題,但在生產設定中,我們不建議這樣做。

8.4.2 建立日誌以捕捉

首先,我們需要一個應用程式來生成日誌事件,以便觀察日誌 DaemonSet 從 Kubernetes 和應用程式收集事件(即,它們只是將日誌傳送到 stdout 和 stderr)。為此,我們可以使用容器化的 LogSimulator 版本。該工具的容器化版本預設組態為迴圈遍歷一個簡單的資料集幾次,然後停止。每個日誌事件都寫入 stdout;因此,日誌事件將被 Kubernetes 收集。當 LogSimulator pod 完成其執行時,它將停止 pod,此時 Kubernetes 將介入以重新啟動佈署。

LogSimulator Docker 映象已經存在於 Docker Hub 中。使用此 Docker 映象在 pod 中的 Kubernetes 組態如下所示,可以從 http://mng.bz/5KQB 取得。由於不需要任何組態或外部端點,因此 YAML 組態非常簡單。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: log-simulator
  labels:
    app: log-simulator
spec:
  replicas: 1
  selector:
    matchLabels:
      app: log-simulator
  template:
    metadata:
      labels:
        app: log-simulator
    spec:
      containers:
      - name: log-simulator
        image: mp3monster/log-simulator:v1

清單 8.2 Chapter8/LogGenerator/Kubernetes/log-simulator-deployment.yaml

要佈署此 pod,您需要確保定義了環境變數 LogSimulator-Home,它參照了先前安裝的 LogGenerator 的根資料夾。或者,編輯提供的指令碼(deploy-log-sim-k8.bat 或 deploy-log-sim-k8.sh),用絕對路徑替換環境變數參照。如果使用指令碼,它將始終嘗試首先刪除任何可能的現有 pod 佈署,以確保安全。這意味著,如果您想重新佈署,只需使用指令碼。要自行發出佈署命令,請在 shell 中發出以下陳述式:

minikube kubectl -- apply -f %LogSimulatorHome%\Kubernetes\log-simulator-deployment.yaml --namespace=default

Minikube 應確認佈署成功。

程式碼解密:

此 YAML 組態檔案定義了一個名為 log-simulator 的 Deployment 物件,該物件使用 mp3monster/log-simulator:v1 映象建立一個 pod。該組態檔案指定了 Deployment 的後設資料、規格和範本。在範本中,定義了一個名為 log-simulator 的容器,該容器使用指定的映象。該 Deployment 將確保始終有一個 log-simulator pod 在執行。

此組態檔案的關鍵元素包括:

  • apiVersionkind:定義了 Kubernetes 物件的版本和型別。
  • metadata:提供了物件的後設資料,如名稱和標籤。
  • spec:定義了物件的規格,如副本數量和選擇器。
  • template:定義了 pod 的範本,包括後設資料和規格。
  • containers:定義了 pod 中的容器,包括名稱和映象。

透過應用此組態檔案,Kubernetes 將建立一個 log-simulator Deployment,並確保始終有一個 pod 在執行,以生成日誌事件供 Fluentd 收集。

使用 Kubernetes 進行日誌蒐集的示範

瞭解日誌模擬器的運作視角

在進一步探討 DaemonSet 之前,我們先來「窺視引擎蓋內部」,看看事情是如何運作的。由於我們之前已經啟動了 Kubernetes 儀錶板,我們可以利用它來幫助我們。我們需要存取 Pod 清單(左側選單選項),這樣我們就會看到如圖 8.6 所示的詳細資訊。我們需要存取 log-simulator Pod 例項,可以透過點選以 log-simulator 開頭的名稱來完成。

minikube CLI 與 kubectl 的區別

minikube 命令和 kubectl 命令之間的差異很小。Minikube 對 kubectl 的使用進行了封裝,以便 minikube 命令可以提供額外的命令和 kubectl 命令。如果你已經安裝了 kubectl,則可以將其組態為將指令直接傳送到 minikube 的 Kubernetes 例項。這樣,你就可以用 kubectl 取代命令中以 minikube kubectl – 開頭的部分。對於 Linux 主機,還可以透過使用命令 alias kubectl="minikube kubectl --" 在 Linux 環境中建立別名。這樣,當你使用 kubectl 命令時,Linux 就會將其替換為完整的表示式。如果你發現自己需要使用 sudo 字首來確保許可權正確,你也可以將其納入別名中。

alias kubectl="minikube kubectl --"

內容解密:

此段落程式碼定義了一個別名 kubectl,使其等同於 minikube kubectl --。這樣做的好處是簡化了命令輸入,同時保持與 minikube 的相容性。

  • 使用 alias 命令定義別名是 Linux 中的一種常見做法,可以提高命令輸入的效率。
  • minikube kubectl -- 替換為 kubectl,使得在 minikube 環境中使用原生 kubectl 命令成為可能。
  • 這種做法對於需要在 minikube 環境中頻繁使用 kubectl 命令的開發者來說非常有用。

這將顯示有關特定 Pod 的詳細資訊,螢幕頂部看起來會像圖 8.7 所示的詳細資訊。

瞭解 Fluentd DaemonSets 的組成

我們在第 2 章中首次接觸到 Kubernetes,並簡要介紹了使用 Fluentd 提供的 DaemonSet。我們提到 Kubernetes 的組態可能會很複雜。然而,給定我們用於 LogGenerator 的 Kubernetes.yaml 檔案,可能會讓人對此產生疑問。讓我們花一點時間來逐步瞭解 Fluentd 的 Kubernetes 和 Docker 資源所涉及的內容。有幾個重要的儲存函式庫與此相關,具體如下:

  • Kubernetes DaemonSet 在 GitHub 上 - 這是大多數必要實作細節所在。
  • Docker 檔案基礎映像 - 這些是 Docker 基礎映像,包括用於生成不同 OS 變體的範本機制。
  • Docker Hub 儲存函式庫 - 這是 Kubernetes 組態提取 Docker 映像的地方。
  • 後設資料過濾器 - 這被納入 DaemonSet 中,豐富了 Kubernetes 日誌記錄的上下文。

當你存取 Fluentd 的 DaemonSets 的 GitHub 儲存函式庫時,你會看到一系列 YAML 檔案。Fluentd 社群提供了一系列標準化的組態,用於捕捉 Kubernetes 日誌並將內容傳送到單個目標。這些組態的範圍從將內容轉發到另一個 Fluentd 節點,到傳送到由 AWS、Azure 和 Google 提供的各種雲原生服務,再到 Elasticsearch 和 Syslog 等專用服務。

在檢查 Kubernetes YAML 組態時,你會發現它們在本質上都非常相似,具有以下特點:

  • 設定映像,使其將被佈署在 kube-system 名稱空間中
  • 參照合適的容器映像
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 瞭解 Fluentd DaemonSets 的組成

rectangle "佈署" as node1
rectangle "收集" as node2
rectangle "傳送" as node3
rectangle "儲存" as node4

node1 --> node2
node2 --> node3
node3 --> node4

@enduml

此圖示描述了 Kubernetes 中 Fluentd DaemonSet 的佈署和日誌收集流程。

圖表內容解密:

此圖表展示了 Kubernetes 環境中使用 Fluentd DaemonSet 進行日誌收集和處理的流程。

  • Kubernetes 佈署 Fluentd DaemonSet 到叢集中。
  • Fluentd DaemonSet 負責收集節點上的日誌。
  • 蒐集到的日誌被傳送到指定的目標服務。
  • 目標服務將日誌儲存起來,用於後續的分析和處理。

Kubernetes 與 Docker 日誌管理最佳實踐

在現代化的雲端原生應用中,Kubernetes 和 Docker 已成為容器化佈署的主流技術。然而,隨著容器數量的增加,日誌管理成為了一項挑戰。本篇文章將探討如何使用 Fluentd 與 Kubernetes DaemonSet 來實作高效的日誌收集和管理。

環境變數與組態管理

在佈署 Fluentd 到 Kubernetes 叢集時,我們需要定義多個環境變數來控制 Fluentd 的行為。這些變數包括:

  • 連線外部服務的 host 和 port
  • 組態資源分配給容器
  • 定義主機檔案位置在容器內的對映

這些環境變數可以在 DaemonSet 的組態中定義,例如:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
spec:
  selector:
    matchLabels:
      name: fluentd
  template:
    metadata:
      labels:
        name: fluentd
    spec:
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1.12
        env:
        - name: FLUENTD_SYSTEMD_CONF
          value: "true"
        - name: FLUENTD_PROMETHEUS_CONF
          value: "true"

內容解密:

此組態定義了一個名為 fluentd 的 DaemonSet,使用 fluent/fluentd-kubernetes-daemonset:v1.12 映象,並設定了兩個環境變數 FLUENTD_SYSTEMD_CONFFLUENTD_PROMETHEUS_CONF"true",以啟用 systemd 和 Prometheus 的組態。

Docker 映象管理

Fluentd 的 Docker 映象需要根據不同的硬體架構(例如 x86_64 和 arm64)進行構建。這是因為 Docker 映象需要包含特定於硬體的二進位制檔案。

# x86_64 映象
FROM x86_64/ubuntu:latest

# arm64 映象
FROM arm64v8/ubuntu:latest

內容解密:

此 Dockerfile 使用多階段構建,分別為 x86_64 和 arm64 架構構建不同的映象。這確保了 Fluentd 可以在不同的硬體平台上執行。

Fluentd 組態與擴充套件

Fluentd 的組態檔案使用 include 機制來引入其他組態檔案,例如 fluent.confsystemd.confprometheus.conf

# fluent.conf
<source>
  @type tail
  path /var/log/containers/*.log
  pos_file /var/log/fluentd-containers.log.pos
  tag "kubernetes.*"
</source>

<match kubernetes.**>
  @type forward
  # ...
</match>

內容解密:

此組態定義了一個 tail 輸入外掛,用於讀取 /var/log/containers/ 目錄下的日誌檔案,並使用 forward 輸出外掛將日誌轉發到目標伺服器。

Kubernetes 中繼資料處理

Fluentd 使用 kubernetes_metadata 過濾器來處理 Kubernetes 中繼資料,例如 pod 名稱、namespace 和 label。

# kubernetes.conf
<filter kubernetes.**>
  @type kubernetes_metadata
  # ...
</filter>

內容解密:

此組態定義了一個 kubernetes_metadata 過濾器,用於從 Kubernetes API 中檢索中繼資料,並將其新增到日誌事件中。