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

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

内容简介:在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上,如果你有办法请留言。


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

查看所有标签

猜你喜欢:

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

We Are the Nerds

We Are the Nerds

Christine Lagorio-Chafkin / Hachette Books / 2018-10-2 / USD 18.30

Reddit hails itself as "the front page of the Internet." It's the third most-visited website in the United States--and yet, millions of Americans have no idea what it is. We Are the Nerds is an eng......一起来看看 《We Are the Nerds》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具