在kubernetes上使用flume TAILDIR收集日志到HDFS上

栏目: 服务器 · 发布时间: 8年前

内容简介:在kubernetes上使用flume TAILDIR收集日志到HDFS上

需求分析

我们的应用以前直接跑在物理机上,应用日志使用flume ng 的exec方式(即tail -F)收集后,写到HDFS上。如下图:

在kubernetes上使用flume TAILDIR收集日志到HDFS上

在flume.conf中定义sources、channels、sinks:

agent1.sources = source1
agent1.channels = ch1
agent1.sinks = sink1

agent1.sources.source1.type = exec
agent1.sources.source1.shell = /bin/bash -c
agent1.sources.source1.command = tail -n +0 -F /log/LOG_FILE_NAME
agent1.sources.source1.channels = ch1

agent1.channels.ch1.type = memory
agent1.channels.ch1.capacity = 10000
agent1.channels.ch1.transactionCapacity = 1000

agent1.sinks.sink1.channel = ch1
agent1.sinks.sink1.type = hdfs
agent1.sinks.sink1.hdfs.path = hdfs://dtyundun/logs/flume/SERVICE_NAME/
agent1.sinks.sink1.hdfs.writeFormat = Text
agent1.sinks.sink1.hdfs.fileType = DataStream
agent1.sinks.sink1.hdfs.rollSize = 134217728
agent1.sinks.sink1.hdfs.rollCount = 0
agent1.sinks.sink1.hdfs.rollInterval = 0
agent1.sinks.sink1.hdfs.batchSize = 1000
#agent1.sinks.sink1.hdfs.maxOpenFiles=1

agent1.sinks.sink1.hdfs.filePrefix = FILENAME
agent1.sinks.sink1.hdfs.fileSuffix=.out
agent1.sinks.sink1.hdfs.threadsPoolSize = 10

hdfs sink的参数说明可以看 官方说明 。需要注意由于HDFS一般会设置blocksize为128MB或者64MB,所以不要在文件很小的时候就roll,否则会产生大量的小文件,非常浪费HDFS的空间。我这里配置了rollSize为128MB,而rollCount(Number of events written to file before it rolled),rollInterval(Number of seconds to wait before rolling current file)都配置为0,即是否roll只看rollSize,这样只有文件到了128MB才会生成新文件。

但是,当应用上了k8s以后呢?

一个思路是走虚拟机的套路,也就是在每个应用容器里跑一个flume agent。但flume agent要求 Java 环境,跟着应用镜像的话,太大了,而且对应用开发者来说也很不爽,我打包个镜像你还要我装个小尾巴。

另一个思路是,应用向kubernetes申请一个hostPath类型的volume,应用只要把日志存到这个volume里去就行了;k8s在宿主机上跑flume agent监控hostPath所在的固定目录,并把文件传到HDFS上去。这对应用开发者来说很友好,不需要care任何日志收集的事情(要存HDFS也好,要ELK也好,全都由k8s集群管理员负责)。看上去这个思路不错,ELK用来做日志解析据说也很方便。只是在宿主机上装应用不太方便,再上一套ELK也有点重。

还有一个思路,给应用容器搭配一个僚机(side car),这个容器里只跑flume ng;将应用的日志volume挂载到flume ng容器里,让flume采集以后写到HDFS上。不侵入应用镜像,但要求应用上k8s的时候,编排文件里带上flume ng。

以上三个方案,第一个不靠谱,第二个最合适,不过ELK略微有点重,我比较喜欢第三个方案。

实现细节

flume ng支持的source类型 很多 ,我们之前使用的是exec类型,但在k8s上不好使。为什么呢?

exec的数据来源其实就是tail -F xxx.log(一行一个event),也就是说,xxx.log这个文件必须存在,否则flume ng认为源不存在,采集失败。当然可以在启动flume之前检测下文件是否存在,但灵活性很差:比如应用写的日志不止一个文件,比如应用可能跑着跑着突然生成一个新日志文件。

回过头来看,在k8s上,flume ng实际上是一个类框架的容器,它不应该对应用产生日志的行为做太多限制,只要是输出到应用指定volume的日志,无条件接受就行了。

flume还支持 Spooling Directory Source 类型,可以指定一个目录,看上去符合我们的要求,但其实这娃的行为是这样的:

  • If a file is written to after being placed into the spooling directory, Flume will print an error to its log file and stop processing.
  • If a file name is reused at a later time, Flume will print an error to its log file and stop processing.

简单来说,Spooling Directory Source类型就是个一锤子买卖,文件放我这个目录我会给你传到HDFS上,但你就别想再动了,原始文件我也会改名加后缀.COMPLETED,不能再次添加同样名字的文件,当然也无法再修改这个文件了。

看到这里,发现了没,其实我们需要的,就是Exec Source + Spooling Directory Source的合体呀!

flume还是贴心的,目前的1.7.0版本推出了一个新的Source类型,叫做 Taildir Source 。只要指定一个目录,flume会把新增的文件、已有文件新append的内容,都tail过去。

是不是好棒棒?

下面是配置:

agent1.sources.source1.type = TAILDIR
agent1.sources.source1.filegroups = f1
agent1.sources.source1.filegroups.f1 = /log/.*

是不是好棒棒?

flume.conf解决了以后,只要再给 flume 打包 Docker 镜像就可以了。值得注意的是,由于flume agent镜像需要写HDFS,所以如果只在Docker里加了flume自己的话,会报ClassNotFound错误。一个做法是把Docker宿主机上的目录挂载进去然后不管3721全部拷贝到/flume/lib/下,但稍嫌粗暴。实际上需要的jar包并不是很多,我列在了下面(我把jar包放到了s3上,docker build的时候去取就好了)。

RUN s3cmd get s3://flume/hadoop-auth-2.7.1.2.4.2.0-258.jar /flume/lib && \
	s3cmd get s3://flume/hadoop-common-2.7.1.2.4.2.0-258.jar /flume/lib && \
	s3cmd get s3://flume/hadoop-hdfs-2.7.1.2.4.2.0-258.jar /flume/lib && \
	s3cmd get s3://flume/commons-configuration-1.6.jar /flume/lib && \
	s3cmd get s3://flume/hadoop-mapreduce-client-core-2.7.1.2.4.2.0-258.jar /flume/lib && \
	s3cmd get s3://flume/htrace-core-3.1.0-incubating.jar /flume/lib && \
	s3cmd get s3://flume/commons-io-2.4.jar /flume/lib

另外就是注意要用hdfs用户去启动flume agent,因为需要写HDFS。

flume agent的Docker镜像ready了以后,剩下的就是编辑应用的编排文件。下面直接给一个centos的例子。

apiVersion: v1
kind: ReplicationController
metadata:
  name: centos7-pod
spec:
  replicas: 1
  template:
    metadata:
      labels:
        unit: centos7-pod
    spec:
      containers:
        - name: flume-agent
          image: docker.datastart.cn/datastart/flume:1.7.0
          imagePullPolicy: Always
          volumeMounts:
          - mountPath: /log/
            name: cache-volume
          - mountPath: /hadoop-conf/
            name: hadoop-conf
          env:
          - name: SERVICE_NAME
            value: centos
        - resources:
            limits:
              cpu: 1
          image: docker.datastart.cn/datastart/centos:7.2.1511
          name: centos7-node1
          command: ["/bin/sh", "-c", "sleep 36000"]
          volumeMounts:
          - mountPath: /var/log/
            name: cache-volume
      volumes:
        - name: hadoop-conf
          configMap:
            name: hadoop-conf
        - name: cache-volume
          emptyDir: {}

应用(centos)和flume 沟通的桥梁,就是那个cache-volume。flume会将centos在/var/log下生成的所有日志都采集上传到HDFS上。注意hadoop-conf这个volume,因为要写HDFS,所以flume需要core-site.xml和hdfs-site.xml,这两个文件在不同集群里是不同的,因此我们在每个集群里都创建了一个名为hadoop-conf的configmap,其内容为/etc/hadoop/conf这个目录下的所有文件。对于flume容器来说,只需要将这个configmap挂载以后拷贝走core-site.xml和hdfs-site.xml两个文件到flume conf目录即可,其他的不需要。

以上就是在kubernetes上使用flume TAILDIR收集日志到HDFS上的方案细节,基本上能够满足我们的需求。

不过有一个不爽的地方是,我没办法把不同的文件的原始名字保存到HDFS上,如果你有办法请留言。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learn Python the Hard Way

Learn Python the Hard Way

Zed A. Shaw / Addison-Wesley Professional / 2013-10-11 / USD 39.99

Master Python and become a programmer-even if you never thought you could! This breakthrough book and CD can help practically anyone get started in programming. It's called "The Hard Way," but it's re......一起来看看 《Learn Python the Hard Way》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换