适用范围与版本边界
本文面向 Linux 节点上的 Kubernetes 容器标准输出日志,经 Fluent Bit 采集后进入 Elasticsearch/Kibana 的链路。应用写入自定义文件、Sidecar 转发、托管日志服务以及 Windows 节点需要另核对路径和保留方式。Kubernetes 部分使用稳定的 get、logs 读取接口;Fluent Bit 的 Tail、缓冲和重试配置必须以实际镜像版本对应的官方手册为准。本文未部署测试日志或执行真实集群变更,状态为待验证。
前提与最小证据集
取得目标集群、命名空间、Pod UID、容器名、节点名、采集器名称以及日志平台只读权限。预先确认故障时间的时区、应用事件时间与平台接收时间是否分别保存。优先挑选已有的一条非敏感业务事件,以事件 ID、请求 ID、序号和内容摘要联合辨认;仅用“相同时间、相同文本”可能把正常重复业务误判为重复投递。
示例中的 REPLACE_WITH_... 必须替换为已确认对象。不要查询 Secret、打印全部环境变量,或把包含用户信息的完整日志粘贴到公开工单。所有读取都限定窗口和行数,不在此流程启用 debug 日志或创建探针 Pod。
第一步:固定源 Pod 身份与日志窗口
kubectl config current-context
OPS_CONTEXT='REPLACE_WITH_CONTEXT'
OPS_NAMESPACE='REPLACE_WITH_NAMESPACE'
OPS_POD='REPLACE_WITH_POD'
OPS_CONTAINER='REPLACE_WITH_CONTAINER'
kubectl --context "$OPS_CONTEXT" -n "$OPS_NAMESPACE" get pod "$OPS_POD" -o wide
kubectl --context "$OPS_CONTEXT" -n "$OPS_NAMESPACE" get pod "$OPS_POD" \
-o jsonpath='{.metadata.uid}{"\n"}{.status.containerStatuses[*].restartCount}{"\n"}'
kubectl --context "$OPS_CONTEXT" -n "$OPS_NAMESPACE" logs "$OPS_POD" \
-c "$OPS_CONTAINER" --since=30m --tail=200 --timestamps=true先核对 UID 和容器,避免把同名重建 Pod 的日志混为一份。若发生重启,再按同一目标执行:
kubectl --context "$OPS_CONTEXT" -n "$OPS_NAMESPACE" logs "$OPS_POD" \
-c "$OPS_CONTAINER" --previous --tail=200 --timestamps=true--previous 读取上一次容器实例,不是所有历史归档;kubectl logs 也不提供所有已轮转文件。因此“这里没有事件”不能单独证明应用没有输出,需要结合原始文件保留情况、应用侧记录和重启时间判断。Kubernetes 日志架构 说明了这些边界。
第二步:确认采集器确实覆盖目标节点
OPS_LOG_NAMESPACE='REPLACE_WITH_LOG_NAMESPACE'
OPS_AGENT_DAEMONSET='REPLACE_WITH_DAEMONSET'
OPS_AGENT_POD='REPLACE_WITH_AGENT_POD_ON_TARGET_NODE'
OPS_AGENT_CONTAINER='REPLACE_WITH_AGENT_CONTAINER'
kubectl --context "$OPS_CONTEXT" -n "$OPS_LOG_NAMESPACE" get daemonset "$OPS_AGENT_DAEMONSET" -o wide
kubectl --context "$OPS_CONTEXT" -n "$OPS_LOG_NAMESPACE" get pod "$OPS_AGENT_POD" -o wide
kubectl --context "$OPS_CONTEXT" -n "$OPS_LOG_NAMESPACE" logs "$OPS_AGENT_POD" \
-c "$OPS_AGENT_CONTAINER" --since=30m --tail=200 --timestamps=true把采集器 Pod 的节点与源 Pod 的节点一一核对,再检查采集器重启、资源限制、挂载和实际配置版本。DaemonSet 总体 Ready 不代表每一个业务节点都被覆盖;节点选择器、污点容忍与不可调度状态可能留下空白。使用已有管理视图读取指定工作负载配置,不扩大到全命名空间敏感清单导出。
第三步:检查 Tail 路径、检查点与解析
对已批准的配置副本逐项核对 Path、排除规则、CRI/多行解析器、Tail 的 DB 路径和持久化方式。确认挂载覆盖实际日志路径,而不只覆盖表面上的符号链接。检查业务换节点、采集器重建和镜像升级时,检查点是否仍对应原文件身份。
Tail 数据库保存读取位置,不同 Tail 输入应有独立数据库;检查点丢失时,读取从哪里开始与 read_from_head 等配置有关。路径模式如果同时匹配原文件和轮转文件,可能重复读取。不要通过删除数据库“重置状态”,也不要在运行中的数据库上执行写入或修复命令。Fluent Bit Tail 手册 解释了检查点和轮转行为。
若原始记录存在而解析后字段消失,核对 CRI 前缀、多行拼接、时间解析失败以及过滤规则。保留脱敏前后的单条样本对照,尤其要检查异常堆栈是被合并为一条还是拆成多条,不能简单比较行数。
第四步:区分积压与不可恢复缺口
从已有指标和有限采集器日志观察输出连接错误、认证失败、限流、重试、暂停输入及缓冲占用。对比源端产生量、采集器接收量、成功输出量和后端可检索量;这些计数的统计单位、过滤位置和重启归零行为不同,不能直接相减当作精确丢失数。
文件系统缓冲并非无限保留;为某个输出设置的 storage.total_limit_size 会限制该目的地的逻辑队列,达到上限有丢弃旧块风险。内存缓冲、输入暂停和节点日志轮转也要联动评估。Fluent Bit 缓冲手册 说明相关容量边界。不要在事故中直接把上限无限调大,先核对节点剩余空间、增长速度和恢复吞吐。
第五步:在后端核对同一事件
使用 Kibana 只读检索,明确数据视图、集群、命名空间、Pod UID、容器及时间字段;先以业务事件 ID 精确搜索,再检查收集时间和事件时间。搜索窗口应覆盖实测时钟偏差与排队延迟。一个索引里查不到不等于所有目标都没收到,应核对路由、字段解析、索引别名和保留策略,但不运行全库无界聚合。
出现重复时,对每份记录比较源事件 ID、Pod UID、原始时间、采集器标识和后端文档 ID:源端就重复,交由应用排查;同一源事件经两个采集路径出现,核对重复 DaemonSet、Sidecar 和路径重叠;重试后出现多个后端 ID,检查输出幂等设计。传输成功确认丢失时可能重投,“恰好一次”需要整条链路证明,不能只依赖采集器配置。
判断分支与处置边界
- 源文件仍在、采集器积压增长、后端延迟扩大:优先排查目的地可用性和吞吐,标记为待追平,不提前宣称丢失。
- 源文件已轮转清除、缓冲也无可恢复记录:记录缺口范围和证据不足,交由负责人确认是否有应用审计或归档副本。
- 检索时间字段或路由错误:修订查询条件后复查,区分“未被采集”与“未被找到”。
- 只有部分节点或重建后发生:聚焦节点覆盖、挂载和检查点生命周期,不先重启所有采集器。
验收、停止与恢复边界
验收选择多个已有事件,覆盖故障前、故障中和恢复后,记录可检索延迟、唯一事件数、重复份数和仍未知的缺口。若需生成新探针事件、重放归档或调整配置,应另获授权,约定副作用、重复治理和回退版本。禁止在诊断期间删除 Tail 数据库、清空缓冲、删除索引或修改日志保留设置。若读取给 API Server、节点或搜索集群带来明显压力,立即减少窗口并停止并发查询;只读诊断本身无配置恢复步骤。
案例证据记录模板
- 事件编号、实际版本、集群和目标 Pod UID、节点、时间窗口:待填。
- 脱敏事件 ID 与源端存在证据、采集器处理证据、后端检索证据:待填。
- 重启与轮转时间、检查点存储、缓冲趋势、输出错误:待填。
- 结论分类:查询遗漏、延迟积压、确认缺口、重复采集或证据不足。
- 缺口估算方法、置信边界、负责人、授权处置与复查结果:待填。
模板不包含假设的成功结果;无法证明的链路阶段明确标注未知。