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 (重点!!!)
拉取镜像: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')