1. 集中式日志管理框架ELK簡介
那么,什么是ELK Stack?“ELK”是三個開源項目的首字母縮寫:Elasticsearch,Logstash和Kibana。Elasticsearch是一個搜索和分析引擎。Logstash是一個服務器端數據處理管道,它同時從多個源中提取數據,對其進行轉換,然后將其發送到像Elasticsearch這樣的“存儲”。Kibana允許用戶使用Elasticsearch中的圖表和圖形來可視化數據。
以上的介紹來自官網翻譯,簡單明了。
為什么我們需要這么一個日志管理平臺呢?
在微服務架構下,各個服務可能分布在不同的服務器上,其產生的日志也是分布在不同的機器。當我們遇到一個復雜業務調用出錯時,我們可能需要在查看多臺機器日志才能定位問題,極為不便。此時,一個集中式的日志管理平臺就顯得極為高效和方便。
本文著重介紹Docker 下 ElasticSearch + Kibana + FileBeat的環境搭建。傳統的Logstash因為過于笨重慘遭市場淘汰,本例不再采用。
本示例環境說明:
- windows開發環境下運行了6個服務,產生6個以.log結尾的日志文件存放在D:\log文件夾下,日志格式為springboot默認格式
- windows環境下安裝docker,使用docker方式進行安裝,文檔采用ES 7.3.1版本,實際案例使用的是7.2.0版本
- 本例以學習為目的,盡量以容易理解的方式闡述搭建過程,實現最小化安裝,如集群、安全等未作拓展
1.1 官方文檔
ES Stack 官方文檔
官方文檔中,對ES Stack技術棧有著詳盡的介紹,包括各個組件的下載安裝、配置項等等。雖然很詳細,但對于英語渣渣的我也是看了一禮拜毫無進展,建議還是國產博客+官方文檔的形式進行學習。
1.2. Beats介紹
上文沒有介紹的FileBeat,就是常用日志log類型的運輸器,使用FileBeat將采集我們服務產生的日志,并以json格式發送到ES,ES將數據進行索引。
官方介紹及圖例:
Beats是您在服務器上作為代理安裝的開源數據托運方,用于將操作數據發送到 Elasticsearch。Elastic提供Beats捕獲:
審計數據Auditbeat
日志文件Filebeat
云數據Functionbeat
可用性Heartbeat
系統期刊Journalbeat
度量Metricbeat
網絡流量Packetbeat
Windows事件日志Winlogbeat
Beats可以直接將數據發送到Elasticsearch或通過 Logstash,您可以在Kibana中對數據進行可視化之前進一步處理和增強數據 。
要開始使用,請參閱Beats入門。
2. 環境搭建
官方安裝文檔
在上面文檔中選擇docker安裝,有詳盡的英文文檔
注意,ES版本更新很快,下面的版本號請更換成最新版本
2.1 docker安裝ES
拉取鏡像:docker pull docker.elastic.co/elasticsearch/elasticsearch:7.3.1
運行容器:docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.3.1 --name=elasticsearch
使用docker logs elasticsearch
查看啟動日志
訪問宿主機端口,如圖所示代表ES運行正常
2.2 docker安裝Kibana
拉取鏡像:docker pull docker.elastic.co/kibana/kibana:7.3.1
運行容器:docker run --link YOUR_ELASTICSEARCH_CONTAINER_NAME_OR_ID:elasticsearch -p 5601:5601 --name=kibana
注意,這里的YOUR_ELASTICSEARCH_CONTAINER_NAME_OR_ID
就是上面我們創建ES容器的ID或者名稱,此處替換為我們指定的名稱elasticsearch
使用docker logs kibana
查看啟動日志
此時訪問宿主機對應的端口,可以看到可視化的kibana web界面:
2.3 docker安裝FileBeat (重點?。。。?/h3>
拉取鏡像:docker pull docker.elastic.co/beats/filebeat:7.3.1
運行容器:docker run -d --name=filebeat --volume="你的filebeat.yml配置文件:/usr/share/filebeat/filebeat.yml:ro" --volume="你的日志文件夾路徑:/var/lib/docker/containers:ro" docker.elastic.co/beats/filebeat:7.3.1 filebeat
本實例實際運行的命令如下,掛載了C:\docker\filebeat\filebeat.docker.yml文件作為filebeat的配置文件,掛載了D:\log作為該機器上存儲log日志的目錄:
docker run -d --name=filebeat --volume="C:\docker\filebeat\filebeat.docker.yml:/usr/share/filebeat/filebeat.yml:ro" --volume="D:\log:/var/lib/docker/containers:ro" docker.elastic.co/beats/filebeat:7.2.0 filebeat
注意:啟動FileBeat需要一大堆配置,建議使用配置文件而不是在命令中配置。
filebeat從何處采集日志,如何解析各種格式的日志,解析后的日志以何種格式輸出到什么地方均配置在filebeat.yml中,后面我們著重介紹這個配置文件
使用docker logs filebeat
查看啟動日志
3. 配置FileBeat
在整個EKF日志系統中,FileBeat的配置最為復雜,需要一定耐心研究
注意事項,yml格式,千萬注意縮進?。?!
3.1 filebeat7.3.1配置官方文檔
建議先查看官方文檔,對filebeat常見配置有個了解后再進行filebeat.yml的編寫
3.2 常見filebeat配置
-
filebeat.inputs.- type
輸入的文件類型,本例中輸入為log文件 -
filebeat.inputs.- enabled
是否啟用當前輸入,一般為true -
filebeat.inputs.- paths
文件路徑,可以配置多個,在上面docker命令中我們掛載了宿主機log目錄在容器/var/lib/docker/containers
目錄下,故此處應配置為容器內部目錄 -
multiline
多行合并配置,例如日志為堆棧異常,應將多行日志合并為一條消息。multiline底下的三個配置較為抽象,后面我們再詳細解讀 -
setup.template
模板配置,filebeat會加載默認的模板,當我們想指定自己的索引名稱時在此指定name和匹配規則pattern -
setup.ilm.enabled
當配置模板名稱后不生效,需要關閉此開關 -
output.elasticsearch.hosts
輸出到ES的地址,注意本例中ES和Filebeat均為docker安裝,我在此處配置的IP為宿主機的Docker虛擬網關。也可以使用其他配置進行容器互訪,注意在filebeat容器中一定要能夠訪問此地址 -
output.elasticsearch.index
輸出到ES的索引名稱,這個配置和上面setup.template.name
setup.template.pattern
需要一起使用 -
setup.kibana.host
配置kibana的地址,一般來說filebeat直接發送數據給ES,kibana只做展示可以不用配置,但要使用kibana的dashboard等功能的話需要作出此配置
以上為本實例的基本配置簡要說明,本例具體配置文件如下
filebeat.inputs:
- type: log
paths:
- /var/lib/docker/containers/*.log
# 默認json日志在filebeat發送內容的json字段內,如需放在根root下,需打開此開關
#json.keys_under_root: true
# json字段是否覆蓋filebeat默認的字段,例如日志的時間覆蓋filebeat的@timestamp
#json.overwrite_keys: true
# 當json出錯時封裝一個error.message錯誤消息字段
#json.add_error_key: true
# json解析選項,當你的日志為json格式時啟用,用于過濾單行和多行的設置。這個字段名必須是json根字段名且值必須是String類型,否則配置不生效。如果此項配置未定義,將無法使用多行配置
#json.message_key:
# 多行合并配置
# 匹配的正則表達式,如下面的意思是匹配以日期格式yyyy-MM-dd HH:mm:ss 開頭的行
multiline.pattern: ''^[0-9]{4}-[0-9]{2}-[0-9]{2}''
# 是否取反,即當不以日期格式開頭時
multiline.negate: true
# 匹配規則,before 還是 after。三個配置加起來的意思是: 讀取的行不以日期開頭時,合并到以日期開頭為一行。例如堆棧異常多行信息應當合并為一行消息
multiline.match: after
# 默認的模板名稱是 "filebeat-%{[agent.version]}",這里可以指定自定義的index template名稱
setup.template.name: "service-log-"
# 默認的模板匹配規則是 "-%{[agent.version]}-*" ,這個pattern需要在kibana中創建
setup.template.pattern: "service-log-*"
#關閉ilm,否則索引名稱不生效
setup.ilm.enabled: false
# 輸出到ES
output.elasticsearch.hosts: ["172.28.26.129:9200"]
# 輸出的索引名稱,需要指定setup.template.name和setup.template.pattern
output.elasticsearch.index: "service-log-%{+yyyy.MM.dd}"
# 輸出到kibana的地址
setup.kibana.host: "172.28.26.129:9200"
3.3 Multiline配置
當我們日志打印了堆棧異常時,情況如下
2019-08-28 08:48:00.942 ERROR 4108 --- [ parallel-6] d.c.b.a.s.c.d.InstanceDiscoveryListener : Unexpected error.
reactor.retry.RetryExhaustedException: de.codecentric.boot.admin.server.eventstore.OptimisticLockingException: Verison 0 was overtaken by 0 for f91020c119f1
at reactor.retry.DefaultRetry.retry(DefaultRetry.java:130) ~[reactor-extra-3.1.9.RELEASE.jar:3.1.9.RELEASE]reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:357) [reactor-core-3.1.14.RELEASE.jar:3.1.14.RELEASE]
at reactor.core.publisher.MonoDelay$MonoDelayRunnable.run(MonoDelay.java:118) ~[reactor-core-3.1.14.RELEASE.jar:3.1.14.RELEASE]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_91]
at java.lang.Thread.run(Thread.java:745) ~[na:1.8.0_91]
該日志格式為Java Springboot 使用的默認格式,正常日志每行以日期開頭,匹配^[0-9]{4}-[0-9]{2}-[0-9]{2}
這個正則。
在filebeat采集日志時,默認以行為單位,即如上日志filebeat將采集為7條日志信息,這明顯是不合理的,應當將不以日期開頭的行合并到上一條符合日期開頭的行作為一條日志信息作為采集。
當如3.2配置時,ES獲取的日志如下,成功完成了多行合并:
3.4 關于docker容器互訪
本例中容器互訪通過docker虛擬網關地址,如上面配置中的output.elasticsearch.hosts: ["172.28.26.129:9200"]
IP為宿主機docker虛擬網關地址,各位也可采用其他如--link
的方式
windows查看docker虛擬網關如圖,docker容器可以通過該地址+其他容器映射的端口訪問其他容器。linux下請百度查找該IP的方式
4. 啟動FileBeat
當我們配置好filebeat.yml后,便可參照步驟2.3啟動filebeat容器,以下為步驟和注意事項
- 使用
docker restart filebeat
命令可以重啟容器,我們修改filebeat.yml配置文件后使用此命令可以重新加載配置 - 使用
docker exec -it filebeat /bin/bash
命令可以進入filebeat交互界面,在此交互界面可以看到如下文件
PS C:\Users\user> docker exec -it filebeat /bin/bash
bash-4.2$ ls
LICENSE.txt NOTICE.txt README.md data fields.yml filebeat filebeat.reference.yml filebeat.yml kibana logs module modules.d
filebeat.yml
文件即為創建filebeat容器時和容器掛載的配置文件,實際為宿主機上的C:\docker\filebeat\filebeat.docker.yml
文件,使用cat filebeat.yml
可以查看配置文件是否掛載成功
logs
目錄,該目錄下存儲了filebeat的日志,使用cat logs/filebeat
查看日志,可以根據日志判斷當前filebeat是否運行正常,是否連接到ES,是否正常獲取日志文件等內容
正常日志如下,可以看到成功連接ES,收割日志文件:
5. Kibana的簡單使用
5.1查看索引
當filebeat配置正常運行,我們可以登錄Kibana,在management菜單下的的Index Management中可以看到如下內容:
service-log-2019.08.27
這個索引名稱就是在filebeat中配置的output.elasticsearch.index
filebeat-7.2.0
這個索引名稱為默認的索引名稱,當filebeat未作索引名稱時默認生成此索引
5.2 創建Index Pattern
如配置所示,index我們使用了日期,意味著每天filebeat都會創建一個格式為service-log-%{+yyyy.MM.dd}
的索引。
當我們查找日志時,如何查找多個索引中的信息?此時需要創建Index Pattern,步驟如下
在Kibana的Management - Index patterns - Create index pattern菜單可以看到如下界面
輸入一個IndexPattern,Kibana將會展示符合該Pattern的所有Index,當存在這樣的索引時,提示Success,點擊Next Step即可創建該IndexPattern
5.3 使用Discover搜索日志
訪問Kibana下的Discover菜單,可見如下界面:
左側下拉菜單中展示了當前Kibana中已經創建的IndexPattern
@timestamp
為采集日志的時間,這個時間會稍晚于日志的實際時間,當然這個時間可以配置為日志的記錄時間覆蓋掉,后面再說
log.file.path
這個路徑為filebeat容器內部的路徑,可以看到當前日志來自于zh-linemanager.log
文件
message
這個則為實際采集的一行日志
假設前端頁面展示了某個異常信息lineId不能為空
需要查找具體的日志,過濾message字段進行搜索,如下圖所示,可以快速的獲取到日志信息,即使該異常信息可能來自任何一個服務,我們均能快速的定位到所在的服務。
6 其他配置
6.1 filebeat_reference.yml
filebeat_reference.yml文件是ES官方網站提供的參考文件,包含各項配置的示例及英文說明,如有超出本例需求外的配置,可以進行配置的查找,訪問下面鏈接即可
https://www.elastic.co/guide/en/beats/filebeat/7.3/filebeat-reference-yml.html
6.2 使用Json格式常見異常(暫時沒有找到適合JSON日志且能處理堆棧異常的解決方案,僅先記錄一下)
@timestamp格式化異常,使用json日志格式,并覆蓋filebeat默認字段時出現,原因為josn日志中的日期格式不符合filebeat的UTC日期格式
2019-08-27T01:21:40.753Z ERROR jsontransform/jsonhelper.go:53 JSON: Won't overwrite @timestamp because of parsing error: parsing time "2019-08-27 09:21:27,487" as "2006-01-02T15:04:05Z07:00": cannot parse " 09:21:27,487" as "T"
json解碼于多行配置問題,需要指定message_key配置
Exiting: Error while initializing input: When using the JSON decoder and multiline together, you need to specify a message_key value accessing 'filebeat.inputs.0' (source:'filebeat.yml')
json解碼且使用了行過濾配置時,需指定message_key配置
Exiting: Error while initializing input: When using the JSON decoder and line filtering together, you need to specify a message_key value accessing 'filebeat.inputs.0' (source:'filebeat.yml')