1. 程式人生 > 實用技巧 >從 Docker 到 Kubernetes 日誌管理機制詳解

從 Docker 到 Kubernetes 日誌管理機制詳解

轉載於:https://blog.csdn.net/qianghaohao/article/details/100072538

在容器化時代,容器應用的日誌管理和傳統應用存在很大的區別,為了順應容器化應用,Docker 和 Kubernetes 提供了一套完美的日誌解決方案。本文從 Docker 到 Kubernetes 逐步介紹在容器化時代日誌的管理機制,以及在 Kubernetes 平臺下有哪些最佳的日誌收集方案。涉及到的話題有 Docker 日誌管理機制、Kubernetes 日誌管理機制、Kubernetes 叢集日誌收集方案。本文結構如下:

  • Docker 日誌管理機制

    • Docker 的日誌種類
    • 基於日誌驅動(loging driver)的日誌管理機制
    • Docker 日誌驅動(loging driver)配置
    • Docker 預設的日誌驅動json-file
  • Kubernetes 日誌管理機制

    • 應用 Pod 日誌
    • Kuberntes 叢集元件日誌
  • Kubernetes 叢集日誌收集方案

    • 節點級日誌代理方案
    • sidecar 容器方案
    • 應用程式直接將日誌傳輸到日誌平臺

一、Docker 日誌管理機制

1、Docker 的日誌種類

在 Docker 中日誌分為兩大類:

  • Docker 引擎日誌;
  • 容器日誌;
Docker 引擎日誌

Docker 引擎日誌就是 docker 服務的日誌,即dockerd

守護程序的日誌,在支援 Systemd 的系統中可以通過journal -u docker檢視日誌。

容器日誌

容器日誌指的是每個容器打到 stdout 和 stderr 的日誌,而不是容器內部的日誌檔案。docker 管理所有容器打到 stdout 和 stderr 的日誌,其他來源的日誌不歸 docker 管理。我們通過docker logs命令檢視容器日誌都是讀取容器打到 stdout 和 stderr 的日誌。

基於日誌驅動(loging driver)的日誌管理機制

Docker 提供了一套通用、靈活的日誌管理機制,Docker 將所有容器打到 stdout 和 stderr 的日誌都統一通過日誌驅動重定向到某個地方。

Docker 支援的日誌驅動有很多,比如 local、json-file、syslog、journald 等等,類似外掛一樣,不同的日誌驅動可以將日誌重定向到不同的地方,這體現了 Docker 日誌管理的靈活性,以熱插拔的方式實現日誌不同目的地的輸出。

Dokcer 預設的日誌日誌驅動是json-file,該驅動將將來自容器的 stdout 和 stderr 日誌都統一以json的形式儲存到本地磁碟。日誌儲存路徑格式為:/var/lib/docker/containers/<容器 id>/<容器 id>-json.log。所以可以看出在json-file日誌驅動下,Docker 將所有容器日誌都統一重定向到了/var/lib/docker/containers/目錄下,這為日誌收集提供了很大的便利。

注意:只有日誌驅動為:local、json-file 或者 journald 時,docker logs命令才能檢視到容器打到 stdout/stderr 的日誌。


下面為官方支援的日誌驅動列表:

驅動描述
none 執行的容器沒有日誌,docker logs也不返回任何輸出。
local 日誌以自定義格式儲存,旨在實現最小開銷。
json-file 日誌格式為JSON。Docker的預設日誌記錄驅動程式。
syslog 將日誌訊息寫入syslog。該 syslog 守護程式必須在主機上執行。
journald 將日誌訊息寫入journald。該journald守護程式必須在主機上執行。
gelf 將日誌訊息寫入Graylog擴充套件日誌格式(GELF)端點,例如Graylog或Logstash。
fluentd 將日誌訊息寫入fluentd(轉發輸入)。該fluentd守護程式必須在主機上執行。
awslogs 將日誌訊息寫入Amazon CloudWatch Logs。
splunk 使 用HTTP 事件收集器將日誌訊息寫入 splunk。
etwlogs 將日誌訊息寫為 Windows 事件跟蹤(ETW)事件。僅適用於Windows平臺。
gcplogs 將日誌訊息寫入 Google Cloud Platform(GCP)Logging。
logentries 將日誌訊息寫入 Rapid7 Logentries。

Docker 日誌驅動(loging driver)配置

上面我們已經知道 Docker 支援多種日誌驅動型別,我們可以修改預設的日誌驅動配置。日誌驅動可以全域性配置,也可以給特定容器配置。

  • 檢視 Docker 當前的日誌驅動配置
docker  info |grep  "Logging Driver"
  • 檢視單個容器的設定的日誌驅動
docker inspect  -f '{{.HostConfig.LogConfig.Type}}'   容器id
  • Docker 日誌驅動全域性配置
    全域性配置意味所有容器都生效,編輯 /etc/docker/daemon.json 檔案(如果檔案不存在新建一個),新增日誌驅動配置。
    示例:配置 Docker 引擎日誌驅動為syslog
{
  "log-driver": "syslog"
}
  • 給特定容器配置日誌驅動
    在啟動容器時指定日誌驅動--log-driver引數。
    示例:啟動 nginx 容器,日誌驅動指定為 journald
docker  run --name nginx -d --log-driver journald nginx

Docker 預設的日誌驅動json-file

json-file 日誌驅動記錄所有容器的 STOUT/STDERR 的輸出 ,用 JSON 的格式寫到檔案中,每一條 json 日誌中預設包含log,stream,time三個欄位,示例日誌如下:
檔案路徑為:

/var/lib/docker/containers/40f1851f5eb9e684f0b0db216ea19542529e0a2a2e7d4d8e1d69f3591a573c39/40f1851f5eb9e684f0b0db216ea19542529e0a2a2e7d4d8e1d69f3591a573c39-json.log
{"log":"14:C 25 Jul 2019 12:27:04.072 * DB saved on disk\n","stream":"stdout","time":"2019-07-25T12:27:04.072712524Z"}

那麼打到磁碟的 json 檔案該如何配置輪轉,防止撐滿磁碟呢?每種 Docker 日誌驅動都有相應的配置項日誌輪轉,比如根據單個檔案大小和日誌檔案數量配置輪轉。json-file日誌驅動支援的配置選項如下:

選項描述示例值
max-size 切割之前日誌的最大大小。可取值單位為(k,m,g), 預設為-1(表示無限制)。 --log-opt max-size=10m
max-file 可以存在的最大日誌檔案數。如果切割日誌會建立超過閾值的檔案數,則會刪除最舊的檔案。僅在max-size設定時有效。正整數。預設為1。 --log-opt max-file=3
labels 適用於啟動Docker守護程式時。此守護程式接受的以逗號分隔的與日誌記錄相關的標籤列表。 --log-opt labels=production_status,geo
env 適用於啟動Docker守護程式時。此守護程式接受的以逗號分隔的與日誌記錄相關的環境變數列表。 --log-opt env=os,customer
compress 切割的日誌是否進行壓縮。預設是disabled。 --log-opt compress=true

二、Kubernetes 日誌管理機制

在 Kubernetes 中日誌也主要有兩大類:

  • 應用 Pod 日誌;
  • Kuberntes 叢集元件日誌;

1、應用 Pod 日誌

Kubernetes Pod 的日誌管理是基於 Docker 引擎的,Kubernetes 並不管理日誌的輪轉策略,日誌的儲存都是基於 Docker 的日誌管理策略。k8s 叢集排程的基本單位就是 Pod,而 Pod 是一組容器,所以 k8s 日誌管理基於 Docker 引擎這一說法也就不難理解了,最終日誌還是要落到一個個容器上面。

假設 Docker 日誌驅動為json-file,那麼在 k8s 每個節點上,kubelet 會為每個容器的日誌建立一個軟連結,軟連線儲存路徑為:/var/log/containers/,軟連線會連結到/var/log/pods/目錄下相應 pod 目錄的容器日誌,被連結的日誌檔案也是軟連結,最終連結到 Docker 容器引擎的日誌儲存目錄:/var/lib/docker/container下相應容器的日誌。另外這些軟連結檔名稱含有 k8s 相關資訊,比如:Pod id,名字空間,容器 ID 等資訊,這就為日誌收集提供了很大的便利。

舉例:我們跟蹤一個容器日誌檔案,證明上述的說明,跟蹤一個 kong Pod 日誌,Pod 副本數為 1

/var/log/containers/kong-kong-d889cf995-2ntwz_kong_kong-432e47df36d0992a3a8d20ef6912112615ffeb30e6a95c484d15614302f8db03.log
------->
/var/log/pods/kong_kong-kong-d889cf995-2ntwz_a6377053-9ca3-48f9-9f73-49856908b94a/kong/0.log
------->
/var/lib/docker/containers/432e47df36d0992a3a8d20ef6912112615ffeb30e6a95c484d15614302f8db03/432e47df36d0992a3a8d20ef6912112615ffeb30e6a95c484d15614302f8db03-json.log

Kuberntes 叢集元件日誌

Kuberntes 叢集元件日誌分為兩類:

  • 執行在容器中的 Kubernetes scheduler 和 kube-proxy。
  • 未執行在容器中的 kubelet 和容器 runtime,比如 Docker。

在使用 systemd 機制的伺服器上,kubelet 和容器 runtime 寫入日誌到 journald。如果沒有 systemd,他們寫入日誌到 /var/log 目錄的 .log 檔案。容器中的系統元件通常將日誌寫到 /var/log 目錄,在 kubeadm 安裝的叢集中它們以靜態 Pod 的形式執行在叢集中,因此日誌一般在/var/log/pods目錄下。

2、Kubernetes 叢集日誌收集方案

Kubernetes 本身並未提供叢集日誌收集方案,k8s 官方文件給了三種日誌收集的建議方案:

  • 使用執行在每個節點上的節點級的日誌代理
  • 在應用程式的 pod 中包含專門記錄日誌 sidecar 容器
  • 應用程式直接將日誌傳輸到日誌平臺

節點級日誌代理方案

從前面的介紹我們已經瞭解到,k8s 每個節點都將容器日誌統一儲存到了/var/log/containers/目錄下,因此可以在每個節點安裝一個日誌代理,將該目錄下的日誌實時傳輸到日誌儲存平臺。

由於需要每個節點執行一個日誌代理,因此日誌代理推薦以 DaemonSet 的方式執行在每個節點。官方推薦的日誌代理是 fluentd,當然也可以使用其他日誌代理,比如 filebeat,logstash 等。

sidecar 容器方案

有兩種使用 sidecar 容器的方式:

  • sidecar 容器重定向日誌流
  • sidecar 容器作為日誌代理
sidecar 容器重定向日誌流

這種方式基於節點級日誌代理方案,sidecar 容器和應用容器在同一個 Pod 執行,這個容器的作用就是讀取應用容器的日誌檔案,然後將讀取的日誌內容重定向到 stdout 和 stderr,然後通過節點級日誌代理統一收集。這種方式不推薦使用,缺點就是日誌重複儲存了,導致磁碟使用會成倍增加。比如應用容器的日誌本身打到檔案儲存了一份,sidecar 容器重定向又儲存了一份(儲存到了 /var/lib/docker/containers/ 目錄下)。這種方式的應用場景是應用本身不支援將日誌打到 stdout 和 stderr,所以才需要 sidecar 容器重定向下。

sidecar 容器作為日誌代理

這種方式不需要節點級日誌代理,和應用容器在一起的 sidecar 容器直接作為日誌代理方式執行在 Pod 中,sidecar 容器讀取應用容器的日誌,然後直接實時傳輸到日誌儲存平臺。很顯然這種方式也存在一個缺點,就是每個應用 Pod 都需要有個 sidecar 容器作為日誌代理,而日誌代理對系統 CPU、和記憶體都有一定的消耗,在節點 Pod 數很多的時候這個資源消耗其實是不小的。另外還有個問題就是在這種方式下由於應用容器日誌不直接打到 stdout 和 stderr,所以是無法使用kubectl logs命令檢視 Pod 中容器日誌。

應用程式直接將日誌傳輸到日誌平臺

這種方式就是應用程式本身直接將日誌打到統一的日誌收集平臺,比如 Java 應用可以配置日誌的 appender,打到不同的地方,很顯然這種方式對應用程式有一定的侵入性,而且還要保證日誌系統的健壯性,從這個角度看應用和日誌系統還有一定的耦合性,所以個人不是很推薦這種方式。

總結:綜合對比上述三種日誌收集方案優缺點,更推薦使用節點級日誌代理方案,這種方式對應用沒有侵入性,而且對系統資源沒有額外的消耗,也不影響 kubelet 工具檢視 Pod 容器日誌。

相關文件

https://juejin.im/entry/5c03f8bb5188251ba905741d| Docker 日誌驅動配置
https://www.cnblogs.com/operationhome/p/10907591.html| Docker容器日誌管理最佳實踐
https://www.cnblogs.com/cocowool/p/Docker_Kubernetes_Log_Location.html| 談一下Docker與Kubernetes叢集的日誌和日誌管理
https://kubernetes.io/docs/concepts/cluster-administration/logging/| Kubernetes 日誌架