监控和日志历来都是系统稳定运行和问题排查的关键,在微服务架构中,数量众多的容器以及快速变化的特性使得一套集中式的日志管理系统变成了生产环境中一个不可获取的部分。此次话题我们会集中在日志管理方面,本篇会介绍Docker自带的logs子命令以及其Logging driver,然后介绍一个流行的开源日志管理方案ELK/EFK。
一、Docker logs子命令
默认情况下,Docker的日志会发送到容器的标准输出设备(STDOUT)和标准错误设备(STDERR),其中STDOUT和STDERR实际上就是容器的控制台终端。
我们可以通过logs子命令来查看具体某个容器的日志输出:
docker logs edc-k8s-demo
这时看到的日志是静态的,截止到目前为止的日志。如果想要持续看到新打印出的日志信息,那么可以加上 -f 参数,如:
docker logs -f edc-k8s-demo
二、Docker logging driver
刚刚我们学习了默认配置下,Docker日志会发送到STDOUT和STDERR。但实际上,Docker还提供了其他的一些机制允许我们从运行的容器中提取日志,这些机制统称为 logging driver。
对Docker而言,其默认的logging driver是json-file,如果在启动时没有特别指定,都会使用这个默认的logging driver。
json-file会将我们在控制台通过docker logs命名看到的日志都保存在一个json文件中,我们可以在服务器Host上的容器目录中找到这个json文件。
容器日志路径:/var/lib/docker/containers/<container-id>/<container-id>-json.log
例如我们可以查看一个exceptionless-api容器的json日志:
一个快速查看某个容器的日志文件路径的方法:
docker inspect exceptionless_api_1
通过inspect命令,可以查到该容器的ID及一系列配置信息,我们重点关注LogPath即可:
查到LogPath后,即可复制其后面的日志路径了,打开这个json文件你就可以看到输出的容器日志了。
除了json-file,Docker还支持以下多种logging dirver,来源:Configure logging drivers
其中,none 代表禁用容器日志,不会输出任何容器日志。
其他几个logging driver解释如下:
- syslog 与 journald 是Linux上的两种日志管理服务
- awslog、splunk 与 gcplogs是第三方日志托管服务
- gelf 与 fluentd 是两种开源的日志管理方案
我们可以在容器启动时通过加上 --log-driver 来指定使用哪个具体的 logging driver,例如:
docker run -d --log-driver=syslog ......
如果想要设置默认的logging driver,那么则需要修改Docker daemon的启动脚本,例如:
{
"log-driver": "json-file",
"log-opts": {
"labels": "production_status",
"env": "os,customer"
}
}
每个logging driver都有一些自己特定的log-opt,使用时可以参考具体官方文档。
三、关于ELK
3.1 ELK简介
ELK 是Elastic公司提供的一套完整的日志收集以及展示的解决方案,是三个产品的首字母缩写,分别是ElasticSearch、Logstash 和 Kibana。
- Elasticsearch是实时全文搜索和分析引擎,提供搜集、分析、存储数据三大功能
- Logstash是一个用来搜集、分析、过滤日志的工具
- Kibana是一个基于Web的图形界面,用于搜索、分析和可视化存储在 Elasticsearch指标中的日志数据
3.2 ELK日志处理流程
上图展示了在Docker环境下,一个典型的ELK方案下的日志收集处理流程:
- Logstash从各个Docker容器中提取日志信息
- Logstash将日志转发到ElasticSearch进行索引和保存
- Kibana负责分析和可视化日志信息
由于Logstash在数据收集上并不出色,而且作为Agent,其性能并不达标。基于此,Elastic发布了beats系列轻量级采集组件。
这里我们要实践的Beat组件是Filebeat,Filebeat是构建于beats之上的,应用于日志收集场景的实现,用来替代 Logstash Forwarder 的下一代 Logstash 收集器,是为了更快速稳定轻量低耗地进行收集工作,它可以很方便地与 Logstash 还有直接与 Elasticsearch 进行对接。
本次实验直接使用Filebeat作为Agent,它会收集我们在第一篇《Docker logs & logging driver》中介绍的json-file的log文件中的记录变动,并直接将日志发给ElasticSearch进行索引和保存,其处理流程变为下图,你也可以认为它可以称作 EFK。
四、ELK套件的安装
本次实验我们采用Docker方式部署一个最小规模的ELK运行环境,当然,实际环境中我们或许需要考虑高可用和负载均衡。
首先拉取一下sebp/elk这个集成镜像,这里选择的tag版本是640(最新版本已经是7XX了):
docker pull sebp/elk:640
注:由于其包含了整个ELK方案,所以需要耐心等待一会。
通过以下命令使用sebp/elk这个集成镜像启动运行ELK:
docker run -it -d --name elk \
-p 5601:5601 \
-p 9200:9200 \
-p 5044:5044 \
sebp/elk:640
运行完成之后就可以先访问一下 http://[Your-HostIP]:5601 看看Kibana的效果:
Kibana管理界面
Kibana Index Patterns界面
当然,目前没有任何可以显示的ES的索引和数据,再访问一下http://[Your-HostIP]:9200 看看ElasticSearch的API接口是否可用:
ElasticSearch API
_Note:_如果启动过程中发现一些错误,导致ELK容器无法启动,可以参考《Docker启动ElasticSearch报错》及《ElasticSearch启动常见错误》一文。如果你的主机内存低于4G,建议增加配置设置ES内存使用大小,以免启动不了。例如下面增加的配置,限制ES内存使用最大为1G:
docker run -it -d --name elk \
-p 5601:5601 \
-p 9200:9200 \
-p 5044:5044 \
-e ES_MIN_MEM=512m \
-e ES_MAX_MEM=1024m \
sebp/elk:640
五、Filebeat配置
5.1 安装Filebeat
这里我们通过rpm的方式下载Filebeat,注意这里下载和我们ELK对应的版本(ELK是6.4.0,这里也是下载6.4.0,避免出现错误):
wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.4.0-x86_64.rpm
rpm -ivh filebeat-6.4.0-x86_64.rpm
5.2 配置Filebeat
这里我们需要告诉Filebeat要监控哪些日志文件 及 将日志发送到哪里去,因此我们需要修改一下Filebeat的配置:
cd /etc/filebeat
vim filebeat.yml
要修改的内容为:
(1)监控哪些日志?
filebeat.inputs:
# Each - is an input. Most options can be set at the input level, so
# you can use different inputs for various configurations.
# Below are the input specific configurations.
- type: log
# Change to true to enable this input configuration.
enabled: true
# Paths that should be crawled and fetched. Glob based paths.
paths:
- /var/lib/docker/containers/*/*.log
- /var/log/syslog
这里指定paths:/var/lib/docker/containers/_/_.log,另外需要注意的是将 enabled 设为 true。
(2)将日志发到哪里?
#-------------------------- Elasticsearch output ------------------------------
output.elasticsearch:
# Array of hosts to connect to.
hosts: ["192.168.16.190:9200"]
# Optional protocol and basic auth credentials.
#protocol: "https"
#username: "elastic"
#password: "changeme"
这里指定直接发送到ElasticSearch,配置一下ES的接口地址即可。
_Note:_如果要发到Logstash,请使用后面这段配置,将其取消注释进行相关配置即可:
#----------------------------- Logstash output --------------------------------
#output.logstash:
# The Logstash hosts
#hosts: ["localhost:5044"]
# Optional SSL. By default is off.
# List of root certificates for HTTPS server verifications
#ssl.certificate_authorities: ["/etc/pki/root/ca.pem"]
# Certificate for SSL client authentication
#ssl.certificate: "/etc/pki/client/cert.pem"
# Client Certificate Key
#ssl.key: "/etc/pki/client/cert.key"
5.3 启动Filebeat
由于Filebeat在安装时已经注册为systemd的服务,所以只需要直接启动即可:
systemctl start filebeat.service
检查Filebeat启动状态:
systemctl status filebeat.service
5.4 验证Filebeat
通过访问ElasticSearch API可以发现以下变化:ES建立了以filebeat-开头的索引,我们还能够看到其来源及具体的message。
六、Kibana配置
接下来我们就要告诉Kibana,要查询和分析ElasticSearch中的哪些日志,因此需要配置一个Index Pattern。从Filebeat中我们知道Index是filebeat-timestamp这种格式,因此这里我们定义Index Pattern为 filebeat-*
点击Next Step,这里我们选择Time Filter field name为@timestamp:
单击Create index pattern按钮,即可完成配置。
这时我们单击Kibana左侧的Discover菜单,即可看到容器的日志信息啦:
仔细看看细节,我们关注一下message字段:
可以看到,我们重点要关注的是message,因此我们也可以筛选一下只看这个字段的信息:
此外,Kibana还提供了搜索关键词的日志功能,例如这里我关注一下日志中包含unhandled exception(未处理异常)的日志信息:
这里只是朴素的展示了导入ELK的日志信息,实际上ELK还有很多很丰富的玩法,例如分析聚合、炫酷Dashboard等等。笔者在这里也是初步使用,就介绍到这里啦。
七、Fluentd引入
7.1 关于Fluentd
前面我们采用的是Filebeat收集Docker的日志信息,基于Docker默认的json-file这个logging driver,这里我们改用Fluentd这个开源项目来替换json-file收集容器的日志。
Fluentd是一个开源的数据收集器,专为处理数据流设计,使用JSON作为数据格式。它采用了插件式的架构,具有高可扩展性高可用性,同时还实现了高可靠的信息转发。Fluentd也是云原生基金会 (CNCF) 的成员项目之一,遵循Apache 2 License协议,其github地址为:https://github.com/fluent/fluentd/。Fluentd与Logstash相比,比占用内存更少、社区更活跃,两者的对比可以参考这篇文章《Fluentd vs Logstash》。
因此,整个日志收集与处理流程变为下图,我们用 Filebeat 将 Fluentd 收集到的日志转发给 Elasticsearch。
当然,我们也可以使用Fluentd的插件(fluent-plugin-elasticsearch)直接将日志发送给 Elasticsearch,可以根据自己的需要替换掉Filebeat,从而形成Fluentd => ElasticSearch => Kibana 的架构,也称作EFK。
7.2 运行Fluentd
这里我们通过容器来运行一个Fluentd采集器:
docker run -d -p 24224:24224 -p 24224:24224/udp -v /edc/fluentd/log:/fluentd/log fluent/fluentd
默认Fluentd会使用24224端口,其日志会收集在我们映射的路径下。
此外,我们还需要修改Filebeat的配置文件,将/edc/fluentd/log加入监控目录下:
#=========================== Filebeat inputs =============================
filebeat.inputs:
# Each - is an input. Most options can be set at the input level, so
# you can use different inputs for various configurations.
# Below are the input specific configurations.
- type: log
# Change to true to enable this input configuration.
enabled: true
# Paths that should be crawled and fetched. Glob based paths.
paths:
- /edc/fluentd/log/*.log
添加监控配置之后,需要重新restart一下filebeat:
systemctl restart filebeat
7.3 运行测试容器
为了验证效果,这里我们Run两个容器,并分别制定其log-dirver为fluentd:
docker run -d \
--log-driver=fluentd \
--log-opt fluentd-address=localhost:24224 \
--log-opt tag="test-docker-A" \
busybox sh -c 'while true; do echo "This is a log message from container A"; sleep 10; done;'
docker run -d \
--log-driver=fluentd \
--log-opt fluentd-address=localhost:24224 \
--log-opt tag="test-docker-B" \
busybox sh -c 'while true; do echo "This is a log message from container B"; sleep 10; done;'
这里通过指定容器的log-driver,以及为每个容器设立了tag,方便我们后面验证查看日志。
7.4 验证EFK效果
这时再次进入Kibana中查看日志信息,便可以通过刚刚设置的tag信息筛选到刚刚添加的容器的日志信息了:
八、小结
本文从Docker自带的logs子命令入手,介绍了Docker具有多种logging dirver,然后过度到ELK的基本组成,并介绍了ELK的基本处理流程,以及从0开始搭建了一个ELK环境,演示了基于Filebeat收集容器日志信息的案例。然后,通过引入Fluentd这个开源数据收集器,演示了如何基于EFK的日志收集案例。当然,ELK/EFK有很多的知识点,希望未来能够分享更多的实践总结。
参考资料
CloudMan,《每天5分钟玩转Docker容器技术》
一杯甜酒,《ELK学习总结》
于老三,《快速搭建ELK日志分析系统》
zpei0411,《Logstash beats系列 & Fluentd》