NOTE:这是对先前发布的原创文章《在Kubernetes上使用Fluent Bit控制日志(第四部分)》的一次特殊更新。
此次更新所需的议题在上周末出现,当时我发现收购了VMWare(Bitnami目录的托管方)的Broadcom对我们所有人做了一件不太好的事情。
在该议题中,他们宣布该目录将于2025年8月迁移至一个“遗留目录”,取而代之的是一个“安全”目录,并且将不再更新。
这意味着当前的“日志控制简易安装”项目、研讨会《在Kubernetes上使用Fluent Bit控制日志》以及原始文章都必须更新。我花了整个周末和大部分一周的时间,将这三个工件全部更新,用一个新的应用程序工作负载替换了Ghost CMS的使用。
让我们看看这些变化对原始文章意味着什么,并为您提供一份关于使用Fluent Bit掌控Kubernetes集群日志的新指南。
与本系列所有文章一样,在分享如何在Kubernetes集群上使用Fluent Bit遥测流水线来控制所有生成的日志之前,我先对Fluent Bit做一个简短介绍。
什么是Fluent Bit?
在深入探讨Fluent Bit之前,让我们退一步审视一下这个项目在Fluent组织内的定位。如果我们查看Github上的Fluent组织,会发现那里托管着Fluentd和Fluent Bit项目。背后的故事是,该项目始于一个日志解析项目Fluentd,于2026年加入CNCF,并在2019年达到毕业状态。
一旦发现世界正朝着云原生Kubernetes环境发展,而原有解决方案并非为Kubernetes解决方案所要求的灵活和轻量级需求而设计。Fluent Bit应运而生,旨在满足云原生Kubernetes环境对低资源使用、高吞吐量和高可扩展性日志管理解决方案的需求。该项目于2017年在Fluent组织内作为子项目启动,剩下的就是上周v4发布后长达10年的历史了!
Fluent Bit已远不止是一个灵活、轻量的日志流水线解决方案,现在能够处理指标和追踪,并且正成为那些希望在数据收集源头就能掌控其遥测数据的人们的首选遥测流水线收集工具。
让我们开始使用Fluent Bit,看看它能做什么!
为什么要在Kubernetes集群上控制日志?
当您涉足云原生世界时,这意味着您要在Kubernetes上部署容器。随着您的应用程序和微服务在这个动态的基础设施环境中交互,复杂性急剧增加。
部署可以自动扩缩,Pod会根据需求启动和关闭,而这一切的底层是各种Kubernetes控制组件。所有这些都会生成遥测数据,而Fluent Bit是在Kubernetes集群上掌控它们的绝佳方式。它提供了一种在运行过程中通过中央遥测流水线收集一切数据的方法,同时提供了解析、过滤和路由所有遥测数据的能力。
对于开发人员,本文将演示在开发Kubernetes集群上使用Fluent Bit作为日志收集的单一接入点,并部署一个工作负载。最后,本文中的所有示例都是在OSX上完成的,并假设读者能够将此处展示的操作转换到自己的本地机器上。
从何处开始
为确保您准备好开始控制Kubernetes集群日志,本文的其余部分假设您已阅读过之前的文章并完成了其中概述的步骤。这确保了:
- 您正在运行一个两节点的Kubernetes集群,
- 有一个以Log Generator形式运行的工作负载,
- 并安装了Fluent Bit来收集所有容器日志。
如果您没有阅读之前的文章,我提供了一个“日志控制简易安装”项目仓库,您可以下载、解压并用一条命令运行,以便在您的本地机器上启动具备上述设置的Kubernetes集群。
无论采用哪种路径,一旦设置完成,您就可以查看包含此运行集群上生成的所有内容的Fluent Bit日志。这将跨越两个命名空间的日志:kube-system和logging。
您可以通过浏览这些命名空间来验证它们是否正在运行,如下所示在我的本地机器上:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
$ kubectl --kubeconfig target/logdemoconfig.yaml get pods --namespace kube-system
NAME READY STATUS RESTARTS AGE
coredns-668d6bf9bc-2skfg 1/1 Running 0 2m43s
coredns-668d6bf9bc-79jpn 1/1 Running 0 2m43s
etcd-logdemo-control-plane 1/1 Running 0 2m51s
kindnet-7lm5s 1/1 Running 0 2m43s
kube-apiserver-logdemo-control-plane 1/1 Running 0 2m50s
kube-controller-manager-logdemo-control-plane 1/1 Running 0 2m50s
kube-proxy-2q9db 1/1 Running 0 2m43s
kube-scheduler-logdemo-control-plane 1/1 Running 0 2m50s
$ kubectl --kubeconfig target/logdemoconfig.yaml get pods --namespace default
NAME READY STATUS RESTARTS AGE
log-generator-7cdff9fcf8-qgw9k 1/1 Running 0 5m4s
$ kubectl --kubeconfig target/logdemoconfig.yaml get pods --namespace logging
NAME READY STATUS RESTARTS AGE
fluent-bit-vk2rf 1/1 Running 0 4m49s
|
Fluent Bit实例的初始配置是收集来自所有命名空间的所有容器日志,如下所示在我们设置中使用的fluent-bit-helm.yaml配置文件中,加粗部分所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
args:
- --workdir=/fluent-bit/etc
- --config=/fluent-bit/etc/conf/fluent-bit.yaml
config:
extraFiles:
fluent-bit.yaml: |
service:
flush: 1
log_level: info
http_server: true
http_listen: 0.0.0.0
http_port: 2020
pipeline:
inputs:
- name: tail
tag: kube.*
read_from_head: true
path: /var/log/containers/*.log
multiline.parser: docker, cri
outputs:
- name: stdout
match: '*'
|
要查看收集的所有日志,我们可以转储Fluent Bit日志文件,如下所示,使用上面找到的Pod名称:
1
2
3
4
|
$ kubectl --kubeconfig target/logdemoconfig.yaml logs fluent-bit-vk2rf --namespace logging
[OUTPUT-CUT-DUE-TO-LOG-VOLUME]
...
|
浏览时您可能会注意到有错误和信息消息,如果仔细观察,还会发现来自Kubernetes Pod、应用程序工作负载甚至您的Fluent Bit实例的一些日志。作为在集群上工作的开发人员,如何在这片日志海洋中找到任何有用的东西?好消息是,您确实有一个单一的地方可以查找它们!
另一点需要注意的是,通过使用Fluent Bit的tail输入插件并将其设置为从每个日志文件的开头读取,我们确保了我们的日志遥测数据取自我们所有的日志。如果我们没有将其设置为从日志文件开头收集,我们的遥测流水线将会错过Fluent Bit实例启动之前生成的所有内容。这确保了我们拥有工作负载的启动消息,并且每次修改流水线配置时都可以在标准日志遥测事件上进行测试。
让我们开始掌控我们的日志,看看我们作为开发人员如何利用我们在本地开发测试期间希望看到的日志数据。
夺回控制权
首先,我们可以将日志收集工作集中在仅我们感兴趣的工作负载上,在这个例子中,我们正在寻找Log Generator应用程序部署的问题。由于您对kube-system命名空间中发生的任何日志不感兴趣,因此可以缩小Fluent Bit输入插件的关注范围,仅检查Log Generator日志文件。
这可以通过创建一个名为myfluent-bit-helm.yaml的新配置文件来完成,并按如下方式更改默认路径(加粗部分):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
args:
- --workdir=/fluent-bit/etc
- --config=/fluent-bit/etc/conf/fluent-bit.yaml
config:
extraFiles:
fluent-bit.yaml: |
service:
flush: 1
log_level: info
http_server: true
http_listen: 0.0.0.0
http_port: 2020
pipeline:
inputs:
- name: tail
tag: kube.*
read_from_head: true
path: /var/log/containers/*generator*
multiline.parser: docker, cri
outputs:
- name: stdout
match: '*'
|
下一步是使用helm update命令更新Fluent Bit实例,如下所示:
1
2
3
4
|
$ helm upgrade --kubeconfig target/logdemoconfig.yaml --install fluent-bit fluent/fluent-bit --set image.tag=4.0.0 --namespace=logging --create-namespace --values=myfluent-bit-helm.yaml
NAME READY STATUS RESTARTS AGE
fluent-bit-mzktk 1/1 Running 0 28s
|
现在,探索Fluent Bit收集的日志,注意所有kube-system命名空间的日志都不再存在,我们可以专注于我们部署的工作负载。
1
2
3
4
5
6
7
|
$ kubectl --kubeconfig target/logdemoconfig.yaml logs fluent-bit-mzktk --namespace logging
...
[0] kube.var.log.containers.log-generator-7cdff9fcf8-qgw9k_default_log-generator-f1be04153240cf686ba99566f79d64a0e2496a4b555dd833000e1ff222f73dc8.log: [[1762440627.216814972, {}], {"time"=>"2025-11-06T14:50:27.216814972Z", "stream"=>"stdout", "_p"=>"F", "log"=>"Thu Nov 6 14:50:27 UTC 2025 - This is a log message from the log generator."}]
[0] kube.var.log.containers.log-generator-7cdff9fcf8-qgw9k_default_log-generator-f1be04153240cf686ba99566f79d64a0e2496a4b555dd833000e1ff222f73dc8.log: [[1762440630.220889184, {}], {"time"=>"2025-11-06T14:50:30.220889184Z", "stream"=>"stdout", "_p"=>"F", "log"=>"Thu Nov 6 14:50:30 UTC 2025 - {message:true 200 success}"}]
[0] kube.var.log.containers.log-generator-7cdff9fcf8-qgw9k_default_log-generator-f1be04153240cf686ba99566f79d64a0e2496a4b555dd833000e1ff222f73dc8.log: [[1762440633.226102188, {}], {"time"=>"2025-11-06T14:50:33.226102188Z", "stream"=>"stderr", "_p"=>"F", "log"=>"Thu Nov 6 14:50:33 UTC 2025 - {message:false 500 error}"}]
...
|
这只是总输出中的一部分日志行。如果更仔细地观察,你会发现这些日志有它们自己的某种格式,所以让我们标准化它们,使JSON成为输出格式,并通过更改您的Fluent Bit输出插件配置来使各种时间戳更具可读性,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
args:
- --workdir=/fluent-bit/etc
- --config=/fluent-bit/etc/conf/fluent-bit.yaml
config:
extraFiles:
fluent-bit.yaml: |
service:
flush: 1
log_level: info
http_server: true
http_listen: 0.0.0.0
http_port: 2020
pipeline:
inputs:
- name: tail
tag: kube.*
read_from_head: true
path: /var/log/containers/*ghost*
multiline.parser: docker, cri
outputs:
- name: stdout
match: '*'
format: json_lines
json_date_format: java_sql_timestamp
|
使用helm update命令更新Fluent Bit实例,如下所示:
1
2
3
4
|
$ helm upgrade --kubeconfig target/logdemoconfig.yaml --install fluent-bit fluent/fluent-bit --set image.tag=4.0.0 --namespace=logging --create-namespace --values=myfluent-bit-helm.yaml
NAME READY STATUS RESTARTS AGE
fluent-bit-gqsc8 1/1 Running 0 42s
|
现在探索Fluent Bit收集的日志,注意输出变化:
1
2
3
4
5
6
|
$ kubectl --kubeconfig target/logdemoconfig.yaml logs fluent-bit-gqsc8 --namespace logging
...
{"date":"2025-11-06 14:51:44.314963","time":"2025-11-06T14:51:44.314963452Z","stream":"stdout","_p":"F","log":"Thu Nov 6 14:51:44 UTC 2025 - This is a log message from the log generator."}
{"date":"2025-11-06 14:51:47.317883","time":"2025-11-06T14:51:47.317883265Z","stream":"stdout","_p":"F","log":"Thu Nov 6 14:51:47 UTC 2025 - {message:true 200 success}"}
{"date":"2025-11-06 14:51:50.321730","time":"2025-11-06T14:51:50.321730204Z","stream":"stderr","_p":"F","log":"Thu Nov 6 14:51:50 UTC 2025 - {message:false 500 error}"}
...
|
现在,如果我们更仔细地查看消息数组,作为开发人员,我们注意到混合了stderr和stdout日志行。让我们来掌控局面,修剪掉所有不包含stderr的行,因为我们只对出错的内容感兴趣。
我们需要使用grep过滤器向Fluent Bit配置添加一个过滤器部分,并定位一个正则表达式来选择键stream或值stderr,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
args:
- --workdir=/fluent-bit/etc
- --config=/fluent-bit/etc/conf/fluent-bit.yaml
config:
extraFiles:
fluent-bit.yaml: |
service:
flush: 1
log_level: info
http_server: true
http_listen: 0.0.0.0
http_port: 2020
pipeline:
inputs:
- name: tail
tag: kube.*
read_from_head: true
path: /var/log/containers/*ghost*
multiline.parser: docker, cri
filters:
- name: grep
match: '*'
regex: stream stderr
outputs:
- name: stdout
match: '*'
format: json_lines
json_date_format: java_sql_timestamp
|
使用helm update命令更新Fluent Bit实例,如下所示:
1
2
3
4
|
$ helm upgrade --kubeconfig target/logdemoconfig.yaml --install fluent-bit fluent/fluent-bit --set image.tag=4.0.0 --namespace=logging --create-namespace --values=myfluent-bit-helm.yaml
NAME READY STATUS RESTARTS AGE
fluent-bit-npn8n 1/1 Running 0 12s
|
现在探索Fluent Bit收集的日志,注意输出变化:
1
2
3
4
5
6
7
8
|
$ kubectl --kubeconfig target/logdemoconfig.yaml logs fluent-bit-npn8n --namespace logging
...
{"date":"2025-11-06 14:52:56.411711","time":"2025-11-06T14:52:56.411711621Z","stream":"stderr","_p":"F","log":"Thu Nov 6 14:52:56 UTC 2025 - {message:false 500 error}"}
{"date":"2025-11-06 14:53:07.426493","time":"2025-11-06T14:53:07.426493474Z","stream":"stderr","_p":"F","log":"Thu Nov 6 14:53:07 UTC 2025 - {message:false 500 error}"}
{"date":"2025-11-06 14:53:18.441807","time":"2025-11-06T14:53:18.441807795Z","stream":"stderr","_p":"F","log":"Thu Nov 6 14:53:18 UTC 2025 - {message:false 500 error}"}
{"date":"2025-11-06 14:53:29.453509","time":"2025-11-06T14:53:29.453509211Z","stream":"stderr","_p":"F","log":"Thu Nov 6 14:53:29 UTC 2025 - {message:false 500 error}"}
{"date":"2025-11-06 14:53:40.462905","time":"2025-11-06T14:53:40.462905134Z","stream":"stderr","_p":"F","log":"Thu Nov 6 14:53:40 UTC 2025 - {message:false 500 error}"}\
...
|
现在我们不再看到标准输出日志事件,因为我们的遥测流水线正在过滤以仅显示标记为标准错误的日志!
这个练习展示了如何在Kubernetes集群上使用Fluent Bit遥测流水线来格式化和修剪我们的日志。现在,让我们看看如何丰富我们的日志遥测数据。
我们将在每个标准错误行上添加标签,指向待命开发人员需要联系的SRE。为此,我们扩展Fluent Bit配置的过滤器部分,使用modify过滤器并定位键stream或值stderr,以删除这些键并添加两个新键STATUS和ACTION,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
args:
- --workdir=/fluent-bit/etc
- --config=/fluent-bit/etc/conf/fluent-bit.yaml
config:
extraFiles:
fluent-bit.yaml: |
service:
flush: 1
log_level: info
http_server: true
http_listen: 0.0.0.0
http_port: 2020
pipeline:
inputs:
- name: tail
tag: kube.*
read_from_head: true
path: /var/log/containers/*ghost*
multiline.parser: docker, cri
filters:
- name: grep
match: '*'
regex: stream stderr
- name: modify
match: '*'
condition: Key_Value_Equals stream stderr
remove: stream
add:
- STATUS REALLY_BAD
- ACTION CALL_SRE
outputs:
- name: stdout
match: '*'
format: json_lines
json_date_format: java_sql_timestamp
|
使用helm update命令更新Fluent Bit实例,如下所示:
1
2
3
4
|
$ helm upgrade --kubeconfig target/logdemoconfig.yaml --install fluent-bit fluent/fluent-bit --set image.tag=4.0.0 --namespace=logging --create-namespace --values=myfluent-bit-helm.yaml
NAME READY STATUS RESTARTS AGE
fluent-bit-ftfs4 1/1 Running 0 32s
|
现在,探索Fluent Bit收集的日志,注意输出变化,其中stream键缺失,并且在每个错误日志事件的末尾添加了两个新键:
1
2
3
4
5
6
7
8
9
|
$ kubectl --kubeconfig target/logdemoconfig.yaml logs fluent-bit-ftfs4 --namespace logging
...
[CUT-LINE-FOR-VIEWING] {message:false 500 error}","STATUS":"REALLY_BAD_ERROR","ACTION":"CALL_SRE"}
[CUT-LINE-FOR-VIEWING] {message:false 500 error}","STATUS":"REALLY_BAD_ERROR","ACTION":"CALL_SRE"}
[CUT-LINE-FOR-VIEWING] {message:false 500 error}","STATUS":"REALLY_BAD_ERROR","ACTION":"CALL_SRE"}
[CUT-LINE-FOR-VIEWING] {message:false 500 error}","STATUS":"REALLY_BAD_ERROR","ACTION":"CALL_SRE"}
[CUT-LINE-FOR-VIEWING] {message:false 500 error}","STATUS":"REALLY_BAD_ERROR","ACTION":"CALL_SRE"}
...
|
现在我们有了一个正在运行的Kubernetes集群、一个生成日志的应用程序工作负载,以及一个用于收集和控制日志遥测数据的Fluent Bit遥测流水线。
最初,我们发现收集所有日志遥测数据令人应接不暇,并且难以筛选出对开发需求重要的事件。然后,我们开始通过缩小收集策略、过滤并最终丰富遥测数据来夺回对日志遥测数据的控制权。
系列后续
在本文中,您学习了如何在Kubernetes集群上使用Fluent Bit来掌控遥测数据。本文基于这个(更新后的)在线免费研讨会。
本系列将有更多内容,您将继续学习如何在现实世界中配置、运行、管理和掌握Fluent Bit的使用。接下来,将是Fluent Bit服务部分配置的开发人员指南。