Kubernetes 集羣日誌 和 EFK 架構日誌方案 (轉)


 

 


本文主要參考以下兩個文章,對文章內容進行翻譯整合。

 

https://devopscube.com/kubernetes-logging-tutorial/

https://devopscube.com/setup-efk-stack-on-kubernetes/

第一部分:Kubernetes 日誌

在這個 Kubernetes 日誌教程中,您將學習 Kubernetes 集羣日誌中涉及的關鍵概念和工作流。

當涉及到 Kubernetes 生產調試時,日誌起着至關重要的作用。它可以幫助你理解正在發生的事情,哪裏出了問題,甚至是哪裏可能出問題。作爲一名 DevOps 工程師,您應該清楚地瞭解 Kubernetes 日誌以解決集羣和應用程序問題。

Kubernetes Logging 是如何工作的

在 Kubernetes,大多數組件都是以容器方式運行的。在 kubernetes 架構中,一個應用程序 Pod 可以包含多個容器,大多數 Kubernetes 集羣組件都是這樣,如 api-server、 kube-scheduler、 Etcd、 kube 代理等等,會以容器方式運行。但是,kubelet 組件以本機 systemd 服務運行。

在這一節中,我們將看看日誌是如何爲 Kubernetes Pod 工作的。它可以是一個 Application Pod 或 Kubernetes component Pod。我們還將研究如何管理 kubelet systemd 日誌。

通常,我們在 Kubernetes 上部署的任何 Pod 都會將日誌寫入 stdout 和 stderr 流,而不是將日誌寫入專用的日誌文件。但是,來自每個容器的對 stdout 和 stderr 的流都以 JSON 格式存儲在文件系統中。底層容器引擎完成這項工作,它被設計用來處理日誌記錄。例如,Docker 容器引擎。

筆者注:這段話的意思是容器應用的日誌通過控制檯輸出時,會被容器引擎收集,這些日誌流會被以 Json 文件的形式存儲到文件系統中。

容器的日誌收集方式後面提到。

注意: 所有 kubernetes 集羣組件日誌都是像處理其他容器日誌一樣處理的。

Kubelet 在所有節點上運行,以確保節點上的容器正常運行。它還負責運行的靜態 Pod 以及,如果 kubelet 作爲一個系統服務運行,它將日誌記錄到 journald(systemd-journald )。

另外,如果容器沒有將日誌傳輸到 stdout 和 stderr,您將不會使用 kubetl logs 命令獲得日誌,因爲 kubelet 無法訪問日誌文件。

筆者注:例如 Pod 在節點 B 中運行,但是你在 A 節點執行 kubectl logs 命令,Pod 的日誌不會憑空飛過去,是通過 kubelet 傳輸過去的。

這一小節說的是,程序的日誌要通過 stdout 和 stderr 輸出,纔會被 Kubernetes 利用(kubectl logs),而在節點間傳輸日誌的組件叫 kubelet。因爲 kubelet不是以 Pod 而是以 systemd 的形式運行,因此 kubelet 自身的日誌要通過 systemd-journald 查看。

Kubernetes Pod 日誌存儲位置

您可以在以下每個工作節點的目錄中找到 kubernetes 存儲的 Pod 日誌。

  1. /var/log/containers: 所有容器日誌都存在於一個單獨的位置;
  2. /var/log/pods/: 在此位置下,容器日誌被組織到單獨的 pod 文件夾中。/var/log/pods/<namespace>_<pod_name>_<pod_id>/<container_name>/.每個 pod 文件夾包含單個容器文件夾及其各自的日誌文件。每個文件夾都有一個命名方案;

另外,如果您的底層容器工程師是 docker,您將在 /var/lib/docker/containers 文件夾中找到日誌。

image-20220213091744268

日誌以 Json 的形式記錄,還會記錄日誌的一些屬性信息。

{"log":"Shutting down, got signal: Terminated\n","stream":"stderr","time":"2021-11-09T06:14:42.535854831Z"}

如果您登錄到任何 Kubernetes 工作者節點並轉到 /var/log/containers 目錄,您將找到該節點上運行的每個容器的日誌文件。日誌文件命名方案遵循 /var/log/pods/<namespace>_<pod_name>_<pod_id>/<container_name>/。下面的圖片顯示了一個例子。

image-20220213091606019

此外,這些日誌文件由 Kubelet 控制,因此當您運行 kubectl logs命令時,Kubelet 會在終端中顯示這些日誌。

Kubelet Logs

對於 Kubelet,您可以使用 journalctl 從單個工作者節點訪問日誌。例如,使用以下命令檢查 Kubelet 日誌。

journalctl -u kubelet
journalctl -u kubelet -o cat

如果 Kubelet 在沒有 systemd 的情況下運行,您可以在 /var/log 目錄中找到 Kubelet 日誌。

Kubernetes 容器日誌格式

下面是容器日誌的其中一行數據示例:

{"log":"Shutting down, got signal: Terminated\n","stream":"stderr","time":"2021-11-09T06:14:42.535854831Z"}

如前所述,所有日誌數據都以 JSON 格式存儲。因此,如果打開任何一個日誌文件,就會發現每個日誌條目都有三個鍵。

  1. log-實際的日誌數據
  2. stream – 寫入日誌的流
  3. time – Timetamp 時間表

Kubernetes 日誌的類型

說到 Kubernetes,以下是不同類型的日誌。

  1. Application logs: 來自用戶部署的應用程序的日誌。應用程序日誌有助於理解應用程序內部發生的事情。

  2. Kubernetes Cluster components(集羣組件):來自 api-server、 kube-scheduler、 etcd、 kube-proxy 等的日誌。

  3. Kubernetes Audit logs(審計日誌): 所有與 API 服務器記錄的 API 活動相關的日誌。主要用於調查可疑的 API 活動。

Kubernetes Logging 架構

如果我們將 Kubernetes 集羣作爲一個整體,那麼我們將需要統一收集日誌。但是 Kubernetes 並不提供任何日誌收集功能,因此您需要設置一個集中的日誌後端(例如: Elasticsearch) ,並將所有日誌發送到日誌後端。下面的圖像描繪了一個 high-level 的 Kubernetes Logging 架構。

img

讓我們瞭解一下日誌記錄的三個關鍵組件。

  1. Logging Agent: 一個日誌代理,可以在所有的 Kubernetes 節點中作爲 daemonset 運行,它將日誌不斷地集中到日誌後端。日誌代理也可以作爲 sidecar 容器運行。例如 Fluentd。
  2. Logging Backend: 一個集中的系統,能夠存儲、搜索和分析日誌數據。
  3. Log Visualization: 以儀表板的形式可視化日誌數據的工具。

Kubernetes Logging 模式

本節將研究一些 Kubernetes 日誌記錄模式,以便將日誌流傳到日誌後端。有三種關鍵的 Kubernetes 集羣日誌記錄模式

  1. Node level logging agent
  2. Streaming sidecar container
  3. Sidecar logging agent

讓我們詳細研究一下每個方案的特點。

Node Level Logging Agent

img

在這種方法中,每個節點運行着一個代理(例如: Fluentd)讀取使用容器 STDOUT 和 STDERR 流創建的日誌文件,然後將其發送給像 Elasticsearch 這樣的日誌後端。這是一種常用的日誌記錄模式,不需要任何開銷就可以很好地工作

而云原生中的 12因素應用程序方法 也建議將日誌流傳到 STDOUT。

參考地址:https://12factor.net/logs

Streaming sidecar container

img

當應用程序不能直接向 STDOUT 和 STDERR 流寫入日誌時,這種 Sidecar 方法非常有用。

Pod 中的應用程序容器將所有日誌寫入容器中的一個文件,然後 Pod 中存在一個 sidecar 容器從該日誌文件中讀取數據並將其傳輸到 STDOUT 和 STDERR,最後利用 Node Level Logging Agent 的方式收集。

應用程序的日誌自定義文件 -> 重新將流輸出到 STDOUT -> 容器引擎收集

Sidecar Logging Agent

img

在這種方法中,日誌不會被流送到 STDOUT 和 STDERR。相反,一個帶有日誌代理的 sidecar 容器將與應用程序容器一起運行。然後,日誌代理將直接將日誌流傳到日誌後端。

也就是說,Pod 中的 sidecar 容器,把日誌1直接推送到日誌存儲後端,不需要容器引擎的收集。

這種方法有兩個缺點。

  1. 將日誌記錄代理作爲 sidecar 運行是資源密集型的,即會消耗大量 IO。
  2. 您不能使用 kubectl logs 命令獲得日誌,因爲 Kubelet 不會處理日誌。

Kubernetes Logging 工具

Kubernetes 最常用的開源日誌堆棧是 EFK (Elasticsearch,Flunentd/Fluent-but,和 Kibana)。

EFK 方案包含以下三大部件:

  1. Elasticsearch – Log 聚合器
  2. Flunetd/Fluentbit – Logging 代理(Fluentbit 是爲集裝箱工作負載設計的輕量級代理)
  3. Kibana – Log 可視化和儀表板工具

當涉及到像 Google GKE、 AWS 和 Azure AKS 這樣的管理 Kubernetes 服務時,它集成了特定於雲的集中式日誌記錄。因此,當您部署託管 kubernetes 集羣時,您將獲得在相應的日誌記錄服務中啓用日誌監視的選項。比如說:

  1. AWS EKS uses Cloud
  2. Google GKE uses Stackdriver monitoring
  3. Azure AKS uses Azure Monitor

需要在雲上操作。

此外,組織可能會使用企業日誌解決方案,比如 Splunk。在這種情況下,日誌被轉發給 Splunk 監控,並遵守組織的日誌保留規範。以下是一些企業日誌解決方案。

  1. Logz.io
  2. Splunk
  3. Elastic
  4. Sumologic
  5. LogDNA

Kubenretes Logging 與 EFK

在 Kubernetes 中,目前其中一個最好的開源日誌方案是 EFK ,它包含 Elasticsearch、 Fluentd 和 Kibana 三個部分。

在第二部分中,我們將在 Kubernetes 集羣中,部署 EFK 日誌方案。

第二部分:EFK 實踐

第一部分,其中爲初學者介紹了 Kubernetes 日誌基本原理和模式。在第二部分中,您將學習如何在 Kubernetes 集羣上設置用於日誌流、日誌分析和日誌監視的 EFK。

在 Kubernetes 集羣上運行多個應用程序和服務時,將所有應用程序和 Kubernetes 集羣日誌流到一個集中的日誌基礎設施中,以便於日誌分析,這樣做更有意義。第二部分旨在通過 EFK 堆棧向您介紹 Kubernetes 日誌的重要技術方面。

EFK Stack

EFK 代表 Elasticsearch、 Fluentd 和 Kibana。EFK 是用於 Kubernetes 日誌聚合和分析的流行且最佳的開源選擇。

  1. Elasticsearch 是一個分佈式和可擴展的搜索引擎,通常用於篩選大量的日誌數據。它是一個基於 Lucene 搜索引擎(來自 Apache 的搜索庫)的 NoSQL 數據庫。它的主要工作是儲存日誌和從 Fluentd 中取回日誌。
  2. Fluentd 是日誌收集處理器,它是一個開源日誌收集代理,支持多個數據源和輸出格式。此外,它還可以將日誌轉發給 Stackdriver、 Cloudwatch、 Elasticsearch、 Splunk、 Bigquery 等。簡而言之,它是日誌數據生成系統和日誌數據存儲系統之間的統一層。
  3. Kibana 是一個用於查詢、數據可視化和儀表板的 UI 工具。它是一個查詢引擎,允許您通過 web 界面探索您的日誌數據,爲事件日誌構建可視化,特定於查詢過濾信息以檢測問題。您可以使用 Kibana 虛擬地構建任何類型的儀表板。Kibana Query Language (KQL)用於查詢 elasticsearch 數據。在這裏,我們使用 Kibana 在 elasticsearch 中查詢索引數據。

此外,Elasticsearch 還可以幫助解決大量非結構化數據分離的問題,目前許多組織都在使用 Elasticsearch,通常跟 Kibana 部署在一起。

注意: 當涉及到 Kubernetes 時,FLuentd 是最好的選擇,因爲比 logstash 更好,因爲 FLuentd 可以解析容器日誌而不需要任何額外的配置。此外,這是一個 CNCF 項目。

在 Kubernetes 上設置 EFK

接下來我們將一步步在 Kubernetes 中部署和配置 EFK,你可以在 Kubernetes EFK Github repo 中找到本博客中使用的所有部署定義文件,每個 EFK 組件的 YAML 定義文件都放在不同的目錄中。

首先克隆倉庫:

git clone https://github.com/scriptcamp/kubernetes-efk

注意,在本文部署的 EFK 組件,都會在 Kubernetes 默認的 default 命名空間中。

倉庫的文件結構如下:

├── kubernetes-efk
│   ├── README.md
│   ├── elasticsearch
│   │   ├── es-sts.yaml
│   │   └── es-svc.yaml
│   ├── fluentd
│   │   ├── fluentd-ds.yaml
│   │   ├── fluentd-rb.yaml
│   │   ├── fluentd-role.yaml
│   │   └── fluentd-sa.yaml
│   ├── kibana
│   │   ├── kibana-deployment.yaml
│   │   └── kibana-svc.yaml
│   └── test-pod.yaml

EFK 架構

下圖顯示了我們將要構建的 EFK 的高級架構。

img

EKF 組件部署說明如下:

  1. Fluentd: 在需要從所有節點收集容器日誌時作爲守護進程部署。它連接到 Elasticsearch 服務端點以轉發日誌。
  2. Elasticsearch:在保存日誌數據時作爲狀態集部署。我們還公開 Fluentd 和 kibana 的服務端點以連接到它。
  3. Kibana:- 作爲部署部署並連接到 Elasticsearch 服務端點。

部署 Elasticsearch Statefulset

Elasticsearch 是作爲 Statefulset 部署的,多個副本通過一個 headless service 彼此連接。Headless svc 在 Pod 的 DNS 域中提供幫助。

打開 elasticsearch/es-svc. yaml 文件,可以看到定義如下:

apiVersion: v1
kind: Service
metadata:
  name: elasticsearch
  labels:
    app: elasticsearch
spec:
  selector:
    app: elasticsearch
  clusterIP: None
  ports:
    - port: 9200
      name: rest
    - port: 9300
      name: inter-node

讓我們現在就創造它。

kubectl create -f es-svc.yaml

在我們開始爲彈性搜索創建 statefulset 之前,讓我們回想一下,statefulset 需要事先定義的存儲類,它可以在需要時創建卷。

注意: 雖然在生產環境中,可能需要 400-500gb SSD 支撐 ES 的存儲,由於這裏是存儲環境,因此定義 YAML 文件中是 3GB 的 PV。

筆者因爲要學習 EFK,特意掛載了一個 512GB 的企業級 SSD。

elasticsearch/es-sts.yaml 文件中,它會自動創建一個具有 3GB 的存儲卷,其定義如下:

    spec:
      accessModes: [ "ReadWriteOnce" ]
      # storageClassName: ""
      resources:
        requests:
          storage: 3Gi

由於筆者有自己的盤,筆者掛載到了 slave2 節點中,所以這裏筆者就不用這個配置了,筆者使用 NFS - PV 的方式,當然讀者爲了避免麻煩,可以繼續使用上面的配置。

讀者可以首先按照 https://k8s.whuanle.cn/5.volumes/3.nfts.html 部署自己的 NFS 存儲,然後利用下面這個模板創建 PV。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: es-pv 
spec:
  capacity:
    storage: 450Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: es-volume 
  mountOptions:
    - hard
    - nfsvers=4.1
  nfs:
    path: /data/volumns/es
    server: 10.0.0.4

需讀者自行提前創建 NFS,讀者可參考 https://k8s.whuanle.cn/5.volumes/3.nfts.html 創建一個自己的跨節點的存儲系統。

將 volumeClaimTemplates 部分改成:

  volumeClaimTemplates:
  - metadata:
      name: data
      labels:
        app: elasticsearch
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "es-volume"
      resources:
        requests:
          storage: 450Gi

然後我們看一下 es-sts.yaml 的文件中,對於 Eelasticsearch 集羣的定義:

          - name: discovery.seed_hosts
            value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch"

這裏有兩個地方要注意,一是你的集羣必須要安裝 CoreDNS,二是你的從節點數量跟 es-sts.yaml 中定義的 replicas: 3 數量一致,如果你有三個節點(一主二從),那麼 replics 要設置爲 2,但是一般 Eelasticsearch 實例數量都是單數。因此筆者只設置使用一個 Eelasticsearch 實例。

然後部署 Elasticsearch :

 kubectl create -f es-sts.yaml 

驗證 Elasticsearch 部署

在 Elasticsearch Pod 進入運行狀態之後,讓我們嘗試驗證 Elasticsearch 狀態集。最簡單的方法是檢查集羣的狀態。爲了檢查狀態,端口前進 Elasticsearch Pod 的 9200 端口。

kubectl port-forward es-cluster-0 19200:9200

port-forward 方式具有臨時性,避免 Elasticsearch 暴露到外網;或者使用 Service IP 等方式測試 IP 連通性,你還可以使用 Service NodePort 的方式暴露 Elasticsearch 。

要檢查 Elasticsearch 集羣的健康狀況,請在終端中運行以下命令。

curl http://localhost:19200/_cluster/health/?pretty

輸出將顯示 Elasticsearch 集羣的狀態。如果所有的步驟都被正確的執行,訪問此地址,會獲得 Json 響應。

image-20220213152739445

部署 Kibana

跟部署 Elasticsearch 一樣,可以使用一個簡單的 yaml 文件部署 Kibana。如果您檢查以下 Kibana 部署清單文件,我們有一個 ELASTICSEARCH_URL 定義來配置 Elasticsearch 集羣 Endpoint,Kibana 使用 Endpoint URL 連接 Elasticsearch。

下面是 kibana-deployment.yaml 文件的定義。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kibana
  labels:
    app: kibana
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kibana
  template:
    metadata:
      labels:
        app: kibana
    spec:
      containers:
      - name: kibana
        image: docker.elastic.co/kibana/kibana:7.5.0
        resources:
          limits:
            cpu: 1000m
          requests:
            cpu: 100m
        env:
          - name: ELASTICSEARCH_URL
            value: http://elasticsearch:9200
        ports:
        - containerPort: 5601
"state":"green","message":"Status changed from yellow to green - Ready","prevState":"yellow","prevMsg":"Waiting for Elasticsearch"

現在直接部署 Kibana 即可:

kubectl create -f kibana-deployment.yaml

讓我們創建一個 NodePort 類型的 Service,通過節點 IP 地址訪問 Kibana UI。我們使用 nodePort 進行演示。然而,理想情況下,kubernetes 與 ClusterIP 服務的接入用於實際的項目實現。

kibana-svc.yaml 文件的定義如下:

apiVersion: v1
kind: Service
metadata:
  name: kibana-np
spec:
  selector: 
    app: kibana
  type: NodePort  
  ports:
    - port: 8080
      targetPort: 5601 
      nodePort: 30000

創建 Kibana Service:

kubectl create -f kibana-svc.yaml

現在你可以通過 http://<node-ip>:3000 訪問 Kibana UI。

Pod 進入運行狀態後,讓我們嘗試驗證 Kibana 部署。最簡單的方法是通過集羣的 UI 訪問。

要檢查狀態,端口轉發 Kibana Pod 的 5601端口。如果您已經創建了 nodePort 服務,您也可以使用它(注意防火牆可能會攔截)。

kubectl port-forward <kibana-pod-name> 5601:5601

之後,通過 web 瀏覽器訪問 UI 或使用 curl 發出請求

curl http://localhost:5601/app/kibana

如果 Kibana UI 加載或出現有效的 curl 響應,那麼我們可以斷定 Kibana 正在正確運行。

image-20220213160045560

部署 Fluentd

Fluentd 被部署爲守護進程,因爲它必須從集羣中的所有節點流日誌。除此之外,它還需要特殊的權限來列出和提取所有名稱空間中的 Pod 元數據。

Kubernetes 服務帳戶用於爲 Kubernetes 中的組件提供權限,以及集羣角色和集羣綁定。讓我們繼續前進,創建所需的服務帳戶和角色。

創建 Fluentd 集羣角色

Kubernetes 中的集羣角色包含表示一組權限的規則,對於 Fluentd,我們希望爲 Pod 和名稱空間授予權限。
fluentd-role.yaml 文件的定義如下:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: fluentd
  labels:
    app: fluentd
rules:
- apiGroups:
  - ""
  resources:
  - pods
  - namespaces
  verbs:
  - get
  - list
  - watch

創建角色:

kubectl create -f fluentd-role.yaml

創建 Fluentd Service Account

在 Kubernetes 中,Service Account 是爲 Pod 提供身份的實體,在這裏,我們希望創建一個 Service Account,用於 Fluentd Pods。

fluentd-sa.yaml 文件的定義如下:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: fluentd
  labels:
    app: fluentd

創建 Service Account:

kubectl create -f fluentd-sa.yaml

集羣角色綁定

Kubernetes 中的集羣角色綁定將集羣角色中定義的權限授予服務帳戶。我們希望在上面創建的角色和服務帳戶之間創建一個角色綁定。
fluentd-rb.yaml 文件的定義如下:

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: fluentd
roleRef:
  kind: ClusterRole
  name: fluentd
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: fluentd
  namespace: default

創建角色綁定:

kubectl create -f fluentd-rb.yaml

部署 Fluentd DaemonSet

現在讓我們部署 Fluentd :

kubectl create -f fluentd-ds.yaml

爲了驗證 fluentd 的安裝,讓我們啓動一個連續創建日誌的 pod。然後我們將嘗試在 Kibana 境內看到這些日誌。

kubectl create -f test-pod.yaml

現在,讓我們前往 Kibana,看看這個吊艙裏的日誌是否被 fluentd 拾取並存儲在 elasticsearch。遵循以下步驟:

1,點擊 explore on my own 進入後臺。

image-20220213160840954

2,選擇 Kibana 部分下的“ Index Patterns”選項。

image-20220213160921037

3,使用 logstash-* 模式創建一個新的 Index Patten,然後點擊 Next step

image-20220213161248126

4,在選項找到 @timestamp ,然後點擊 Create index pattern

image-20220213161402788

現在已經創建了索引模式,我們可以前往控制檯,在控制檯中,您將能夠看到所有由 Fluentd 導出的日誌,如下圖所示,這些日誌來自我們的 test-pod

image-20220213161617937

接下來,讀者可以根據官方文檔或其他資料,繼續深入學習探究圖表的製作和日誌分析,以便在生產中應用 EFK 三件套。

如果想深入 Kibana 面板,筆者推薦你閱讀這篇博客:https://devopscube.com/kibana-dashboard-tutorial/

一個逗逗的大學生
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章