Fluentd:在Kubernetes上支持多行日志
首先
我认为在Kubernetes中使用fluent进行日志收集是一种相当流行的方法。
实际尝试后,我发现当在Kubernetes上运行的应用程序产生多个业务的日志时,
日志会在Kubernetes中被拆分为多个部分。
我认为在Fluentd中,根据固定的日志格式,可以解析日志内容是其中的一个优点,
但现在这样做可能无法进行解析了。
具体来说,就是这种感觉。
2020-10-04T14:07:22.234Z ERR Authorization error because you have to be a member of following groups
XXXX
YYYY
ZZZZ
这将会被划分成类似这样的感觉。
{"log":"2020-10-04T14:07:22.234Z ERR Authorization error because you have to be a member of following groups\n","stream":"stderr","time":"2020-10-04T14:07:22.234Z"}
{"log":"XXXX\n","stream":"stderr","time":"2020-10-04T14:07:22.434Z"}
{"log":"YYYY\n","stream":"stderr","time":"2020-10-04T14:07:22.634Z"}
{"log":"ZZZZ\n","stream":"stderr","time":"2020-10-04T14:07:22.639Z"}
我认为最终会将日志集中到数据库或者Elasticsearch之类的地方,但这样可读性会下降呢…
我进行了各种调查,但没有找到同时进行日志合并和解析(按照我的想法)的案例,所以我进行了反复尝试,终于写成了一篇文章。
如果能对某人有所帮助,我会很高兴的。
顺便提一下,在Fluent内可以使用Ruby代码,但是我不懂Ruby。
我在最后的解析部分使用了Ruby,但是只是试探性地进行,所以可能会有一些改进点被Ruby专家发现。
如果可以的话,我们非常希望您能给予我们友善且有建设性的意见。
环境
kubectl:v1.16.13
k8s 服务器: AWS EKS
fluentd:1.11.3
流畅的配置
尽快解决方案。
首先,选择要使用的插件。
fluent-plugin-concat (2.4.0)
fluent-plugin-record-reformer (0.9.1)
因为没有时间去调查,所以我只好编辑并使用现有的图片了。
FROM fluent/fluentd-kubernetes-daemonset:v1.11.3-debian-kinesis-1.0
RUN fluent-gem install fluent-plugin-record-reformer
我们将在这里制作的图像上传到AWS ECR,并将其作为Daemonset使用。
这个图像默认会收集kubernetes上的日志,但是不支持合并上述分割的日志,而是按行输出。
我会更改这个。
最初的逻辑
主要的配置文件是/fluentd/etc/fluent.conf。
@include "#{ENV['FLUENTD_SYSTEMD_CONF'] || 'systemd'}.conf"
@include "#{ENV['FLUENTD_PROMETHEUS_CONF'] || 'prometheus'}.conf"
@include kubernetes.conf
Kubernetes上的应用程序日志存储在/var/log/containers/*.log中。
由于kubernets.conf对应上述配置,所以将覆盖此文件。
我正在原始文件中添加以下内容。
<filter kubernetes.**>
@type concat
key log
multiline_start_regexp /^\d{4}-\d{1,2}-\d{1,2}.*/
separator ''
flush_interval 5
timeout_label @NORMAL
</filter>
<match **>
@type relabel
@label @NORMAL
</match>
<label @NORMAL>
<match kubernetes.**>
@type record_reformer
tag ref.kubernetes
enable_ruby true
time ${begin log.scan(/^(\d{4}-\d{1,2}-\d{1,2}T\d{1,2}:\d{1,2}:\d{1,2}.\d{1,3}Z?)/).first.first rescue "" end}
level ${begin log.scan(/^\d{4}-\d{1,2}-\d{1,2}T\d{1,2}:\d{1,2}:\d{1,2}.\d{1,3}Z (\w{3}?)/).first.first rescue "" end}
message ${begin log.gsub(/\n/, 'NNN').scan(/^\d{4}-\d{1,2}-\d{1,2}T\d{1,2}:\d{1,2}:\d{1,2}.\d{1,3}Z \w{3} (.*?)$/).first.first.gsub(/NNN/, '\n') rescue log end}
</match>
<filter ref.kubernetes>
@type record_transformer
enable_ruby
<record>
container ${record.dig("kubernetes", "container_name")}
</record>
</filter>
<match **>
@type kinesis_streams
@id out_kinesis_streams
region "ap-northeast-1"
stream_name "xxxxx"
include_time_key "xxxxx"
<buffer>
@type file
path /var/log
flush_at_shutdown true
flush_interval 1
chunk_limit_size "1m"
flush_thread_interval 0.1
flush_thread_burst_interval 0.01
flush_thread_count 15
</buffer>
</store>
</match>
</label>
以下是解释。
1. 请使用 @type 连接起来
这是几乎与Github说明文件中的kubernetes实际应用案例完全相同。
我们利用应用程序日志中的规则性(即使换行,日期始终位于日志的开头),使用multiline_start_regexp来判断multiline的结束。
另外,由于异常常常不符合此格式,因此我们设置了超时和超时标签,并使得不符合此正则表达式的内容能够继续传递到后续步骤中。
将设置为键的日志字段连接在一起,然后流经下一个进程。
2. @类型 记录整理器
由於在前一個步驟中標籤已經被賦予,所以在
我正在使用Ruby的scan方法,通过正则表达式提取值。
另外,不符合前一个多行正则表达式的内容根本不会成为scan的目标,
由于scan(xxx)没有返回值,所以会触发scan(xxx).first.first的异常。
因此,我在其中使用了Ruby的异常处理机制begin rescue end。
最后,由于合并日志中的主要部分,肯定会包括换行符。
在这里,我尝试了正则表达式和扫描等常规方法,但无论如何都无法正确处理换行部分,
如果忽略换行符,就无法正确确定结尾,无法顺利进行。
尽管有些污乱,但使用gsub来转义换行符,最后再恢复换行(因为在本例中想要将换行符发送到kinesis作为换行的原因。如果希望使用空格等其他字符,只需将其更改为空格即可)。
结束
以上是关于我为什么写了这篇文章的原因。
我想很多人都有尝试同样的事情,但无论是用日语还是英语,都没有直接适用的内容。
因此,我进行了各种调查和试错,将其内容写成了这篇文章。
期待您的问题、改善意见等。
请你用中文给一个翻译。
关于 concatenate:fluent-plugin-concat
关于连接后的解析提示:使用FluentD解析Ruby on Rails日志