Fluentd 是另一个 Ruby 语言编写的日志收集系统。和 Logstash 不同的是,Fluentd 是基于 MRI 实现的,并不是利用多线程,而是利用事件驱动。单个日志处理的流程如下,当然也可以多个日志流一同处理。
这里穿插一下Docker 的日志格式,默认的是json-file,分为以下三个字段,当然也有别的driver,但是会导致docker logs不能使用,也就没有尝试。
"log": "10.244.0.1 - - [21/Dec/2018:13:06:52 +0000] \"GET / HTTP/1.1\" 200,"
"stream": "stdout",
"time": "2018-12-21T13:06:52.182042579Z"
}
配置
fluentd配置主要由以下5部分组成
- source:确定输入源
- match: 确定输出目的地
- filter:确定 event 处理流
- system:设置系统范围的配置
- label:将内部路由的输出和过滤器分组
- @include:包括其它文件
下面以k8s项目日志收集配置为实例,介绍一下相关配置。
数据源
<source>
@id fluentd-containers.log
@type tail
path /var/log/containers/demo.log
pos_file /var/log/es-containers.log.pos
tag raw.kubernetes.*
read_from_head true
<parse>
@type multi_format
<pattern>
format json
time_key time
time_format %Y-%m-%dT%H:%M:%S.%NZ
</pattern>
<pattern>
format /^(?<time>.+) (?<stream>stdout|stderr) [^ ]* (?<log>.*)$/
time_format %Y-%m-%dT%H:%M:%S.%N%:z
</pattern>
</parse>
</source>
下一步解析json
<match raw.kubernetes.**>
@id raw.kubernetes
@type detect_exceptions
remove_tag_prefix raw
message log
stream stream
multiline_flush_interval 5
max_bytes 500000
max_lines 1000
</match>
# 加上kubernetes的metadata信息
<filter kubernetes.**>
@type kubernetes_metadata
verify_ssl false
</filter>
# 再次使用match 配置输出方向
<match **>
@id elasticsearch
@type elasticsearch
@log_level info
type_name fluentd
include_tag_key true
host 118.178.178.140
port 9200
logstash_format true
<buffer>
@type file
path /var/log/fluentd-buffers/kubernetes.system.buffer
flush_mode interval
retry_type exponential_backoff
flush_thread_count 2
flush_interval 5s
retry_forever
retry_max_interval 30
chunk_limit_size 2M
queue_limit_length 8
overflow_action block
</buffer>
</match>
fluent解析之后的格式会带上pod的相关信息,之后发到ES,下面是ES中对应的一条数据:
{
"_index": "logstash-2018.12.21",
"_type": "fluentd",
"_id": "WnlC0WcBd0poFKe5TXTB",
"_version": 1,
"_score": 1,
"_source": {
"log": "10.244.0.1 - - [21/Dec/2018:11:35:20 +0000] GET / HTTP/1.1",
"stream": "stdout",
"docker": {
"container_id": "873ddbe58783f2e733e19a3b53e453"
},
"kubernetes": {
"container_name": "nginx",
"namespace_name": "default",
"pod_name": "nginx-6665cb456b-hslrv",
"pod_id": "3027acd2-0514-11e9-891e-00163e0d0afe",
"labels": {
"pod-template-hash": "6665cb456b",
"run": "nginx"
},
"host": "prod-consul-2",
"master_url": "https://10.96.0.1:443/api",
"namespace_id": "0753cc1f-0513-11e9-891e-00163e0d0afe"
},
"@timestamp": "2018-12-21T11:35:20.417931350+00:00",
"tag": "kubernetes.var.log.containers.nginx-6665cb456b-hb19a3b53e453.log"
}
}
其他
fluent的缺点?
- ruby也有全局锁的东西(GIL),所以在多核机器上只能利用一个CPU,所以规模大了之后可能会成为瓶颈,另外可以参考Ref#1。
- 当你修改一个规则的时候,需要重新部署,而且不能区分应用,这种方式其实并不是很适合k8s,banzaicloud开源了一个logoperator,定义了新的CRD,可以基于label的方式来采集日志,还是可以的。https://github.com/banzaicloud/logging-operator
- 采集容器内非标准输出的日志,阿里云有一个log-pilot可以根据ENV的方式来采集绝对路径下的日志,但是有一些问题,不过可以参考下。https://github.com/AliyunContainerService/log-pilot/
不断产生日志的脚本,或许有更好的方式?
while true; do echo '{"log":"2019-01-29T10:35:27,234+08:00 [main] INFO ","stream":"stderr","time":"2019-01-12T03:36:43.390762996Z"}' >> /var/log/containers/demo.log && sleep 1;done
Ref
Fluentd语法速记
https://lintingbin2009.github.io/2018/05/01/fluentd%E8%AF%AD%E6%B3%95%E9%80%9F%E8%AE%B0/