原文来源: Rancher Labs
应用日志的收集、分析和监控是日常运维工作重要的部分,妥善地处理应用日志收集往往是应用容器化重要的一个课题。
Docker处理日志的方法是通过docker engine捕捉每一个容器进程的STDOUT和STDERR,通过为contrainer制定不同log driver 来实现容器日志的收集,缺省json-file log driver是将容器的STDOUT/STDERR 输出保存在磁盘上,然后用户就能使用docker logs <container>来进行查询。
在部署一个传统的应用的时候,应用程序记录日志的方式通常记录到文件里, 一般(但不一定)会记录到/var/log目录下。应用容器化后,不同于以往将所有日志放在主机系统的统一位置,日志分散在很多不同容器的相互隔离的环境中。
如何收集应用写在容器内日志记录,有以下挑战:
1) 资源消耗
如果在每个容器运行一个日志收集进程, 比如logstatsh/fluentd 这类的日志工具,在主机容器密度高的时候,logstatsh/fluentd这类日志采集工具会消耗大量的系统资源。上面这种方法是最简单直观的,也是最消耗资源的。
2) 应用侵入
一些传统应用,特别是legacy 系统,写日志机制往往是没法配置和更改的,包括应用日志的格式,存放地址等等。日志采集机制,要尽量避免要求修改应用。
3) 日志来源识别
采用统一应用日志收集方案,日志分散在很多不同容器的相互隔离的环境中,需要解决日志的来源识别问题。
日志来源识别的功能借助了rancher平台为container_name的命名的规则特性,可以做到即使一个容器在运行过程中被调度到另外一台主机,也可以识别日志来源。
下面是我们设计的一个低资源资源消耗、无应用侵入、可以清楚识别日志来源的统一日志收集方案,该方案已经在睿云智合的客户有成功实施案例。
在该方案中,会在每个host 部署一个wise2c-logger,wise2C会listen docker engine的event,当有新容器创建和销毁时,会去判断是否有和日志相关的local volume 被创建或者销毁了,根据lables,wise2c-logger 会动态配置logstatsh的input、filter 和output,实现应用日志的收集和分发。
1) 应用如何配置
应用容器化时候,需要在为应用容器挂载一个专门写有日志的volume,为了区别该volume 和容器其它数据volume,我们把该volume 定义在容器中,通过volume_from 指令share 给应用容器,下面是一个例子:demo应用的docker-compose file
web-data 容器使用一个local volume,mount到/var/log目录(也可以是其它目录),在web-data中定义了几个标签, io.wise2c.logtype说明这个容器中包含了日志目录,标签里面的值elasticsearch、kafka可以用于指明log的output或者过滤条件等。
那么我们现在来看下wiselogger大致的工作流程:
监听新的日志容器->获取日志容器的type和本地目录->生成新的logstash配置:
1)wise2c-looger 侦听docker events 事件, 检查是否有一个日志容器创建或者被销毁;
2)当日志容器被创建后(通过container label 判断), inspect 容器的volume 在主机的path;
3)重新配置wise2c-logger 内置的logstatsh 的配置文件,设置新的input, filter 和output 规则。
这里是把wise2c-logger在rancher平台上做成catalog需要的docker-compose.yml的截图,大家可以配合上面的流程描述一起看一下。
目前我们还在对Wise2C-logger 作进一步的优化:
1)收集容器的STDOUT/STDERR日志
特别是对default 使用json-file driver的容器,通过扫描容器主机的json-file 目录,实现容器STDIN/STDERR日志的收集。
2)更多的内置日志收集方案
目前内置缺省使用logstatsh 作日志的收集,和过滤和一些简单的转码逻辑。未来wise2C-logger 可以支持一些更轻量级的日志收集方案,比如fluentd、filebeat等。
Q:有没有做过性能测试?我这边模块的日志吞吐量比较大。比如在多少量级的日志输出量基础上,主要为logger模块预留多少系统资源,保证其正常稳定工作?
A:没有做过很强的压力,但是我们现在正常使用倒没碰上过性能上的瓶颈。我们现在没有对logger做资源限制,但是能占用300~400M内存,因为有logstash的原因。
Q:「生成日志容器」是指每个应用容器要对应一个日志容器?这样资源消耗不会更大吗?k8s那种日志采集性能消耗会比这样每个应用容器对应一个日志容器高么?
A:是指每个应用容器对应一个日志容器。虽然每个应用有一个日志容器,但是,日志容器是start once的,不会占用运行时资源。
Q:你说的start once是什么意思?我说占资源是大量日志来的时候,那么多日志容器要消耗大量io的吧,CPU使用率会上升,不会影响应用容器使用CPU么?
A:不会,日志容器只生成一下,不会持续运行。
Q:怎么去监听local volume?
A:可以监听文件目录,也可以定时请求docker daemon。
Q:直接用syslog driver,能做到对应用无侵入么?
A:启动容器的时候 注明使用Syslog driver的参数即可,这样几乎没有额外资源占用。
Q:这种方案是不是要保证应用容器日志要输出到/var/log下啊?
A:不是,可以随意定义,logstah可以抓syslog。
Q:syslog driver能收集容器内的日志文件么?容器内不同流向的日志能区分么?
A:容器内应用的本地日志syslog可以收集,分流同样可以完成,但是容器内的本地日志这个我个人觉得跟容器环境下的应用无本地化、无状态化相悖吧。
Q:最后你说到,重新配置logstash中配置文件,看上去感觉你又是通过wiselog这个容器去采集所有日志的?只不过是动态配置logstash里面参数。
A:是的,现在收集工作是logstash来完成的,单纯的文件收集,可选的方案还挺多的,也没有必要再造轮子了。
Q:那这个方案其实有个疑问,为什么不学k8s那种,直接固定那目录,通过正则表达式去采集日志文件,而要动态这么做?有什么好处吗?目前我感觉这两套方案几乎一样。
A:为了减少对应用的侵入。因为很多用户的现有系统不能再修改了,这样做也是为了减少用户现有程序的修改,为了最重要的“兼容现有”。
Q:除了kibana还有没别的可视化方案?
A:针对es来说,还没有别的更好的方案。
Q:如果是挂载log目录,logstash就可以去宿主机收集了,还需要别的插件做什么?
A:通过容器可以识别出来这个应用的业务上的逻辑,可以拿到service名称。
Q:有的应用输出的log名都是一样的,不会有冲突吗,比如我启动2个容器在一个宿主机上,都往xx.log里写入会有问题。
A:不会,给每一个应用容器配一个日志卷容器就可以解决这个问题。这个问题也是我们出方案时一个棘手的问题。所以这个方案的一个好处就是,每一个应用的都可以随意设置日志目录,不用考虑和别的应用冲突,也不会和同宿主机同一应用冲突。
Q:上次听别人说全部把日志扔到标准输出里,不知道靠谱不?
A:有人报过这种处理方式,日志量大时,docker daemon会崩溃。