Fluent Bit
Fluent Bit 是一款开源的日志收集组件,资源开销非常小,小到甚至能在嵌入式系统上运行,支持日志解析&过滤&转发,同时作为云原生基金会下的一个子项目,天然支持容器和 k8s 场景。
基本概念
大部分日志收集组件都将系统大致分为输入、缓冲区、输出三大部分,输入部分负责采集日志,采集了之后放在缓冲区,然后输出部分将其再转发到其他系统。
Fluent Bit 将这三大部分细分成了:输入、解析、过滤、缓冲区、路由、输出六个部分:
- 输入部分负责采集原始日志;
- 解析部分将原始日志结构化,比如提取字段、解转义等操作;
- 过滤部分可以对日志做一些的统一的过滤和修改操作,比如增加一些统一的字段,过滤一些脏日志等等
- 然后日志会被放到缓冲区等待发送
- 路由部分会决策这个包应该发送到哪些输出
- 输出将日志真正转发出去
数据流
输入:INPUT
一个Fluent Bit 可以有多个输入,输入部分是插件化的,提供了许多种常用的插件供我们使用,常见的日志采集方式,如:文件、TCP、HTTP、MQTT、标准输入这些都是支持的,除此之外,Fluent Bit还支持一些带业务含义的插件,如:采集内存、CPU、磁盘、温度等信息;采集进程状态;采集 Linux 内核、systemd 日志;采集 windows 事件等等。
一个文件采集输入的配置例子:
[INPUT]
Name tail
Tag api.log # 打标签,后面处理和转发会根据这个标签来匹配
Path /var/log/api/*.log # 采集/var/log/api目录下所有 log 后缀的文件
解析:PARSER
解析器主要用于将原始日志进行结构化,支持 JSON、LTSV、logfmt 等格式的解析,对于非规则的日志也可以通过正则解析器来提取。
一个通过正则匹配提取 apache 日志的解析器例子:
[PARSER]
Name apache
Format regex
Regex ^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$
Time_Key time
Time_Format %d/%b/%Y:%H:%M:%S %z
Types code:integer size:integer
原始 HTTP 日志:
192.168.2.20 - - [29/Jul/2015:10:27:10 -0300] "GET /cgi-bin/try/ HTTP/1.0" 200 3395
解析之后:
{
"host": "192.168.2.20",
"user": "-",
"method": "GET",
"path": "/cgi-bin/try/",
"code": "200",
"size": "3395",
"referer": "",
"agent": ""
}
过滤:FILTER
Filter 部分允许我们在发送前对日志进行修改,是很有用的一个模块,filter 也是插件化的,同时一个实例内支持使用多个 filter 插件,常用的 filter 插件包括:
Grep
正则过滤日志GeoIP2 Filter
查询 IP 库给 IP 字段附加地理信息Lua
可以直接嵌入 lua 脚本对数据进行修改Modify
重命名、添加、删除字段
配置例子:过滤所有 debug 级别的日志:
[FILTER]
name grep
match *
exclude ^\[debug\] .+ # 正则
缓冲:BUFFER
日志经过 filter 处理完之后就会在缓存区先放着,可以避免突然的大流量导致输出模块处理不过来从而导致日志丢失,也可以让输出模块攒一批日志然后批量发送提升性能。
和大部分的日志收集组件一样,Fluent Bit 也支持内存和磁盘两种 buffer,内存速度会快一些,但是稳定性不如磁盘,断电后内存 buffer 里的数据就丢了,而磁盘则正好相反,不会丢日志但是速度慢。
路由:ROUTING
路由部分会决定日志要发往哪些输出,不过在配置文件并没有单独的实体存在,主要依赖标签机制来实现,在日志通过输入模块流入时可以给日志打上标签,然后 router 会读取输出插件的 Match
字段进行正则匹配,来判断要不要发往这个输出。
[INPUT]
Name tail
Tag api.log # 打标签,后面处理和转发会根据这个标签来匹配
Path /var/log/api/*.log # 采集/var/log/api目录下所有 log 后缀的文件
[INPUT]
Name tail
Tag api.log # 打标签,后面处理和转发会根据这个标签来匹配
Path /var/log/api/*.log # 采集/var/log/api目录下所有 log 后缀的文件
[OUTPUT]
输出:OUTPUT
输出部分也是插件化的,我们可以通过多种方式将日志发送到它的目的地。
常用的输出插件如下:
- S3对象存储
- ES
- 文件
- Forward:将日志用 forward 协议发出去,常用于边缘 fluent bit + 中心 fluentd 架构
- HTTP
- InfluxDB
- Kafka
- Loki
- PostgresQL
- TCP
- Websocket
例子:将日志通过HTTP的方式输出到目标接口:
[OUTPUT]
Name http
Match * # 匹配所有日志
Host log.example.com
Port 80
URI /something
Format json
值得一提的是,output 插件还支持用 Go 语言开发,只需要实现指定的几个方法,编译出一个动态链接库即可,详情参考:https://docs.fluentbit.io/manual/development/golang-output-plugins。
Fluent Bit 和 Fluentd
fluentd
和 fluent bit
师出同门,先有的 fluentd
,后来 Treasure Data 基于 fluentd
的架构思想 又设计开源了更轻量的 fluent bit
,功能虽然没有前者多,但是基本够用,胜在轻量,fluent bit
之于 fluentd
类似 filebeat
之于 logstash
。
很常见的一种应用场景是在边缘部署更轻量 fluent-bit
然后汇总到中心的 fluentd
处理:
详细对比:
Fluentd | Fluent Bit | |
---|---|---|
使用范围 | 容器 / 服务器 | 嵌入式 Linux / 容器 / 服务器 |
语言 | C & Ruby | C |
内存 | ~40MB | ~650KB |
性能 | 高 | 高 |
日志聚合 | YES | NO |
依赖 | 依赖一些 ruby gem | 零依赖 |
插件 | 1000+ | 70+ |
Github Star | 10.2k | 2.7k |
HELLO WORLD
安装
CentOS
先配置YUM源:
echo '[td-agent-bit]
name = TD Agent Bit
baseurl = https://packages.fluentbit.io/centos/7/$basearch/
gpgcheck=1
gpgkey=https://packages.fluentbit.io/fluentbit.key
enabled=1' > /etc/yum.repos.d/td-agent-bit.repo
fluent-bit 是以 td-agent-bit
的名称分发的,我们直接安装即可:yum install td-agent-bit
可以直接手动启动二进程程序,这样更直观:
/opt/td-agent-bit/bin/td-agent-bit -i mem -o stdout -f 1
或者通过 systemd 托管启动:
sudo service td-agent-bit start
Docker【推荐】
用 docker 安装通常来说会是一种更便捷及标准化的做法,我们只需要一行命令就能直接体验 fluent bit:
# 输入:CPU信息采集 输出:标准输出 FLUSH: 1秒一次
docker run -it fluent/fluent-bit:1.7 /fluent-bit/bin/fluent-bit -i cpu -o stdout -f 1
实践:采集Docker日志到ES
一种很常见的场景,我们的业务代码中打了日志,然后希望收集到 ES 中通过 Kibana 查看日志,这个时候我们就可以使用 Fluent Bit 来实现日志的收集与转发。
搭建 ES + Kibana
业务上有现成的 ES 肯定最方便,如果是想从零开始体验的话,我们可以直接拉起一套容器环境:
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -d elasticsearch:7.12.0
docker run --name kibana --link=elasticsearch:test -p 5601:5601 -d kibana:7.12.0
然后创建一个 ES 索引用来放日志:
curl -X PUT 'http://127.0.0.1:9200/api-log'
配置容器日志
首先,在业务代码中,我们需要将日志打成 JSON 格式到标准输出中供 docker 收集,这里可以使用 logrus 框架。
Docker 默认的日志驱动是 json-file
,会将日志写入到 /var/lib/docker/containers/<container id>/<container id>-json.log
中,理论上我们可以配置日志采集程序直接监听这个文件即可,不过 docker 1.8 后有了更高效的选择,docker 原生支持了 **fluentd 和fluent bit**,我们只需要配置一下容器的驱动即可,然后 docker 就会将日志通过 fluent bit 能够识别的FORWARD协议转发到 tcp://localhost:24224
。
docker run --log-driver=fluentd api-system:latest
配置 Fluent Bit
这一步是最为关键的,我们需要合理地配置 fluent bit,来让它可以收集 docker 日志,然后转发到 ES 的接口中去。
另外,docker 过来的日志本来就是 json 格式,而我们业务上的 json 日志则会被转义放入 log 字段中,所以我们需要将业务日志反转义然后提取到最上一级的 json 结构下,这样才能直观的在 kibana 中看到我们的字段。
配置文件如下:
/etc/fluent-bit/fluent-bit.conf
[SERVICE]
Parsers_File parser.conf # 解析文件位置
Flush 5 # 5秒写入一次ES
Daemon Off
Log_Level debug
[INPUT]
Name forward # forward 协议
Listen 0.0.0.0
Port 24224 # 默认端口,如果需要修改的话,Docker日志驱动参数也要同步
[FILTER]
Name parser
Key_Name log
Parser docker # 指定使用 docker 解析器来处理日志,定义于 parser.conf 中
Match *
[FILTER]
Name nest
Match *
Operation lift
Nested_under log # 将 log 下的所有 json 字段上移一级
[OUTPUT]
Name es # 转发日志到指定地址的 es 中
Match *
Host 127.0.0.1
Port 9200
Index api-log # es 索引,需要提前创建好
/etc/fluent-bit/parser.conf
[PARSER]
Name docker
Format json
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
Decode_Field_As escaped log # 解转义
Decode_Field_As json log # json解析,而不是视为纯字符串
启动 Fluent Bit
这里我们直接用容器的方式启动一个 Fluent Bit 进程,同时直接和宿主机共用网络空间减少网络包跨越网络空间带来的损耗,另外我们需要将我们上面的配置文件地址映射到容器内的默认配置读取目录,来使我们的配置生效:
docker run --name fluent-bit --network host -d -v /etc/fluent-bit/:/fluent-bit/etc fluent/fluent-bit:1.7
然后理论上我们就能方便地在 kibana 中查看我们的日志了。