本篇文章着重的是实战方面,基于本机使用docker来搭建elk环境,然后接入frostmourne来实现监控、报警、分析系统,后续会再发文来介绍如何将此监控报警发布到生产环境。
随着公司业务的不断发展,系统开发的功能也越来越多,服务也越来越多,随之而来的就是遇到的问题也越来越多,那么此时服务报警监控也显得越来越重要,基于此,本文就以本机使用docker搭建elk环境并接入frostmourne来实现监控报警效果来给大家共享学习一下。
我们学习任何东西都需要先了解它的概念,ELK也是如此,关于ELK的基本概念,大家可以看Centos8搭建elk(v7.8.0)环境并使用prometheus监控这篇文章,这里面有很详细的基本概念介绍以及对应的Centos8操作系统如何搭建elk并加入prometheus监控的,这里就不做过多的赘述了。
执行下面搜索elasticsearch镜像命令:
docker search elasticsearch
执行下面拉取镜像命令(默认拉取最新版):
docker pull docker.elastic.co/elasticsearch/elasticsearch:7.17.3
执行以下命令来查看elasticsearch镜像是否已加载:
docker images | grep elasticsearch
执行创建挂载目录命令:
mkdir -p /data/elk/es/{config,data,logs}
执行赋予权限命令:
chown -R 1000:1000 /data/elk/es
创建elasticsearch.yml:
cd /data/elk/es/config/
touch elasticsearch.yml
配置文件内容:
cluster.name: "dxm-es"
network.host: 0.0.0.0
http.port: 9200
接下来我们通过镜像来启动一个容器,并将9200和9300端口映射到本机(elasticsearch的默认端口是9200,我们把本机的9200端口映射到Docker容器中的9200端口)。
docker run -it -d -p 9200:9200 -p 9300:9300 --name es -e ES_JAVA_OPTS="-Xms1g -Xmx1g" -e "discovery.type=single-node" --restart=always \
-v /data/elk/es/config/elasticsearch.yml:/etc/elasticsearch/config/elasticsearch.yml \
-v /data/elk/es/data:/etc/elasticsearch/data \
-v /data/elk/es/logs:/etc/elasticsearch/logs \
docker.elastic.co/elasticsearch/elasticsearch:7.17.3
看到这个容器ID说明已经启动成功。接下来我们curl一下,验证安装是否成功:
curl http://localhost:9200
执行下面搜索kibana镜像命令:
docker search kibana
执行下面拉取镜像命令:
ddocker pull docker.elastic.co/kibana/kibana:7.17.3
执行以下命令来查看kibana镜像是否已加载:
docker images | grep kibana
执行下面命令来获取elasticsearch容器IP:
docker inspect --format '{{ .NetworkSettings.IPAddress }}' es
新建配置文件,用于docker文件映射。
mkdir -p /data/elk/kibana
vim /data/elk/kibana/kibana.yml
配置文件内容:
#Default Kibana configuration for docker target
server.name: kibana
server.host: "0"
elasticsearch.hosts: ["http://172.17.0.2:9200"]
xpack.monitoring.ui.container.elasticsearch.enabled: true
注意:elasticsearch.hosts
这里的IP要修改为自己对应的elasticsearch的容器IP地址。
同样的,我们还是通过镜像来启动一个容器,具体执行命令如下:
docker run -d --restart=always --log-driver json-file --log-opt max-size=100m --log-opt max-file=2 --name kibana780 -p 5601:5601 -v /data/elk/kibana/kibana.yml:/usr/share/kibana/config/kibana.yml docker.elastic.co/kibana/kibana:7.17.3
看到这个容器ID说明已经启动成功。验证安装是否成功:
我们在输入到浏览器访问一下:
问题1:Kibana server is not ready yet,我们查看一下容器错误日志docker logs 92c79376f6a6 | grep error
:
重点:Unable to retrieve version information from Elasticsearch nodes. getaddrinfo ENOTFOUND elasticsearch,大概意思就是不能获取到Elasticsearch的版本信息,其实和下面这个错误是一样的(下面这个是我用8.2.0版本做的测试),根本原因就是你kibana容器里面的配置文件对应的elasticsearch的地址不对,要么是启动的时候挂载的有问题,要么就是宿主机里面的kibana.yml配置的elasticsearch地址不对。
大家可以看到这里的status是red
,es插件这里显示的是Unable to connect to ElasticSearch at http://elasticsearch:9200,我们执行docker logs -f 容器ID
命令看到如下日志:
{“type”:“log”,“@timestamp”:“2022-05-06T07:59:03Z”,“tags”:[“warning”,“elasticsearch”,“admin”],“pid”:13,“message”:“Unable to revive connection: http://elasticsearch:9200/”}
{“type”:“log”,“@timestamp”:“2022-05-06T07:59:03Z”,“tags”:[“warning”,“elasticsearch”,“admin”],“pid”:13,“message”:“No living connections”}
问题2:Unable to revive connection: http://elasticsearch:9200/
原因:容器内es的IP地址配置不对
解决方案:
第①步:进入容器内:docker exec -it 容器ID /bin/bash
第②步:找到/etc/kibana/kibana.yml文件,编辑内容如下:
server.name: kibana
server.host: “0”
elasticsearch.hosts: [“http://172.17.0.2:9200”]
xpack.monitoring.ui.container.elasticsearch.enabled: true
esc:wq! 保存之后输入exit退出docker容器,然后重启kibana:docker restart 容器ID
然后我们访问一下http://localhost:5601/
看到如下:
到这里说明我们已经成功安装了kibana。
为了解决问题,我们需要进入容器使用Vim命令编辑文件,但是容器一般没有安装vim,就需要安装vim,apt-get install vim命令用于安装vim,但是下载过慢,所以我们需要执行以下三步:
第①步:配置国内镜像源
进入某个容器内,执行:
mv /etc/apt/sources.list /etc/apt/sources.list.bak
echo “deb http://mirrors.163.com/debian/ jessie main non-free contrib” >> /etc/apt/sources.list
echo “deb http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib” >>/etc/apt/sources.list
echo “deb-src http://mirrors.163.com/debian/ jessie main non-free contrib” >>/etc/apt/sources.list
echo “deb-src http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib” >>/etc/apt/sources.list
第②步:更新源
apt update
第③步:apt-get install vim
然后就可以进行编辑文件内容了。
执行下面搜索logstash镜像命令:
docker search logstash
执行下面拉取镜像命令:
docker pull docker.elastic.co/logstash/logstash:7.17.3
执行以下命令来查看logstash镜像是否已加载:
docker images | grep logstash
新建配置文件,用于docker文件映射。
mkdir -p /data/elk/logstash
vim /data/elk/logstash/logstash.yml
配置文件内容:
http.host: "0.0.0.0"
xpack.monitoring.elasticsearch.hosts: [ "http://172.17.0.2:9200" ]
path.logs: /var/log/logstash
注意:xpack.monitoring.elasticsearch.hosts
这里的IP要修改为自己对应的elasticsearch的容器IP地址。
同样的,我们还是通过镜像来启动一个容器,具体执行命令如下:
非交互模式:
docker run -d --restart=always --log-driver json-file --log-opt max-size=100m --log-opt max-file=2 -p 5044:5044 --name logstash -v /data/elk/logstash/logstash.yml:/usr/share/logstash/config/logstash.yml -v /data/elk/logstash/conf.d/:/data/docker/logstash/conf.d/ docker.elastic.co/logstash/logstash:7.17.3
看到这个容器ID说明已经启动成功。如果不放心,我们可以看一下容器日志是否有报错:
可以看到并没有error日志,说明启动成功了。
交互模式:
docker run -it -p 5044:5044 -p 9600:0600 --restart=always --log-driver json-file --log-opt max-size=100m --log-opt max-file=2 --name logstash -v /data/elk/logstash/logstash.yml:/usr/share/logstash/config/logstash.yml -v /data/elk/logstash/conf.d/:/data/docker/logstash/conf.d/ docker.elastic.co/logstash/logstash:7.17.3 bash
注意:为了便于我们测试,这里的启动命令使用的是交互模式
。
我们输入命令:logstash -e “input { stdin {} } output{stdout{}}”,把标准的输入输出作为logstash的输入和输出验证是否启动,界面如下:
这种把标准的输入输出作为logstash的输入和输出验证比较直观,所见即所得。当然,我们也可以输出到文件,可以用如下命令:
logstash -e 'input { stdin {} } output { file { path => "/tmp/test-%{+YYYY.MM.dd}.log"} }'
这个方式比较简单,这里我们就不做测试了,到这里说明我们已经成功安装了logstash。
执行以下命令:
logstash -e 'input { stdin {} } output { elasticsearch { hosts => ["172.17.0.2:9200"] index => "logstash-test-%{+YYYY.MM.dd}" } }'
然后我们在kibana看一下
点击create index pattern
创建索引,
然后我们做字段映射:
然后点击Discover:
可以看到我们刚才测试输入的内容已经成功输出到了elasticsearch中。
我们输入:
curl http://localhost:9200/_cat/indices\?v
可以看到logstash-test-2022.05.08,则表示elasticsearch已经可以获取来自logstash的数据,同时kibana也可以展示出来。然后我们再将交互模式的容器停止,用非交互模式启动logstash。
前面我们已经将elasticsearch、kibana和logstash都启动成功了,那么如果我们想让logstash和Elasticsearch能配合使用,我们需要另外一个插件filebeat,虽然logstash 和filebeat都具有日志收集功能,但是filebeat更轻量,占用资源更少,而不同的是logstash 具有filter功能,能过滤分析日志,所以一般都是filebeat采集日志,然后发送到MQ中,然后logstash去读取,利用filter功能过滤分析,然后存储到elasticsearch中,下面我们来安装一下filebeat。
执行下面搜索filebeat镜像命令:
docker search filebeat
执行下面拉取镜像命令(默认拉取最新版):
docker pull docker.elastic.co/beats/filebeat:7.17.3
注意:filebeat的版本要和elasticsearch、kibana保持一致
,否则会出现一些不必要的异常需要处理,会很麻烦,这是我走了弯路之后,给大家的一点建议。
执行以下命令来查看filebeat镜像是否已加载:
docker images | grep filebeat
新建配置文件,用于docker文件映射。
mkdir -p /data/elk/filebeat
vim /data/elk/filebeat/filebeat.yml
配置文件内容:
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/messages/*.log
setup.kibana:
host: "172.17.0.3:5601"
output.elasticsearch.allow_older_versions: true
output.elasticsearch:
hosts: '192.168.120.78:9200'
indices:
- index: "filebeat-%{+yyyy.MM.dd}"
#----------------------------- Logstash output --------------------------------
output.logstash:
# The Logstash hosts
hosts: '192.168.120.78:5044'
注意:output.elasticsearch.hosts
和output.logstash.hosts
这里的IP要修改为自己对应的elasticsearch的容器IP地址。
同样的,我们还是通过镜像来启动一个容器,具体执行命令如下:
docker run -d \
--name=filebeat \
--restart=always \
-v /data/elk/filebeat:/usr/share/filebeat \
-v /var/log/messages:/var/log/messages \
docker.elastic.co/beats/filebeat:7.17.3
注意:问题记录里面涉及到的版本可能和上面的不一样,因为一开始是高版本做的测试,后面慢慢的换了版本,问题记录的是遇到的所有问题,不一定是同一个版本的。
这里我们把部署过程中遇到的问题进行记录一下,目的是帮助自己和他人避免踩坑。
解决方案:
docker ps | grep filebeat
docker stop e2d8743bd5af
docker rm -f e2d8743bd5af
docker run -d --name=filebeat docker.elastic.co/beats/filebeat:8.2.0
docker cp filebeat:/usr/share/filebeat /data/
这时候我们可以-v去映射目录了,但是…还有坑,我们用docker cp命令复制完之后权限发生了改变,你会发现还是起不来,给特权也不行,我们只能修改容器内的文件权限了:
chown -R 1000:1000 filebeat/
然后再次重启容器,发现还是有坑,Exiting: error unpacking config data: more than one namespace configured accessing ‘output’ (source:‘filebeat.yml’)
从字面意思看,退出:解压缩配置数据时出错:访问“输出”时配置了多个命名空间(源:‘filebeat.yml’),那么我们修改一下我们的filebeat.yml:
然后重启我们的容器:docker restart eb430e4108d9
再执行docker logs eb430e4108d9 | grep error,看到:
Exiting: error initializing processors: each processor must have exactly one action, but found 3 actions (hosts,indices,add_docker_metadata)
我们修改我们的filebeat.yml配置文件:
然后重启我们的容器:
可以看到我们的容器启动成功了。
{"log.level":"error","@timestamp":"2022-05-07T00:39:49.116Z","log.origin":{"file.name":"instance/beat.go","file.line":1038},
"message":"Exiting: error connecting to Kibana: fail to get the Kibana version: HTTP GET request to http://localhost:5601/api/status fails: fail to execute the HTTP GET request: Get \"http://localhost:5601/api/status\": dial tcp [::1]:5601: connect: cannot assign requested address. Response: .","service.name":"filebeat","ecs.version":"1.6.0"}
Exiting: error connecting to Kibana: fail to get the Kibana version: HTTP GET request to http://localhost:5601/api/status fails: fail to execute the HTTP GET request: Get "http://localhost:5601/api/status": dial tcp [::1]:5601: connect: cannot assign requested address. Response: .
解决方案:和elasticsearch、kibnana版本不一致?8.2.0->5.6.12
然后重启容器,查看容器日志:
报错如下:
{"log.level":"error","@timestamp":"2022-05-07T02:07:17.488Z","log.origin":{"file.name":"instance/beat.go","file.line":1038},
"message":"Exiting: error connecting to Kibana: fail to get the Kibana version: fail to unmarshal the response from GET http://172.17.0.3:5601/api/status. Response: {\"name\":\"kibana\",\"version\":\"5.6.12\",\"buildNum\":15653,\"buildSha\":\"a07347478b7a3b1661cfb77c149fd15bdeb8921d\",\"uuid\":\"afef1289-d441-400b-a216-8fba73037b8b\",\"status\":{\"overall\":{\"state\":\"green\",\"title\":\"Green\",\"nickname\":\"Looking good\",\"icon\":\"success\",\"... (truncated). Kibana status api returns: json: cannot unmarshal string into Go struct field kibanaVersionResponse.version of type struct { Number string \"json:\\\"number\\\"\"; Snapshot bool \"json:\\\"build_snapshot\\\"\" }","service.name":"filebeat","ecs.version":"1.6.0"}
Exiting: error connecting to Kibana: fail to get the Kibana version: fail to unmarshal the response from GET http://172.17.0.3:5601/api/status. Response: {"name":"kibana","version":"5.6.12","buildNum":15653,"buildSha":"a07347478b7a3b1661cfb77c149fd15bdeb8921d","uuid":"afef1289-d441-400b-a216-8fba73037b8b","status":{"overall":{"state":"green","title":"Green","nickname":"Looking good","icon":"success","... (truncated). Kibana status api returns: json: cannot unmarshal string into Go struct field kibanaVersionResponse.version of type struct { Number string "json:\"number\""; Snapshot bool "json:\"build_snapshot\"" }
解决方案:注释掉#setup.dashboards.enabled: true,然后重启容器,查询容器:
问题解决。
我们先修改配置文件将output改为elasticsearch,注释掉logstash,如下:
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/messages/*.log
setup.kibana:
host: "172.17.0.3:5601"
output.elasticsearch.allow_older_versions: true
output.elasticsearch:
hosts: ["172.17.0.2:9200"]
indices:
- index: "filebeat-%{+yyyy.MM.dd}"
#----------------------------- Logstash output --------------------------------
#output.logstash:
# The Logstash hosts
# hosts: '172.17.0.4:5044'
然后重启容器。打开kibana:
然后我们打开discover:
我们看到有filebeat-*这个index了,然后我们搜索一下:
ke’yi可以看到我们的日志目录就是filebeat配置文件里面日志目录,这里我用了本机的arthas的日志文件做了测试,因为我觉得实在没必要再弄一个单独的日志文件做测试,就用现成的了。
至此我们就完成了使用docker搭建eLk的环境,下面我们来接入一下frostmourne
frostmourne(霜之哀伤)是汽车之家经销商技术部监控系统的开源版本,用于帮助开发监控应用日志,现主要用于监控Elasticsearch数据。如果你现在使用Elastic stack(ELK)建立起了日志系统,却苦恼于没有一个配套日志监控系统,也许它能帮到你。
在用ELK建立起日志系统之后,我们发现应用日志监控这块除了ElastAlert之外,没有其他方案。我们初期使用ElastAlert来解决日志监控的问题, 但是随着配置的增加,不仅管理成本和使用成本较高,稳定性方面也不能让我们满意,所以为了更好的易用性,稳定性,我们决定自己做一套简单的监控系统, 来解决日志监控的问题。如果你面临和我们同样的问题,不妨一试。
但是项目并不仅限于elasticsearch数据,还有HTTP数据监控,InfluxDB数据监控,Mysql数据监控, ClickHouse数据监控,后面还会加入更多的常用数据源(如:prometheus, skywalking, iotdb, loki等)纳入监控范畴,需要做的东西还有很多,需要更多相关开发加入进来,欢迎联系我们,一起做大做强。
提供docker-compose方式,让你更快运行起来便于更好理解项目作用。 详细请看文档:
Quick-Start,下面我们就参考这个文档来操作一下。
JDK 1.8
Maven 3.2.x+
Mysql 5.7.8+
mysql我这里用的是MySQL8版本,本机用docker-compose启动的,大家也可以使用上面快速启动里面提供的方式搭建一个。
按照文档里面介绍的使用docker-compose方式启动完成:
接下来我们就按照官方Elasticsearch数据监控指南文档来接入一下我们的es。
打开页面:数据管理->数据源,点击新增按钮,弹出窗口,填写字段并保存。
注意:
1、服务地址端口不能缺省
,就算是80端口也需要加上, 而且不能带scheme(http, https)
2、es开启http-ssl认证时,需要上传.p12扩展名ssl证书以及证书密码
,如:elastic-certificates.p12,我搭建的elasticsearch并没有开启http-ssl认证,所以这里我们就选择否就好了。
打开页面:数据管理->数据名,点击新增按钮,弹出窗口,填写字段并保存。
数据名在elasticsearch场景可以理解为索引模式,之所以不直接用索引,是因为项目计划不只支持elasticsearch,还会支持influxdb等其它数据源类型。索引后缀如果不是标准的时间模式或者单位小于天的时间模式,可以用*号。
其中显示字段可以配置数据查询页面列表表头显示的字段和顺序,信息填写完毕,点击保存
添加完数据名,打开数据查询页面,下拉选择刚才保存的数据名,点击查询,如果查出来数据和你的索引数据对上了,说明数据信息都填写正确了。
query string查询语句语法不清楚的,可以参考文档: query string简易教程,查询页面主要特性列表:
在添加监控之前,我们先添加服务信息,因为在添加监控的时候需要选择对应的服务。
点击保存。
打开页面:监控管理->监控编辑。填入信息并保存,保存前可以先进行测试。
这里查询语句填写的是input.type: log,是因为用的arthas日志,不是程序日志,大家在写的时候这块可以随着自己的项目改变,因为frostmourne项目elasticsearch查询语句使用的是query string语句,而不是DSL query, 这里提供了一个简易教程供不会的同学快速 入门,英文水平可以的同学最好是看官方文档。
表示最近1000分钟查出来的日志数量大于1就报警,因为我们是测试数据,日志不是一直不断有输出的,所以设置的时间大一些,大家要根据自己的需求来定义。
因为我这个是测试用的日志,所以消息模板就简化了,主要是要达到报警的效果。官方的消息模板是:
${Project}最近${TIME_WINDOW}分钟内有异常日志${NUMBER}条。最近一条异常信息:
服务器IP: ${ServerIP}
异常类型: ${ExceptionType}
自定义信息: ${CustomMessage}
异常信息: ${ExceptionMessage}
注意:使用者需要根据自己的日志格式指定消息模板,不能直接套用我们的,因为大家日志格式都不一样。关于消息模板如何定制,请看文档:消息模板配置。
报警方式我这里选择的是钉钉,然后简单拉了个三人的钉钉群,申请了群机器人来测试的,为了看测试效果,我们这里设置了静默时间为1分钟,大家要按照需求来设定,另外报警接收人
这个要注意一下,设置的就是消息里面@的人,我这里因为没有加其他用户,所以只能默认选择的admin,后面消息里面拿不到admin的信息,@的就是空。
然后,我们点击测试:
最后点击保存。再点击运行,弹出运行结果如下:
监控每次运行都会产生一条执行日志,在页面监控管理->执行日志能看到所有监控的执行日志。如果产生了报警发送,还会产生消息发送记录,在页面监控管理->我的消息可以看到所有发送给你的消息。
问题1:elasticsearch 报错:field name is null or empty
验证查询的时候,提示unknown exception,进入容器,查看日志:
一番Google和百度之后,都没有解决问题,然后就各种尝试其他的解决办法,还好被我发现了,结果错误提示field name is null or empty
以及查看容器日志里面显示的EsRestClientContainer.java:143
,再次综合判断,怀疑是这个是因为查询的时候用到了timestampField这个字段导致的错误,然后编辑刚才的数据名里面的时间字段:
点击保存,再点击数据查询
提示error when search elasticsearch data
,好吧,打地鼠吧,解决一个还有一个。同样的,我们查看日志里面的报错信息:
从日志可以看出来是连接我们的elasticsearch的时候被拒绝了。然后看一下我们配置的数据源elasticsearch的地址是127.0.0.1:9200
,我去,被误导了,这要是能访问通就怪了,然后修改一下我们数据源的地址为192.168.0.4:9200
:
点击保存。再点击数据查询:
又是未知异常,我们再次查看容器日志:
原因是no such index [null],为什么呢?看我上面的filebeat-20220507
,再来看看我本地kibana里面的index:
到这里,大家应该明白了,问题所在了吧,我修改一下数据名里面的时间后缀:
我们点击保存,再点击数据查询:
好了,问题都解决了,查询也出来了。
以上就是这篇文章要讲的内容,本文不仅仅是简单介绍了如何使用docker来搭建elk环境,还记录了在搭建过程中遇到的各种问题,很多问题都有对应的原因以及解决方案,希望能对大家有所帮助,另外,frostmourne除了接入elasticsearch监控以外,还可以接入MySQL、influxDB、http、clickhouse的监控,有兴趣的可以尝试一下。