Docker日志收集最佳实践

传统日志处理linux

说到日志,咱们之前处理日志的方式以下:json

· 日志写到本机磁盘上后端

· 一般仅用于排查线上问题,不多用于数据分析tomcat

·须要时登陆到机器上,用grep、awk等工具分析app

 

那么,这种方式有什么缺点呢?框架

 

第一,   它的效率很是低,由于每一次要排查问题的时候都要登到机器上去,当有几十台或者是上百台机器的时候,每一台机器去登录这是一个没办法接受的事情,可能一台机器浪费两分钟,整个几小时就过去了。elasticsearch

 

第二,   若是要进行一些比较复杂的分析,像grep、awk两个简单的命令不可以知足需求时,就须要运行一些比较复杂的程序进行分析。分布式

 

第三,   日志自己它的价值不光在于排查一些系统问题上面,可能在一些数据的分析上,可能利用日志来作一些用户的决策,这也是它的价值,若是不能把它利用起来,价值就不能充分的发挥出来。工具

 

因此,如今不少公司会采用集中式日志收集的日志处理方式,咱们会把日志分布式收集,集中来存储,咱们会在全部机器上面把日志都收集起到一个中心,在中内心面作一个日志全文索引搜索,能够经过一个界面去查询,同时这个日志系统后端能够对接一些更复杂的数据处理系统,能够对接监控、报警系统,对接数据挖掘数据分析系统,充分发挥日志的价值。性能

 

Docker的日志处理

 

使用过Docker的人尤为是使用过容器编排系统,好比说咱们的容器服务,可能已经注意到这样的一些特色:

 

容器编排跟传统的布置方式是不同的,在容器编排里面,资源分配应用跑到哪台机器上面的决策是由容器层来作的,因此你事先不知道你的容器应用会跑到哪台机器上面;还有自动伸缩,根据负载自动增长或者减小容器数量;另外,在整个运行过程当中,系统发生一些状况时,好比说你的容器宕掉了,容器服务会自动把容器应用迁到其余的机器上去,整个过程很是动态,若是像传统方式去配制日志的收集工具,从一台机器上面收集某一个应用,在这个动态下面,很难用原来的方式去配置。

 

基于这些特色,在Docker的日志里面, 咱们只可以采用中心化的日志收集方案,你已经没办法再像原来登到一台机器上面去看它的日志是什么,由于你不知道它其实在哪一个机器上面。

 

stdout和文件日志

 

Docker的日志咱们能够把它分红两类,一类是stdout标准输出,另一类是文件日志。stdout是写在标准输出里面的日志,好比你在程序里面,经过print或者echo来输出的时候,这种输出标准在linux上面实际上是往一个ID为零的文件表述书里面去写;另外的就是文件日志,文件日志就是写在磁盘上的日志,通常来讲咱们会在传统的应用里面会用得多一些。

 

stdout

 

在Docker的场景里面,目前比较推崇这种标准输出的日志,标准输出日志具体过程如图。标准输出日志的原理在于,当在启动进程的时候,进程之间有一个父子关系,父进程能够拿到子进程的标准输出。拿到子进程标准输出的后,父进程能够对标准输出作全部但愿的处理。

例如,咱们经过exec.Command启动了一个命令,带一些参数,而后就能够经过标准的pipeline拿到标准输出,后面就能够拿到程序运行过程当中产生标准输出。 Docker也是用这个原理来拿的,全部的容器经过Docker Daemon启动,实际上属于Docker的一个子进程, 它能够拿到你的容器里面进程的标准输出,而后拿到标准输出以后,会经过它自身的一个叫作LogDriver的模块来处理,LogDriver就是Docker用来处理容器标准输出的一个模块。 Docker支持不少种不一样的处理方式,好比你的标准输出以后,在某一种状况下会把它写到一个日志里面,Docker默认的JSON File日志,除此以外,Docker还能够把它发送到syslog里面,或者是发送到journald里面去,或者是gelf的一个系统。

 

怎么配置log driver呢?

 

用Docker来启动容器的话,你有两种方式来配置LogDriver:

 

第一种方式是在Daemon上配置,对全部的容器生效。你配置以后,全部的容器启动,若是没有额外的其余配制,默认状况下就会把全部容器标准输出所有都发送给Syslog服务,这样就能够在这个Syslog服务上面收集这台机器上的全部容器的标准输出;

第二种方式是在容器上配置,只对当前容器生效。若是你但愿这个配置只对一个容器生效,不但愿全部容器都受到影响,你能够在容器上面配置。启动一个容器,单独配置它自身使用的logdriver。

其实Docker以前已经支持了不少的logdriver,图中列表是直接从Docker的官方文档上面拿到的。

 

文件日志

 

对于stdout的这种日志,在Docker里面如今处理起来仍是比较方便的,若是没有现成Logdriver的也能够本身实现一个,可是对于文件日志处理起来就没有这么简单了。若是在一个容器里面写了日志,文件位于容器内部,从宿主机上没法访问,的确你是能够根据Docker用的devicemapper、overlayfs访问到它里面的一个文件,可是这种方式跟Docker的实现机制是有关系的,未来它若是改变,你的方案就失效了;另外,容器运行很是动态,日志收集程序难以配置,若是有一个日志收集的程序,在机器上面配置要收集哪一个文件,它的格式是什么样子的、发送到哪儿?由于一台机器上面容器是一直在动态变的,它随时可能在增长一个或者删除一个,事先你并不知道这台机器上会跑了多少个容器,他们的配置是怎么样子的,他们的日志是写在哪儿的,因此没办法预先在一台机器上面把这个采集程序配好,这就是文件收集比较难的两个地方。

 

最简单的一个方案,给每一个容器弄一个日志采集进程,这个进程跑到容器里面,就能够解决以上的两个问题,第一由于它跑到容器里面,就能够访问到容器里面全部的文件,包括日志文件;第二它跟容器在一块儿,当容器启动的时候,收集日志的进程也启动了,当容器销毁的时候,进程也就被销毁掉了。

 

这个方案很是简单,可是其实会有不少的缺点:

 

第一,   由于每一个容器都有一个日志的进程,意味着你的机器上面有100个容器,就须要启动一百个日志设备的程序,资源的浪费很是厉害。

 

第二,   在作镜像的时候,须要把容器里面日志采集程序作到镜像里面去,对你的镜像实际上是有入侵的,为了日志采集,不得不把本身的日志程序再作个新镜像,而后把东西放进去,因此对你的镜像过程是有入侵性的。

 

第三,   当一个容器里面好多个进程的时候,对于容器的资源管理,会干扰你对容器的资源使用的判断,包括对于在作资源分配和监控的时候,都会有一些这样的干扰。

 

fluentd-pilot

 

在容器服务上面,咱们新开发了一个工具,称之为fluentd-pilot。

 

fluentd-pilot是一个开源的日志采集工具,适合直接在一台机器上面跑单个进程模式。fluentd-pilot有这样的一些特色:

 

· 一个单独fluentd进程,收集机器上全部容器的日志。不须要为每一个容器启动一个fluentd进程;

 

· 声明式配置。使用label声明要收集的日志文件的路径;

 

· 支持文件和stdout;

 

· 支持多种后端存储:elasticsearch, 阿里云日志服务, graylog2…

 

具体是怎么作呢?如图,这是一个简单的结构,在Docker宿主机上面部署一个fluentd-pilot容器,而后在容器里面启动的时候,咱们要声明容器的日志信息,fluentd-pilot会自动感知全部容器的配置。每次启动容器或者删除容器的时候,它可以看获得,当看到容器有新容器产生以后,它就会自动给新容器按照你的配置生成对应的配置文件,而后去采集,最后采集回来的日志一样也会根据配置发送到后端存储里面去,这里面后端主要指的elasticsearch或者是SLS这样的系统,接下来你能够在这个系统上面用一些工具来查询等等。整个这一块在Docker宿主机上面,外面的就是外部系统,由这两个部分来组成。

 

咱们既然要用fluentd-pilot,就得先把它启动起来。还要有一个日志系统,日志要集中收集,必然要有一个中间服务去收集和存储,因此要先把这种东西准备好,而后咱们在每个收集日志的机器上面部署一个fluentd-pilot,用这个命令来部署,其实如今它是一个标准的Docker镜像,内部支持一些后端存储,能够经过环境变量来指定日志放到哪儿去,这样的配置方式会把全部的收集到的日志所有都发送到elasticsearch里面去,固然两个管挂载是须要的,由于它链接Docker,要感知到Docker里面全部容器的变化,它要经过这种方式来访问宿主机的一些信息。

配置好以后启动应用,咱们看应用上面要收集的日志,我该在上面作什么样的声明?关键的配置有两个,一是label catalina,声明的时候要收集容器的日志,全部的名字均可以;二是声明access,这也是个名字,均可以用你喜欢的名字。这样一个路径的地址,当你经过这样的配置来去启动fluentd-pilot容器以后,它就可以感受到这样一个容器的启动事件,它会去看容器的配置是什么,要收集这个目录下面的文件日志,而后告诉fluentd-pilot去中心配置而且去采集,这里有一个-V,实际上跟Logs是一致的,在容器外面实际上没有一种通用的方式可以获取到容器里面的文件,全部咱们主动把目录从宿主机上挂载进来,这样就能够在宿主机上看到目录下面全部的东西。

 

除了最简单的场景以外,你的日志可能会有一些更复杂的特性,好比你的日志格式是什么样子,你可能但愿在收集以后加一些内容,便于搜索,当你在真用的时候,它不光是一个很是简单的容器,它可能属于某一个业务或者属于某一个应用,那么,你但愿在收集的时候可以有一些关联信息,因此你能够指定日志格式是什么样子,而后能够在日志里添加tag,这些tag至关于一些关键信息,能够附加任何须要的关联信息,这样未来在搜索的时候能够更方便的把这些日志聚在一块;并且,它能够指定不少的后端,fluetnd-pilot支持多种后端,使用环境变量FLUENTD_OUTPUT指定后端类型。

 

fluent-pilot已经开源,若是功能不知足需求,能够本身定制,本身修改代码实现须要的功能。它的结构比较简单,有这样几个模块:

 

最上层是容器事件管理,这一块跟Docker进行交互,它会感知Docker的建立容器,而后作出相应的生成配置或者清理配置上的事情;解析容器label跟容器配置,当你建立一个新容器以后,就会用这个模块拿到新容器的配置,而后生成对应的配置文件;FluentdController主要是用来维护对应进程,包括控制何时加载新配置,而后检测一些健康状态等等;再下面就是Fluentd的一些插件,若是你须要增长一些日志的后端,就能够本身实现一些插件,放在这个里面,而后再生成跟对应的插件相关的一些配置。   

 

fleuntd-pilot+阿里云容器服务

 

以上是fleuntd-pilot自己的一些能力,如今你能够在任何地方使用它,可是在容器服务上面咱们针对它作了一些更加灵活方便、更酷的一些事情,容器服务为fluentd-pilot进行优化:

第一,   自动识别aliyun.logs标签,并建立Volume;

第二,   从新部署,新容器自动复用已有的Volume,避免日志丢失。

 

原生支持SLS

 

容器服务有一个很棒的特色,它会跟其余的云产品作一些很是方便的集成,这对于用户来讲,在使用容器服务的时候,云产品可以更加方便的使用。好比说在日志方面,阿里云容器服务专为SLS作了优化,让用户更简单的在容器服务上使用SLS。SLS是阿里云提供的日志服务,性能强悍,使用方便,还能够对接ODPS等数据系统;支撑1W台物理机,一天12TB日志数据,IOPS>= 2W,采集平均<1 S;单机:在1个CPU core状况下,能够实时采集15-18MB/S  日志量;若是配置中增长能够用线程数目,可水平扩展;是阿里云环境下的最佳日志方案。

 

优化优势具体体如今:自动建立sls的project, logstore;同时支持stdout和文件日志,使用一样的方式配置。

 

容器服务日志方案

 

好比在容器服务上面布一个tomcat,可能会写如图的一个标准Docker的模板。  

 

当你经过部署以后,就能够在日志服务上面看到会生成两个东西,都是建立好的,加一些前缀来区分,不用管一些配置,你惟一要作的事是什么呢?点日志索引查询,而后到日志搜索界面,刚才启动的时候一些日志,能够看到从哪过来的,这条日志的内容是什么,这些信息都已经很快的出现了,包括须要检索能够选中一个时间段,输入关健词去作一些搜索,自动在日志服务上建立并配置logstore。

 

咱们在容器服务上面作到了对于文件日志的收集,而且方式也都很是简单,都是你能够设立一个label,经过label方式能够收集到全部的日志。

 

日志存储方案

 

最后简单的介绍几种日志存储方案的对比,图为如今比较流行的日志方案Elasticsearch,它自己并不提供界面,ELK中的E,基于Lucene,主要用于日志索引、存储和分析;一般配合Kibana展现日志,免费,支持集群模式,能够搭一个Docker用的生产环境可用的系统。

接下来是graylog2,目前不算很流行,可是也是功能很强大的系统,它不像Elasticsearch还须要配合其它去使用,它自身拥有日志存储、索引以及展现全部的功能,都在一个系统里面实现,它能够设置一些报警规则,当日志里面出现一些关键字的时候自动报警,这个功能仍是很是有用的,免费、支持集群模式,能够在生产环境里面搭一个Docker用的生产系统。

阿里云的日志服务SLS特色以下:

· 阿里云托管,不须要本身维护

· 支持多用户和权限管理

· 能够对接ODPS等系统

· 支撑1W台物理机,一天12TB日志数据,IOPS>= 2W,采集平均<1 S;单机:在1个CPU core状况下,能够实时采集15-18MB/S  日志量;若是配置中增长能够用线程数目,可水平扩展

 

用正确的方式写日志

 

那么,咱们怎么样去收集日志、存储日志,用什么样的系统,日志的源头和写日志咱们又该怎么来作,有这样几个建议:

 

1.  选择合适的日志框架,不要直接print;

2.  为每一条日志选择正确的level,该debug的不要用info;

3.  附加更多的上下文信息;

4.  使用json、csv等日志格式,方便工具解析;

5.  尽可能不要使用多行日志(Java Exception Stack)。

 

       (--转载 :云栖社区--)

相关文章
相关标签/搜索