EFK完成k8s應用日誌收集
- [ ] 在進行日誌收集的過程中,我們首先想到的是使用Logstash,因為它是ELK stack中的重要成員,但是在測試過程中發現,Logstash是基於JDK的,在沒有產生日誌的情況單純啟動Logstash就大概要消耗500M記憶體,在每個Pod中都啟動一個日誌收集元件的情況下,使用logstash有點浪費系統資源,經人推薦我們選擇使用Filebeat替代,經測試單獨啟動Filebeat容器大約會消耗12M記憶體,比起logstash相當輕量級。
方案選擇
Kubernetes官方提供了EFK的日誌收集解決方案,但是這種方案並不適合所有的業務場景,它本身就有一些侷限性,例如:
所有日誌都必須是out前臺輸出,真實業務場景中無法保證所有日誌都在前臺輸出
只能有一個日誌輸出檔案,而真實業務場景中往往有多個日誌輸出檔案
Fluentd並不是常用的日誌收集工具,我們更習慣用logstash,現使用filebeat替代
我們已經有自己的ELK叢集且有專人維護,沒有必要再在kubernetes上做一個日誌收集服務
基於以上幾個原因,我們決定使用自己的ELK叢集。
Kubernetes叢集中的日誌收集解決方案
編號 | 方案 | 優點 | 缺點 |
---|---|---|---|
1 | 每個app的映象中都整合日誌收集元件 | 部署方便,kubernetes的yaml檔案無須特別配置,可以為每個app自定義日誌收集配置 | 強耦合,不方便應用和日誌收集元件升級和維護且會導致映象過大 |
2 | 單獨建立一個日誌收集元件跟app的容器一起執行在同一個pod中 | 低耦合,擴充套件性強,方便維護和升級 | 需要對kubernetes的yaml檔案進行單獨配置,略顯繁瑣 |
3 | 將所有的Pod的日誌都掛載到宿主機上,每臺主機上單獨起一個日誌收集Pod | 完全解耦,效能最高,管理起來最方便 | 需要統一日誌收集規則,目錄和輸出方式 |
綜合以上優缺點,我們選擇使用方案二。
該方案在擴充套件性、個性化、部署和後期維護方面都能做到均衡,因此選擇該方案。
filebeat日誌收集架構圖
圖片 - filebeat日誌收集架構圖
映象地址:https://github.com/flyhxg/docker-test/tree/master/filebeat-5.4.0
測試
我們部署一個應用filebeat來收集日誌的功能測試。
建立應用yaml檔案filebeat-test.yaml。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: filebeat-test
namespace: default
spec:
replicas: 3
template:
metadata:
labels:
k8s-app: filebeat-test
spec:
containers:
- image: 192.168.20.210:5000/filebeat:5.4.0
name: filebeat
volumeMounts:
- name: app-logs
mountPath: /log
- name: filebeat-config
mountPath: /etc/filebeat/
- image: harbor-001.jimmysong.io/library/analytics-docker-test:Build_8
name : app
ports:
- containerPort: 80
volumeMounts:
- name: app-logs
mountPath: /usr/local/TalkingData/logs
volumes:
- name: app-logs
emptyDir: {}
- name: filebeat-config
configMap:
name: filebeat-config
---
apiVersion: v1
kind: Service
metadata:
name: filebeat-test
labels:
app: filebeat-test
spec:
ports:
- port: 80
protocol: TCP
name: http
selector:
run: filebeat-test
---
apiVersion: v1
kind: ConfigMap
metadata:
name: filebeat-config
data:
filebeat.yml: |
filebeat.prospectors:
- input_type: log
paths:
- "/log/*"
- "/log/usermange/common/*"
output.elasticsearch:
hosts: ["172.23.5.255:9200"]
username: "elastic"
password: "changeme"
index: "filebeat-docker-test"
說明
該檔案中包含了配置檔案filebeat的配置檔案的ConfigMap,因此不需要再定義環境變數。
當然你也可以不同ConfigMap,通過傳統的傳遞環境變數的方式來配置filebeat。
例如對filebeat的容器進行如下配置:
containers:
- image: 192.168.20.210:5000/filebeat:5.4.0
name: filebeat
volumeMounts:
- name: app-logs
mountPath: /log
env:
- name: PATHS
value: "/log/*"
- name: ES_SERVER
value: 172.23.5.255:9200
- name: INDEX
value: logstash-docker
- name: INPUT_TYPE
value: log
這裡如果有想不通路徑下的日誌區分,可以加上document_type
apiVersion: v1
kind: ConfigMap
metadata:
name: filebeat-config
data:
filebeat.yml: |
filebeat.prospectors:
- input_type: log
paths:
- "/log/*.log"
document_type: app-logs
multiline.pattern: '^[[:space:]]+|^Caused by:|^#{3}|^;|^org|^com'
multiline.negate: false
multiline.match: after
- input_type: log
paths:
- "/logs/*.log"
document_type: access-logs
multiline.pattern: '^[[:space:]]+|^Caused by:|^#{3}|^;|^org|^com'
multiline.negate: false
multiline.match: after
output.elasticsearch:
hosts: ["192.168.30.21:9200"]
index: "filebeat-test-%{+yyyy.MM.dd}"
目前使用這種方式會有個問題,及時PATHS只能傳遞單個目錄,如果想傳遞多個目錄需要修改filebeat映象的docker-entrypoint.sh指令碼,對該環境變數進行解析增加filebeat.yml檔案中的PATHS列表。
推薦使用ConfigMap,這樣filebeat的配置就能夠更靈活。
注意事項
將app的/usr/local/TalkingData/logs目錄掛載到filebeat的/log目錄下。
該檔案可以在manifests/test/filebeat-test.yaml找到。
我使用了自己的私有映象倉庫,測試時請換成自己的應用映象。
Filebeat的環境變數的值配置請參考https://github.com/rootsongjc/docker-images
建立應用
部署Deployment
kubectl create -f filebeat-test.yaml
檢視http://172.23.5.255:9200/_cat/indices將可以看到列表有這樣的indices:
green open filebeat-docker-test 7xPEwEbUQRirk8oDX36gAA 5 1 2151 0 1.6mb 841.8kb
訪問Kibana的web頁面,檢視filebeat-2017.05.17的索引,可以看到filebeat收集到了app日誌。
點開每個日誌條目,可以看到以下詳細欄位:
filebeat收集的日誌詳細資訊
圖片 - filebeat收集的日誌詳細資訊
_index值即我們在YAML檔案的configMap中配置的index值
beat.hostname和beat.name即pod的名稱
source表示filebeat容器中的日誌目錄
我們可以通過人為得使index = service name,這樣就可以方便的收集和檢視每個service的日誌。
在使用了6.2.4版本的ELK以後,使用如上配置,if [type]匹配不到在filebeat裡面使用document_type定義的字串。在多次除錯和詢問後,發現在6.0版本以上已經取消了document_type的定義。如果要實現以上的配置只能使用如下配置
三、解決方案
?解決方案為在filebeat裡面新增一個fields欄位,service : GameStatis都是自己定義的,定義完成後使用Logstash的if 判斷,條件為if [fields][service] == "GameStatis".就可以了。
?filebeat配置:
filebeat.yml: |
filebeat.prospectors:
- input_type: log
paths:
- "/log/*.log"
fields:
service: app_logs