Buzeli
buzeliSoluções Digitais
Kubernetes

OKE ARM64上的Fluentd DaemonSet:8个连续错误直到日志到达OCI Logging

发布于 2026年4月17日

Fluentd DaemonSet no OKE ARM64: 8 erros em sequência resolvidos para enviar logs ao OCI Logging

目标:Next.js Pod → OCI日志服务

一个使用ARM64节点(A1.Flex Ampere)的OKE(Oracle Kubernetes Engine)集群需要将应用Pod的错误日志发送到OCI日志服务。应用已经通过stdout/stderr输出结构化日志——工作是使用Fluentd捕获这些日志,按正确的Pod过滤,并通过实例主体认证的HTTPS传输到OCI日志服务。

计划的架构很直接:

复制
Pod (console.error → stdout/stderr)
  → CRI-O (写入 /var/log/containers/*.log)
    → Fluentd DaemonSet (tail + filter + match)
      → OCI日志服务 (通过HTTPS,认证:实例主体)

计划之外的是kubectl apply和OCI日志服务中第一条确认日志之间的8个错误。

错误1:OCI容器镜像仓库要求认证

OCI日志官方文档建议使用Oracle自己的容器镜像仓库镜像:

复制
container-registry.oracle.com/oci_logging/fluentbit

尝试在OKE节点上拉取此镜像时,kubelet返回认证错误。即使是公开镜像,Oracle容器镜像仓库也需要登录——在所有集群节点上为外部镜像仓库配置ImagePullSecrets并不是正确的方式。

修复:使用Docker Hub公开镜像仓库中的官方Fluent Bit镜像,无需认证:

复制
docker.io/fluent/fluent-bit:3.2

错误2:CRI-O拒绝短镜像名称

即使将镜像换为fluent/fluent-bit:3.2,kubelet仍然拒绝:

复制
short name mode is enforcing, but image name "fluent/fluent-bit:3.2"
returns ambiguous list of candidates

运行在OKE节点上的Oracle Linux 8.10将CRI-O配置为短名称强制模式——所有镜像名称必须完整指定镜像仓库。

修复:在manifest中所有镜像名称前添加docker.io/前缀:

复制
image: docker.io/fluent/fluent-bit:3.2

错误3:Fluent Bit 3.2没有oci_logging插件

Pod启动后,日志显示Fluent Bit无法加载发送到OCI日志服务所需的输出插件。oci_logging插件在Fluent Bit中不存在——它只存在于Fluentd的Ruby gem中。

修复:从Fluent Bit迁移到带有fluent-plugin-oci-logging gem的Fluentd。这需要基于官方Fluentd构建自定义镜像:

复制
FROM docker.io/fluent/fluentd:v1.17-debian-1
# 在后续步骤中安装gem...

错误4:构建失败——基础镜像中没有工具链

Fluentd基础镜像(debian)不包含C编译器。安装fluent-plugin-oci-logging gem时在编译原生扩展阶段失败:

复制
make: g++: No such file or directory
make[1]: *** [Makefile:234: <target>.o] Error 127

修复:在Dockerfile中gem安装之前添加build-essential

复制
FROM docker.io/fluent/fluentd:v1.17-debian-1

USER root
RUN apt-get update && apt-get install -y build-essential && rm -rf /var/lib/apt/lists/*
RUN gem install fluent-plugin-oci-logging                 fluent-plugin-kubernetes_metadata_filter                 fluent-plugin-parser-cri

错误5:Ruby 3.2中删除了File.exists?

安装gem后,Pod启动但立即崩溃:

复制
NoMethodError: undefined method 'exists?' for File:Class
/usr/local/bundle/gems/fluent-plugin-oci-logging-1.0.12/lib/fluent/plugin/os.rb

File.exists?方法在Ruby 3.2中被删除(自Ruby 2.1起已弃用)。fluent-plugin-oci-logging gem 1.0.12版本仍然使用旧方法,尚未更新。

修复:通过sed在Dockerfile中进行内联补丁:

复制
RUN sed -i 's/File\.exists?/File.exist?/g'     /usr/local/bundle/gems/fluent-plugin-oci-logging-*/lib/fluent/plugin/os.rb
检查gem的未来版本中是否已在上游修复了File.exists?。在gem更新之前需要此补丁。

错误6:创建缓冲区目录时权限被拒绝

Pod启动,gem正常工作——但Fluentd在初始化时挂起:

复制
Permission denied @ dir_s_mkdir - /var/log/fluentd-buffers

DaemonSet配置为以默认Fluentd用户(非root)运行。主机上的/var/log目录属于root,fluent用户没有写入权限。

修复:在DaemonSet中添加securityContext: runAsUser: 0,并将缓冲区移至/tmp/fluentd-buffers/

复制
spec:
  template:
    spec:
      securityContext:
        runAsUser: 0
      containers:
        - name: fluentd
          # 在fluent.conf中:
          # <buffer>
          #   path /tmp/fluentd-buffers/
          # </buffer>

注意:需要从主机读取/var/log/containers/的日志收集DaemonSet通常需要以root身份运行。这对于Fluentd和Fluent Bit等日志收集器是预期且已记录的行为。

错误7:摄取时404——Dynamic Group使用了错误的OCID

Pod运行,权限问题已解决——但摄取到OCI日志服务的尝试失败:

复制
NOT_AUTHORIZED_OR_NOT_FOUND (404) - Authorization failed or resource not found

Fluentd使用实例主体认证——OKE节点需要在具有OCI日志访问策略的Dynamic Group中。Dynamic Group创建时使用了以下规则:

复制
# 错误规则——使用OKE节点上不存在的标签
All {tag.Oracle-Tags.CreatedBy.value = '<集群OCID>'}

问题在于:OKE节点上的Oracle-Tags.CreatedBy标签包含的是节点池OCID,而不是集群OCID。同一区间中不同集群的节点共享相同的集群OCID——但节点池OCID是唯一的。使用错误的OCID导致Dynamic Group无法识别节点。

修复——最简单且最健壮的选项:使用instance.compartment.id而不是标签:

复制
# 正确规则——区间中的所有节点
All {instance.compartment.id = '<区间OCID>'}
使用instance.compartment.id比依赖节点池标签更简单、更健壮。如果集群重建或节点池替换,规则仍然有效。权衡是粒度:区间中的所有节点都进入该组——评估这在您的环境中是否可接受。

错误8:<auth>块破坏认证

修复Dynamic Group后,摄取日志显示关于fluent.conf中auth块的警告:

复制
[warn]: #0 unknown parameter 'auth' in <match>

fluent-plugin-oci-logging插件使用认证类型自动检测——它自动检测是否在OCI实例上运行并使用实例主体。添加显式<auth>块不仅不必要,还会干扰自动认证。

修复:从fluent.conf中完全删除<auth>块。插件通过实例主体自动处理认证。

复制
<match kubernetes.**>
  @type oci_logging
  log_object_id <日志OCID>
  # <auth> — 不要添加。插件使用自动检测。
</match>

结果:DaemonSet运行,11秒内收到第一条日志

解决所有8个错误后,DaemonSet在两个ARM64节点上无重启地启动:

复制
kubectl get pods -n logging
# fluentd-a1b2c   1/1   Running   0   5m
# fluentd-d3e4f   1/1   Running   0   5m

OCI日志中确认的第一条日志在Pod变为Running后11秒到达——恰好是fluent.conf中配置的10秒flush_interval加上网络延迟。

复制
# 第一条摄取的日志:
{
  "timestamp": "2026-04-16T18:21:23Z",
  "message": "Error: Loading chunk failed.",
  "stream": "stderr"
}
# 摄取时间:2026-04-16T18:21:34Z  (+11s)

8个错误和修复摘要

1. 镜像仓库需要认证 → 使用docker.io/fluent/fluentd:v1.17-debian-1(公开Docker Hub)

2. CRI-O拒绝短名称 → 所有镜像名称添加docker.io/前缀

3. Fluent Bit没有oci_logging → 迁移到Fluentd + fluent-plugin-oci-logging gem

4. 构建没有工具链 → 在Dockerfile中添加build-essential

5. Ruby 3.2删除了File.exists? → Dockerfile中的sed补丁

6. 缓冲区权限被拒绝 → runAsUser: 0 + 缓冲区在/tmp/fluentd-buffers/

7. Dynamic Group使用错误的OCID → 使用instance.compartment.id而不是集群/节点池标签

8. <auth>块干扰认证 → 删除——插件使用实例主体自动检测