開發人員在面對 kubernetes 分布式叢集下的日誌需求時,常常會感到頭疼,既有容器自身特性的原因,也有現有日誌採集工具的桎梏,主要包括:
- 容器本身特性:
- 採集目標多:容器本身的特性導致採集目標多,需要採集容器內日誌、容器 stdout。對於容器內部的檔案日誌採集,現在並沒有一個很好的工具能夠去動態發現採集。針對每種資料來源都有對應的採集軟體,但缺乏一站式的工具。
- Auto Scaling難:kubernetes 是分布式的叢集,服務、環境的Auto Scaling對於日誌採集帶來了很大的困難,無法像傳統虛擬機器環境下那樣,事先配置好日誌的採集路徑等資訊,採集的動態性以及資料完整性是非常大的挑戰。
- 現有日誌工具的一些缺陷:
- 缺乏動態配置的能力。目前的採集工具都需要事先手動設定好日誌採集方式和路徑等資訊,因為它無法能夠自動感知到容器的生命週期變化或者動態漂移,所以它無法動態地去配置。
- 日誌採集重複或丟失的問題。因為現在的一些採集工具基本上是通過 tail 的方式來進行日誌採集的,那麼這裡就可能存在兩個方面的問題:一個是可能導致日誌丟失,比如採集工具在重啟的過程中,而應用依然在寫日誌,那麼就有可能導致這個視窗期的日誌丟失;而對於這種情況一般保守的做法就是,預設往前多採集 1M 日誌或 2M 的日誌,那麼這就又會可能引起日誌採集重複的問題。
- 未明確標記日誌源。因為一個應用可能有很多個容器,輸出的應用日誌也是一樣的,那麼當我們將所有應用日誌收集到統一日誌儲存後端時,在搜尋日誌的時候,我們就無法明確這條日誌具體是哪一個節點上的哪一個應用程式容器產生的。
本文檔將介紹一種 Docker 日誌收集工具 log-pilot,結合 Elasticsearch 和 kibana 等工具,形成一套適用於 kubernetes 環境下的一站式日誌解決方案。
log-pilot 介紹
log-Pilot 是一個智能容器日誌採集工具,它不僅能夠高效便捷地將容器日誌採集輸出到多種儲存日誌後端,同時還能夠動態地發現和採集容器內部的記錄檔。
針對前面提出的日誌採集難題,log-pilot 通過聲明式配置實現強大的容器事件管理,可同時擷取容器標準輸出和內部檔案日誌,解決了動態伸縮問題,此外,log-pilot 具有自動探索機制,CheckPoint 及控制代碼保持的機制,自動日誌資料打標,有效應對動態配置、日誌重複和丟失以及日誌源標記等問題。
目前 log-pilot 在 Github 完全開源,項目地址是 https://github.com/AliyunContainerService/log-pilot 。您可以深入瞭解更多實現原理。
針對容器日誌的聲明式配置
Log-Pilot 支援容器事件管理,它能夠動態地監聽容器的事件變化,然後依據容器的標籤來進行解析,組建記錄檔採集設定檔,然後交由採集外掛程式來進行日誌採集。
在 kubernetes 下,Log-Pilot 可以依據環境變數 aliyun_logs_$name = $path
動態地組建記錄檔採集設定檔,其中包含兩個變數:
- $name 是我們自訂的一個字串,它在不同的情境下指代不同的含義,在本情境中,將日誌採集到 Elasticsearch 的時候,這個 $name 表示的是 Index。
- 另一個是 $path,支援兩種輸入形式,stdout 和容器內部記錄檔的路徑,對應日誌標準輸出和容器內的記錄檔。
- 第一種約定關鍵字 stdout 表示的是採集容器的標準輸出日誌,如本例中我們要採集 tomcat 容器日誌,那麼我們通過配置標籤
aliyun.logs.catalina=stdout
來採集 tomcat 標準輸出日誌。 - 第二種是容器內部記錄檔的路徑,也支援萬用字元的方式,通過配置環境變數
aliyun_logs_access=/usr/local/tomcat/logs/*.log
來採集 tomcat 容器內部的日誌。當然如果你不想使用 aliyun 這個關鍵字,Log-Pilot 也提供了環境變數 PILOT_LOG_PREFIX 可以指定自己的聲明式日誌配置首碼,比如PILOT_LOG_PREFIX: "aliyun,custom"
。
- 第一種約定關鍵字 stdout 表示的是採集容器的標準輸出日誌,如本例中我們要採集 tomcat 容器日誌,那麼我們通過配置標籤
此外,Log-Pilot 還支援多種日誌解析格式,通過 aliyun_logs_$name_format=<format>
標籤就可以告訴 Log-Pilot 在採集日誌的時候,同時以什麼樣的格式來解析日誌記錄,支援的格式包括:none、json、csv、nginx、apache2 和 regxp。
Log-Pilot 同時支援自訂 tag,我們可以在環境變數裡配置 aliyun_logs_$name_tags="K1=V1,K2=V2"
,那麼在採集日誌的時候也會將 K1=V1 和 K2=V2 採集到容器的日誌輸出中。自訂 tag 可協助您給日誌產生的環境打上 tag,方便進行日誌統計、日誌路由和日誌過濾。
日誌採集模式
本文檔採用 node 方式進行部署,通過在每台機器上部署一個 log-pilot 執行個體,收集機器上所有 Docker 應用日誌。
前提條件
您已經開通Container Service,並建立了一個 kubernetes 叢集。本樣本中,建立的 Kubernetes 叢集位於華東 1 地區。
步驟1 部署 elasticsearch
- 串連到您的 Kubernetes 叢集。具體操作參見通過SSH訪問Kubernetes叢集 或 通過 kubectl 串連 Kubernetes 叢集。
- 首先部署 elasticsearch 相關服務,該編排模板包含一個 elasticsearch-api 的服務、elasticsearch-discovery 的服務和 elasticsearch 的狀態集,這些對象都會部署在 kube-system 命名空間下。
kubectl apply -f https://acs-logging.oss-cn-hangzhou.aliyuncs.com/elasticsearch.yml
- 部署成功後,kube-system 命名空間下會出現相關對象,執行以下命令查看運行情況。
$ kubectl get svc,StatefulSet -n=kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc/elasticsearch-api ClusterIP 172.21.5.134 <none> 9200/TCP 22h svc/elasticsearch-discovery ClusterIP 172.21.13.91 <none> 9300/TCP 22h ... NAME DESIRED CURRENT AGE statefulsets/elasticsearch 3 3 22h
步驟2 部署 log-pilot 和 kibana 服務
- 部署 log-pilot 日誌採集工具,如下所示:
kubectl apply -f https://acs-logging.oss-cn-hangzhou.aliyuncs.com/log-pilot.yml
- 部署 kibana 服務,該編排樣本包含一個 service 和一個 deployment。
kubectl apply -f https://acs-logging.oss-cn-hangzhou.aliyuncs.com/kibana.yml
步驟3 部署測試應用 tomcat
在 elasticsearch + log-pilot + Kibana 這套日誌工具部署完畢後,現在開始部署一個日誌測試應用 tomcat,來測試日誌是否能正常採集、索引和顯示。
編排模板如下。
apiVersion: v1
kind: Pod
metadata:
name: tomcat
namespace: default
labels:
name: tomcat
spec:
containers:
- image: tomcat
name: tomcat-test
volumeMounts:
- mountPath: /usr/local/tomcat/logs
name: accesslogs
env:
- name: aliyun_logs_catalina
value: "stdout" ##採集標準輸出日誌
- name: aliyun_logs_access
value: "/usr/local/tomcat/logs/catalina.*.log" ## 採集容器內記錄檔
volumes:
- name: accesslogs
emptyDir: {}
tomcat 鏡像屬於少數同時使用了 stdout 和檔案日誌的 Docker 鏡像,適合本文檔的示範。在上面的編排中,通過在 pod 中定義環境變數的方式,動態地組建記錄檔採集設定檔,環境變數的具體說明如下:
aliyun_logs_catalina=stdout
表示要收集容器的 stdout 日誌。aliyun_logs_access=/usr/local/tomcat/logs/catalina.*.log
表示要收集容器內 /usr/local/tomcat/logs/ 目錄下所有名字匹配 catalina.*.log 的檔案日誌。
在本方案的 elasticsearch 情境下,環境變數中的 $name
表示 Index,本例中 $name
即是 catalina 和 access 。
步驟 4 將 kibana 服務暴露到公網
上面部署的 kibana 服務的類型採用 NodePort,預設情況下,不能從公網進行訪問,因此本文檔配置一個 ingress 實現公網訪問 kibana,來測試日誌資料是否正常索引和顯示。
- 通過配置 ingress 來實現公網下訪問 kibana 。本樣本選擇簡單的路由服務來實現,您可參考Ingress 支援 擷取更多方法。該 ingress 的編排模板如下所示。
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: kibana-ingress namespace: kube-system #要與 kibana 服務處於同一個 namespace spec: rules: - http: paths: - path: / backend: serviceName: kibana #輸入 kibana 服務的名稱 servicePort: 80 #輸入 kibana 服務暴露的連接埠
- 建立成功後,執行以下命令,擷取該 ingress 的訪問地址。
$ kubectl get ingress -n=kube-system NAME HOSTS ADDRESS PORTS AGE shared-dns * 120.55.150.30 80 5m
- 在瀏覽器中訪問該地址,如下所示。
- 單擊左側導覽列中的management ,然後單擊 。具體的索引名稱會在
$name
變數尾碼一個時間字串,您可以配合萬用字元*
進行建立。本例中使用$name*
來建立 Index Pattern。您也可以執行以下命令,進入 elasticsearch 對應的 pod,在 index 下列出 elasticsearch 的所有索引。
$ kubectl get pods -n=kube-system #找到 elasticsearch 對應的 pod ... $ kubectl exec -it elasticsearch-1 bash #進入 elasticsearch 的一個 pod ... $ curl 'localhost:9200/_cat/indices?v' ## 列出所有索引 health status index uuid pri rep docs.count docs.deleted store.size pri.store.size green open .kibana x06jj19PS4Cim6Ajo51PWg 1 1 4 0 53.6kb 26.8kb green open access-2018.03.19 txd3tG-NR6-guqmMEKKzEw 5 1 143 0 823.5kb 411.7kb green open catalina-2018.03.19 ZgtWd16FQ7qqJNNWXxFPcQ 5 1 143 0 915.5kb 457.5kb
- 索引建立完畢後,單擊左側導覽列中的Discover,然後選擇前面建立的 Index,選擇合適的時間段,在搜尋欄輸入相關欄位,就可以查詢相關的日誌。
至此,在阿里雲 Kubernetes 叢集上,我們已經成功測試基於 log-pilot、elasticsearch 和 kibana 的日誌解決方案,通過這個方案,我們能有效應對分布式 kubernetes 叢集日誌需求,可以協助提升營運和運營效率,保障系統持續穩定運行。