36.5.3. fluentd
Fluentd 部署为 DaemonSet,它根据节点选择器部署节点,您可以使用 inventory 参数 openshift_logging_fluentd_nodeselector
指定,默认为 logging-infra-fluentd
。作为 OpenShift 集群安装的一部分,建议您将 Fluentd 节点选择器添加到持久的 节点标签 列表中。
Fluentd 使用 journald
作为系统日志源。这些是来自操作系统、容器运行时和 OpenShift 的日志消息。
可用的容器运行时提供少许信息来标识日志消息的来源。在 pod 被删除后,日志收集和日志的规范化可能无法从 API 服务器检索其他元数据,如标签或注解。
如果在日志收集器完成处理日志前删除了具有指定名称和命名空间的 pod,则可能无法将日志消息与类似命名的 pod 和命名空间区分开来。这可能导致日志被索引,并将其注解为不是由部署 pod 的用户拥有的索引。
可用的容器运行时提供少许信息来标识日志消息来源,无法确保唯一的个别日志消息,也不能保证可以追溯这些消息的来源。
OpenShift Container Platform 3.9 或更高版本的清理安装使用 json-file
作为默认日志驱动程序,但从 OpenShift Container Platform 3.7 升级的环境将维护其现有的 journald
日志驱动程序配置。建议您使用 json-file
日志驱动程序。如需了解将现有日志驱动程序配置改为 json-file
的步骤,请参阅更改 Aggregated Logging 驱动程序。
查看 Fluentd 日志
如何查看日志取决于 LOGGING_FILE_PATH
设置。
如果
LOGGING_FILE_PATH
指向一个文件,请使用 logs 程序打印 Fluentd 日志文件的内容:oc exec <pod> -- logs 1
- 1
- 指定 Fluentd Pod 的名称。注意
logs
前面的空格。
例如:
oc exec logging-fluentd-lmvms -- logs
从最旧的日志开始,将打印出日志文件的内容。使用
-f
选项跟踪正在写入日志中的内容。如果使用
LOGGING_FILE_PATH=console
,Fluentd 会将日志记录到其默认位置/var/log/fluentd/fluentd.log
。您可以使用oc logs -f <pod_name>
命令来检索日志。例如:
oc logs -f fluentd.log
配置 Fluentd 日志位置
Fluentd 根据 LOGGING_FILE_PATH
环境变量,将日志写入指定的文件,默认为 /var/log/fluentd/fluentd.log
或控制台。
要更改 Fluentd 日志的默认输出位置,请使用默认清单文件中的 LOGGING_FILE_PATH
参数。您可以指定特定文件或使用 Fluentd 默认位置:
LOGGING_FILE_PATH=console 1 LOGGING_FILE_PATH=<path-to-log/fluentd.log> 2
更改这些参数后,重新运行 logging installer playbook :
$ cd /usr/share/ansible/openshift-ansible $ ansible-playbook [-i </path/to/inventory>] \ playbooks/openshift-logging/config.yml
配置 Fluentd 日志轮转
当当前的 Fluentd 日志文件达到指定大小时,OpenShift Container Platform 会自动重命名 fluentd.log 日志文件,以便收集新的日志数据。日志轮转会被默认启用。
以下示例显示了在一个集群中,最大日志大小为 1Mb,应保留四个日志。当 fluentd.log 到达 1Mb 时,OpenShift Container Platform 会删除当前的 fluentd.log.4,依次重命名每个 Fluentd 日志,并创建一个新的 fluentd.log。
fluentd.log 0b fluentd.log.1 1Mb fluentd.log.2 1Mb fluentd.log.3 1Mb fluentd.log.4 1Mb
您可以控制 Fluentd 日志文件的大小,以及 OpenShift Container Platform 使用环境变量保留的重命名文件的数量。
参数 | 描述 |
---|---|
| Bytes 中单个 Fluentd 日志文件的最大大小。如果 flientd.log 文件的大小超过这个值,OpenShift Container Platform 会重命名 fluentd.log.* 文件,并创建一个新的 fluentd.log。默认值为 1024000 (1MB)。 |
|
Fluentd 在删除前保留的日志数量。默认值为 |
例如:
$ oc set env ds/logging-fluentd LOGGING_FILE_AGE=30 LOGGING_FILE_SIZE=1024000"
通过设置 LOGGING_FILE_PATH=console
来关闭日志轮转。这会导致 Fluentd 写入 Fluentd 默认位置 /var/log/fluentd/fluentd.log,您可以在其中使用 oc logs -f <pod_name>
命令检索它们。
$ oc set env ds/fluentd LOGGING_FILE_PATH=console
使用 MERGE_JSON_LOG 禁用日志的 JSON 解析
默认情况下,Fluentd 会决定日志消息是否为 JSON 格式,并将消息合并到发布至 Elasticsearch 的 JSON 有效负载文档中。
使用 JSON 解析时,您可能会遇到:
- 由于类型映射不一致,Elasticsearch 会拒绝文档从而可能导致日志丢失。
- 拒绝消息循环导致的缓冲存储泄漏 ;
- 使用相同名称的字段覆盖数据。
有关如何缓解这些问题的信息,请参阅配置日志收集器规范日志的方式。
您可以禁用 JSON 解析以避免这些问题,或者不需要从日志解析 JSON。
禁用 JSON 解析:
运行以下命令:
oc set env ds/logging-fluentd MERGE_JSON_LOG=false 1
- 1
- 把此项设为
false
会禁用此功能,设为true
则启用此功能。
要确保此设置在每次运行 Ansible 时应用,请将
openshift_logging_fluentd_merge_json_log="false"
添加到您的 Ansible 清单中。
配置日志收集器规范日志的方式
集群日志记录使用特定的数据模型(例如数据库架构),将日志记录及其元数据存储在日志记录存储中。数据有一些限制:
-
必须有一个含有实际日志消息的
"message"
字段。 -
必须有一个包含 RFC 3339 格式的日志记录时间戳的
"@timestamp"
字段,最好是毫秒或更细的解析度。 -
必须有一个注明日志级别的
"level"
字段,如err
、info
和unknown
等。
如需有关数据模型的更多信息,请参阅导出字段。
由于这些要求的原因,从不同子系统收集的日志数据可能会发生冲突和不一致。
例如,如果您使用 MERGE_JSON_LOG
功能 (MERGE_JSON_LOG=true
),那么让您的应用程序以 JSON 格式记录其输出并让日志收集器自动在 Elasticsearch 中解析和索引数据会特别有用。不过,这会导致几个问题,具体包括:
- 字段名称可能为空,或包含 Elasticsearch 中非法的字符;
- 同一命名空间中的不同应用程序可能会输出具有不同值数据类型的相同字段名称;
- 应用程序可能会发出太多字段;
- 字段可能与集群日志记录内置字段冲突。
您可以编辑 Fluentd 日志收集器 DaemonSet 并设置下表中的环境变量,来配置集群日志记录如何对待来自不同来源的字段。
未定义字段。ViaQ 数据模型未知的字段称为 undefined。来自不同系统的日志数据可以包含未定义字段。数据模型需要定义和描述所有顶级字段。
使用参数来配置 OpenShift Container Platform 如何在名为
undefined
的顶级字段下移动任何未定义字段,以避免与众所周知的 顶级字段冲突。您可以将未定义字段添加到顶级字段,并将其他字段移动到undefined
容器中。您还可以替换未定义字段中的特殊字符,并将未定义字段转换为其 JSON 字符串表示形式。转换为 JSON 字符串可保留值的结构,以便您日后可以检索值并将其重新转换为映射或数组。
-
简单的标量值(如数字和布尔值)将被变为带引号的字符串。例如:
10
变为"10"
,3.1415
变为"3.1415"
,false
变为"false"
。 -
映射/字典值和数组值将转换为对应的 JSON 字符串表示形式:
"mapfield":{"key":"value"}
变成"mapfield":"{\"key\":\"value\"}"
,"arrayfield":[1,2,"three"]
则变成"arrayfield":"[1,2,\"three\"]"
。
-
简单的标量值(如数字和布尔值)将被变为带引号的字符串。例如:
已定义字段。已定义字段会出现在日志的顶级中。您可以配置哪些字段被视为已定义字段。
默认的顶级字段通过
CDM_DEFAULT_KEEP_FIELDS
参数定义,它们包括CEE
、time
、@timestamp
、aushape
、ci_job
、collectd
、docker
、fedora-ci
、file
、foreman
、geoip
、hostname
、ipaddr4
、ipaddr6
、kubernetes
、level
、message
、namespace_name
、namespace_uuid
、offset
、openstack
、ovirt
、pid
、pipeline_metadata
、service
、systemd
、tags
、testcase
、tlog
和viaq_msg_id
。如果
CDM_USE_UNDEFINED
为true
,所有未包含在${CDM_DEFAULT_KEEP_FIELDS}
或${CDM_EXTRA_KEEP_FIELDS}
中的字段将移到${CDM_UNDEFINED_NAME}
。有关这些参数的详情,请参考下表。注意CDM_DEFAULT_KEEP_FIELDS
参数仅供高级用户使用,或在红帽支持的指导下使用。- 空白字段。空白字段没有数据。您可以确定要从日志中保留的空白字段。
参数 | 定义 | 示例 |
---|---|---|
|
除了 |
|
| 即使为空,也要以 CSV 格式指定要保留的字段。未指定的空白已定义字段将被丢弃。默认值为 "message",即保留空消息。 |
|
|
设为 |
|
|
如果使用 |
|
|
如果未定义字段的数量大于此数,则所有未定义字段都转换为其 JSON 字符串表示形式,并存储在
注:即使 |
|
|
设为 |
|
|
指定要在未定义字段中代替句点字符“.”的字符。 |
|
如果将 Fluentd 日志收集器 DaemonSet 中的 MERGE_JSON_LOG
参数和 CDM_UNDEFINED_TO_STRING
环境变量设置为 true,您可能会收到 Elasticsearch 400错误。当 MERGE_JSON_LOG=true
时,日志收集器会添加数据类型为字符串以外的字段。如果设置 CDM_UNDEFINED_TO_STRING=true
,日志收集器会尝试将这些字段作为字符串值添加,从而导致 Elasticsearch 400 错误。日志收集器翻转下一日的日志的索引时会清除此错误。
当日志收集器翻转索引时,它将创建一个全新的索引。字段定义会更新,您也不会收到 400 错误。如需更多信息,请参阅设置 MERGE_JSON_LOG 和 CDM_UNDEFINED_TO_STRING。
要配置未定义和空字段处理,请编辑 logging-fluentd
daemonset:
根据需要配置如何处理字段:
-
使用
CDM_EXTRA_KEEP_FIELDS
指定要移动的字段。 -
以 CSV 格式在
CDM_KEEP_EMPTY_FIELDS
参数中指定要保留的空字段。
-
使用
根据需要配置如何处理未定义字段:
-
将
CDM_USE_UNDEFINED
设置为true
可将未定义字段移到顶级undefined
字段: -
使用
CDM_UNDEFINED_NAME
参数为未定义字段指定名称。 -
将
CDM_UNDEFINED_MAX_NUM_FIELDS
设置为默认值-1
以外的值,以设置单个记录中未定义字段数的上限。
-
将
-
指定
CDM_UNDEFINED_DOT_REPLACE_CHAR
,将未定义字段名称中的句点字符.
更改为其他字符。例如,如果CDM_UNDEFINED_DOT_REPLACE_CHAR=@@@
并且有一个名为foo.bar.baz
的字段,该字段会转变为foo@@@bar@@@baz
。 -
将
UNDEFINED_TO_STRING
设置为true
可将未定义字段转换为其 JSON 字符串表示形式。
如果配置 CDM_UNDEFINED_TO_STRING
或 CDM_UNDEFINED_MAX_NUM_FIELDS
参数,您可以使用 CDM_UNDEFINED_NAME
更改未定义字段名称。此字段是必需的,因为 CDM_UNDEFINED_TO_STRING
或CDM_UNDEFINED_MAX_NUM_FIELDS
可能会更改未定义字段的值类型。当 CDM_UNDEFINED_TO_STRING
或 CDM_UNDEFINED_MAX_NUM_FIELDS
设为 true 并且日志中还有更多未定义字段时,值类型将变为 string
。如果值类型改变(例如,从 JSON 变为 JSON 字符串),Elasticsearch 将停止接受记录。
例如,当 CDM_UNDEFINED_TO_STRING
为 false
或者 CDM_UNDEFINED_MAX_NUM_FIELDS
是默认值 -1
时,未定义字段的值类型将为 json
。如果将 CDM_UNDEFINED_MAX_NUM_FIELDS
更改为默认值以外的值,且日志中还有更多未定义字段,则值类型将变为 string
(JSON 字符串)。如果值类型改变,Elasticsearch 将停止接受记录。
设置 MERGE_JSON_LOG 和 CDM_UNDEFINED_TO_STRING
如果将 MERGE_JSON_LOG
和 CDM_UNDEFINED_TO_STRING
环境变量设置为 true
,您可能会收到 Elasticsearch 400 错误。当 MERGE_JSON_LOG=true
时,日志收集器会添加数据类型为字符串以外的字段。如果设置了 CDM_UNDEFINED_TO_STRING=true
,Fluentd 会尝试将这些字段作为字符串值来添加,从而导致 Elasticsearch 400 错误。下一日翻转索引时会清除此错误。
当 Fluentd 针对下一日的日志翻转索引时,它将创建一个全新的索引。字段定义会更新,您也不会收到 400 错误。
无法重试具有 hard 错误的记录,如架构违规和数据损坏等。日志收集器发送这些记录以进行错误处理。如果在 Fluentd 中添加了一个 <label @ERROR>
部分 作为最后一个 <label>
,您可以根据需要处理这些记录。
例如:
data: fluent.conf: .... <label @ERROR> <match **> @type file path /var/log/fluent/dlq time_slice_format %Y%m%d time_slice_wait 10m time_format %Y%m%dT%H%M%S%z compress gzip </match> </label>
此部分将错误记录写入 Elasticsearch 死信队列 (DLQ) 文件。如需有关文件输出的更多信息,请参阅 fluentd 文档。
然后,您可以编辑该文件来手动清理记录,编辑该文件以与 Elasticsearch /_bulk index
API 搭配使用,并且使用 cURL 来添加这些记录。如需有关 Elasticsearch Bulk API 的更多信息,请参阅 Elasticsearch 文档。
加入多行 Docker 日志
您可以将 Fluentd 配置为从 Docker 日志部分片段中重建整个日志记录。通过此功能活跃,Fluentd 会读取多行 Docker 日志,重新创建它们,并将日志作为 Elasticsearch 中的记录存储在没有缺失数据的 Elasticsearch 中。
但是,因为这个功能可能会导致性能回归,因此这个功能会默认关闭,必须手动启用。
以下 Fluentd 环境变量配置集群日志记录以处理多行 Docker 日志:
参数 | 描述 |
---|---|
USE_MULTILINE_JSON |
设置为 |
USE_MULTILINE_JOURNAL |
设置为 |
您可以使用以下命令来决定正在使用的日志驱动程序:
$ docker info | grep -i log
以下是输出结果之一:
Logging Driver: json-file
Logging Driver: journald
打开多行 Docker 日志处理:
使用以下命令启用多行 Docker 日志:
对于
json-file
日志驱动程序:oc set env daemonset/logging-fluentd USE_MULTILINE_JSON=true
对于
journald
日志驱动程序:oc set env daemonset/logging-fluentd USE_MULTILINE_JOURNAL=true
集群中的 Fluentd Pod 重启。
配置 Fluentd 以将日志发送到外部日志聚合器
除了默认的 Elasticsearch 外,您还可以使用 secure-forward
插件,将 Fluentd 配置为将其日志的副本发送到外部日志聚合器。在本地托管的 Fluentd 处理日志记录之后,您可以从那里进一步处理日志记录。
您不能使用客户端证书配置 secure_foward
插件。身份验证可以通过 SSL/TLS 协议运行,但要求使用 secure_foward
输入插件配置 shared_key
和目标 Fluentd
。
日志记录部署操作在 Fluentd ConfigMap 中提供了一个 secure-forward.conf
部分,可用于配置外部聚合器:
<store> @type secure_forward self_hostname pod-${HOSTNAME} shared_key thisisasharedkey secure yes enable_strict_verification yes ca_cert_path /etc/fluent/keys/your_ca_cert ca_private_key_path /etc/fluent/keys/your_private_key ca_private_key_passphrase passphrase <server> host ose1.example.com port 24284 </server> <server> host ose2.example.com port 24284 standby </server> <server> host ose3.example.com port 24284 standby </server> </store>
这可以通过 oc edit
命令更新:
$ oc edit configmap/logging-fluentd
要在 secure-forward.conf
中使用的证书可以添加到 Fluentd Pod 上挂载的现有 secret 中。your_ca_cert
和 your_private_key
值必须与 configmap/logging-fluentd
中的 secure-forward.conf
中指定的值匹配:
$ oc patch secrets/logging-fluentd --type=json \ --patch "[{'op':'add','path':'/data/your_ca_cert','value':'$(base64 -w 0 /path/to/your_ca_cert.pem)'}]" $ oc patch secrets/logging-fluentd --type=json \ --patch "[{'op':'add','path':'/data/your_private_key','value':'$(base64 -w 0 /path/to/your_private_key.pem)'}]"
将 your_private_key
替换为一个通用名称。这个链接指向 JSON 路径,而不是主机系统上的路径。
配置外部聚合器时,它必须能够安全地接受来自 Fluentd 的消息。
如果外部聚合器是另一个 Fluentd 服务器,它必须安装 fluent-plugin-secure-forward
插件,并使用它提供的输入插件:
<source> @type secure_forward self_hostname ${HOSTNAME} bind 0.0.0.0 port 24284 shared_key thisisasharedkey secure yes cert_path /path/for/certificate/cert.pem private_key_path /path/for/certificate/key.pem private_key_passphrase secret_foo_bar_baz </source>
您可以参阅如何在 fluent-plugin-secure-forward
repository 中设置fluent-plugin-secure-forward
插件。
将连接数量从 Fluentd 减小到 API 服务器
MUX
只是一个技术预览功能。技术预览功能不包括在红帽生产服务级别协议(SLA)中,且其功能可能并不完善。因此,红帽不建议在生产环境中使用它们。这些技术预览功能可以使用户提早试用新的功能,并有机会在开发阶段提供反馈意见。
如需红帽技术预览功能支持范围的更多信息,请参阅 https://access.redhat.com/support/offerings/techpreview/。
MUX
是一个安全转发监听器服务。
参数 | 描述 |
---|---|
|
默认值为 |
|
|
|
默认值为 |
|
默认为 |
| 24284 |
| 500M |
| 2Gi |
|
默认值为 |
|
默认值为空,允许为外部 |
Fluentd 中的节流日志
对于特别冗长的项目,管理员可以减慢 Fluentd 中读取日志的速度,然后再处理。
节流可能会导致日志聚合落后于配置的项目;如果在 Fluentd 赶上之前删除了 Pod,则日志条目可能会丢失。
使用 systemd 系统日志作为日志源时,节流不起作用。节流的实施取决于各个项目中个别日志文件是否能够减慢读取速度。从系统日志中读取时,只有一个日志源,而没有日志文件,因此无法使用基于文件的节流。没有办法可以限制读取到 Fluentd 进程中的日志条目。
要告知 Fluentd 应该限制的项目,在部署后编辑 ConfigMap 中的节流配置:
$ oc edit configmap/logging-fluentd
throttle-config.yaml 键的格式是 YAML 文件,其包含项目名称以及各个节点上希望读取日志的速度。默认值为每个节点一次读取 1000 行。例如:
- 项目
project-name: read_lines_limit: 50 second-project-name: read_lines_limit: 100
- 日志记录
logging: read_lines_limit: 500 test-project: read_lines_limit: 10 .operations: read_lines_limit: 100
要更改 Fluentd,请更改配置并重启 Fluentd Pod 以应用更改。要对 Elasticsearch 进行更改,必须首先缩减 Fluentd,然后再缩减 Elasticsearch 为零。进行更改后,首先扩展 Elasticsearch,然后再将 Fluentd 扩展至其原始设置。
将 Elasticsearch 扩展为零:
$ oc scale --replicas=0 dc/<ELASTICSEARCH_DC>
更改 daemonset 配置中的 nodeSelector 以匹配零:
获取 Fluentd 节点选择器:
$ oc get ds logging-fluentd -o yaml |grep -A 1 Selector nodeSelector: logging-infra-fluentd: "true"
使用 oc patch
命令修改 daemonset nodeSelector:
$ oc patch ds logging-fluentd -p '{"spec":{"template":{"spec":{"nodeSelector":{"nonexistlabel":"true"}}}}}'
获取 Fluentd 节点选择器:
$ oc get ds logging-fluentd -o yaml |grep -A 1 Selector nodeSelector: "nonexistlabel: "true"
从零扩展 Elasticsearch:
$ oc scale --replicas=# dc/<ELASTICSEARCH_DC>
将 daemonset 配置中的 nodeSelector 改为 logging-infra-fluentd: "true"。
使用 oc patch
命令修改 daemonset nodeSelector:
oc patch ds logging-fluentd -p '{"spec":{"template":{"spec":{"nodeSelector":{"logging-infra-fluentd":"true"}}}}}'
微调缓冲块限制
如果 Fluentd 日志记录器无法满足大量日志的需求,则需要切换到文件缓冲来降低内存用量并防止数据丢失。
Fluentd buffer_chunk_limit
由环境变量 BUFFER_SIZE_LIMIT
决定,其默认值为 8m
。每个输出的文件缓冲区大小由环境变量 FILE_BUFFER_LIMIT
决定,其默认值为 256Mi
。持久性卷大小必须大于 FILE_BUFFER_LIMIT
与输出相乘的结果。
在 Fluentd 和 Mux pod 上,持久性卷 /var/lib/fluentd 应该通过 PVC 或 hostmount 进行准备,例如:然后,将该区域用作文件缓冲区。
buffer_type
和 buffer_path
在 Fluentd 配置文件中进行配置,如下所示:
$ egrep "buffer_type|buffer_path" *.conf output-es-config.conf: buffer_type file buffer_path `/var/lib/fluentd/buffer-output-es-config` output-es-ops-config.conf: buffer_type file buffer_path `/var/lib/fluentd/buffer-output-es-ops-config` filter-pre-mux-client.conf: buffer_type file buffer_path `/var/lib/fluentd/buffer-mux-client`
Fluentd buffer_queue_limit
是变量 BUFFER_QUEUE_LIMIT
的值。默认值为 32
。
环境变量 BUFFER_QUEUE_LIMIT
计算为 (FILE_BUFFER_LIMIT / (number_of_outputs * BUFFER_SIZE_LIMIT))
。
如果 BUFFER_QUEUE_LIMIT
变量具有默认值:
-
FILE_BUFFER_LIMIT = 256Mi
-
number_of_outputs = 1
-
BUFFER_SIZE_LIMIT = 8Mi
buffer_queue_limit
的值为 32
。要更改 buffer_queue_limit
,您需要更改 FILE_BUFFER_LIMIT
的值。
在这个公式中,如果所有日志都发送到单个资源,则 number_of_outputs
为 1
,否则每多一个资源就会递增 1
。例如,number_of_outputs
的值为:
-
1
- 如果所有日志都发送到单个 ElasticSearch pod -
2
- 如果应用程序日志发送到 ElasticSearch pod,并且 ops 日志发送到另一个 ElasticSearch pod -
4
- 如果应用程序日志发送到一个 ElasticSearch pod,ops 日志发送到另一个 ElasticSearch pod,并且这两者都转发到其他 Fluentd 实例