公司动态
从 CrashLoopBackOff 到根本原因,只需几秒:使用 Elastic Observability 自动化 20 分钟的 Kubernetes 调查流程
作者来自 Elastic Bahubali Shetti正值你值班期间手机突然响起。CrashLoopBackOff。一个 Pod 卡在不断重启的循环中而现在时间开始倒计时。如果你做 SRE 已经有一段时间了你就知道接下来通常会发生什么。你确认告警打开可观测性工具然后开始这个流程打开集群仪表板找到命名空间找到 Pod检查重启次数切换到日志检查上游依赖是否出现问题与上周的情况进行比较然后在十几个标签页中逐渐拼凑出一个完整的情况。它确实有效但这是一个流程而时间就是在这个流程中一点点流失的。Elastic 全新的 Kubernetes Experience 改变了这个起点。当 CrashLoopBackOff 告警触发时一个调查工作流会自动与它同时运行。等你打开告警时证据已经收集完毕根本原因假设也已经在等着你。你不再面对一个空白的仪表板而是打开告警就能看到答案。或者至少你会得到一个非常明确的起点告诉你下一步应该去哪里查。本文将端到端地介绍一个典型的 CrashLoopBackOff 场景。接下来的章节将逐步解析 Elastic 的 UI 在每个步骤中展示的内容以及它为什么能够帮你节省时间。手动调查 CrashLoopBackOff每个 SRE 都会执行的六个步骤下面是一次常规 CrashLoopBackOff 调查的大致流程不包含 Elastic 的工作流你收到告警。某个 Pod 重启次数过多。你确定上下文。是哪个 Pod哪个命名空间哪个部署拥有它你分析情况。重启了多少次上一次终止的原因是什么——OOMKilled、存活探针失败还是错误的退出代码你进行分类。这是内存问题、配置问题、依赖问题还是调度问题你进行佐证。获取 Kubernetes 事件读取 Pod 日志检查上游服务是否先开始报错将当前行为与健康基线进行比较。你得出结论。到这时你才能形成假设并采取行动。这些步骤中的每一步都意味着一次查询、一次点击或一次上下文切换。单独来看它们没有任何一个很难。但在糟糕的夜晚它们加起来就是你根本没有的 20 分钟而且这 20 分钟里你做的还是上一次事件以及再上一次事件中做过的同样步骤。Elastic Kubernetes Experience 背后的理念很简单这个过程足够确定因此可以自动化。所以 Elastic 把它自动化了。从告警到根本原因只需几分钟Elastic 的 Kubernetes 集成提供了针对从定义上就属于异常状态的情况预构建告警规则模板不需要基线也不需要预热。处于 CrashLoopBackOff 状态的 Pod始终意味着存在问题因此当滚动时间窗口内的重启次数超过你配置的阈值时规则就会立即触发。下面是这个场景中的告警触发情况其中[Kubernetes OTel] Pod CrashLoopBackOff和OOMKilled containers规则都会针对otel-demo命名空间中的recommendation组触发告警本身由 ES|QL 查询定义因此它是透明且可调节的你可以准确查看触发告警的条件并根据你的环境调整阈值。而它的操作正是本文接下来内容得以实现的关键每当新告警触发时该规则都会立即针对每个告警运行K8s CrashLoopBackOff Investigation (OTel)工作流。如果你需要回顾告警库以及这些模板的工作方式请参阅第 1 部分。在这个场景中该规则针对otel-demo命名空间中的recommendationPodrecommendation-788dc88c6c-56w74触发。当你打开告警时Elastic 的 AI Agent 已经在总结发生了什么无需再深入查找规则详情但告警触发只是整个故事的一半。与告警关联的是一个Kubernetes 调查工作流技术预览版它由一系列步骤组成的有向图构成并会在告警触发的瞬间立即启动。当你的手机还在响的时候工作流已经开始查询你的集群根据查询结果进行分支并综合得出答案。深入调查工作流究竟做了什么该工作流模拟了一名经验丰富的 SRE 手动执行的确切流程只不过它可以在几秒钟内完成而且不会记录任何无法用证据支持的内容。对于我们的 CrashLoopBackOff 场景它采取了以下路径。第 1 步工作流首先检查崩溃 Pod 的什么信息工作流查询 Kubernetes 指标包括重启次数、上一次终止原因以及资源使用量与 Pod 声明的限制之间的情况。**结果**上一次终止原因是OOMKilled重启次数为7。查询时内存使用量数据恰好不可用但OOMKilled原因是确定性的容器每次启动时都会因为超过内存限制而被内核终止然后立即重新启动。OOMKilled终止原因决定了后续的所有操作。工作流会进入内存调查路径而不是在非内存崩溃情况下所采用的日志调查路径。第 2 步工作流如何区分内存泄漏和负载突增ML 异常检查是区分一次优秀调查和一次快速但错误调查的关键步骤。OOMKilled并不自动意味着“内存泄漏”。工作流不会从头开始重新计算内存趋势而是查询 ML 异常索引检查该 Pod 是否存在活跃的k8s_pod_memory_growth异常。结果没有发现异常。内存突增被判定为由负载驱动而不是疑似内存泄漏。基于前几天建立的 ML 基线没有发现内存泄漏所特有的缓慢、持续增长趋势而是发现了一次与真实流量相符的突增。区分由负载驱动的内存突增和真正的内存泄漏需要人工花费几分钟并进行大量判断。之所以工作流能够做到这一点是因为第 1 部分中的异常检测作业已经在后台持续学习工作负载的基线。第 3 步故障是否正在扩散到其他 Kubernetes 服务发生崩溃的 Pod 往往是一个症状而不是原因同时它也可能在下游造成问题。因此工作流通过 APMservice_destination聚合数据枚举该 Pod 的依赖项并将当前错误率和延迟与基线进行比较。一个 AI 分类步骤会判断故障是否正在扩散。**结果**唯一的直接调用方是frontend服务它对 recommendation 服务的请求仅受到0.14% 的错误率影响并且没有其他服务相对于基线超过其降级阈值。影响范围被限制在 recommendation 服务没有明显的下游级联故障。问题局限于这个 Pod。第 4 步命名空间中最近的变更是否导致了崩溃循环最后工作流扫描命名空间事件日志。它发现从大约18:51 到 18:54 UTC持续运行的Pulled → Created → Started → Killing → BackOff循环这是告警触发时正在发生的活跃崩溃循环的典型特征。没有发生任何运营层面的变更这是一个持续存在的资源问题。CrashLoopBackOff 根本原因假设是什么样的当你打开告警时首先看到的就是ROOT CAUSE HYPOTHESIS (confidence: high) The recommendation service pod (recommendation-788dc88c6c-56w74) is in a crash-loop caused by repeated OOMKilled terminations. The pod has restarted 7 times and Kubernetes events confirm a continuous BackOff/restart cycle since at least 18:51 UTC. Memory utilization data was unavailable at query time, but the OOMKilled termination reason is definitive: the container is exceeding its configured memory limit on each startup, being killed by the kernel, and immediately restarting. No memory leak was detected by ML anomaly analysis, indicating the memory pressure is load-driven — the containers memory limit is simply insufficient for the current request volume. The frontend service (the sole direct caller) is absorbing the impact with a 0.14% error rate on the recommendation service itself, but no significant downstream cascade is observed. EVIDENCE - Pod restarted 7 times; last termination reason: OOMKilled — container is consistently exceeding its memory limit - ML memory anomaly check: no anomaly found; memory spike assessed as load-driven, not a leak - Blast radius is isolated to the recommendation service; no other service exceeds degradation thresholds relative to baseline - Continuous BackOff events from 18:51–18:54 UTC confirm active crash-loop at alert time PROBABLE CAUSE: The recommendation containers memory limit is too low for current traffic load, causing repeated OOMKilled terminations and a crash-loop backoff. RECOMMENDED NEXT STEPS 1. Immediately increase the memory limit (and request) for the recommendation container in its Deployment spec to provide headroom above the observed peak usage, then redeploy to break the crash-loop. 2. Profile the recommendation service under representative load to determine the actual memory working set and set a right-sized limit with a safe buffer (e.g., 20–30% above peak observed). 3. Add a Kubernetes HorizontalPodAutoscaler or VPA policy for the recommendation service so memory resources scale with traffic rather than requiring manual intervention.从值班工程师的角度再看一遍。你收到了告警。你打开了告警。而告警并没有丢给你一堆日志和一个仪表板它交给你的是一个经过校准的根本原因假设并附有证据以及明确列出的后续操作。“旧方式”中的六个手动步骤已经完成。你现在的工作是做出决定而不是埋头查找。这就是时间节省的真正来源不是让每次查询少花几秒钟而是将整个调查过程中的信息搜寻工作从关键路径中彻底移除。Elastic Observability 如何避免将 OOMKilled 误诊为内存泄漏如果答案是错误的那么速度毫无价值因此值得关注的是工作流是如何避免这些经典误诊的。它将经验丰富的 SRE 会本能应用的推理过程编码了进去OOMKilled并不自动意味着内存泄漏。在得出内存泄漏结论之前它会先与 7 天基线进行比较。在这里正是这一检查将“应用程序正在泄漏内存”纠正为“实际负载下的内存限制设置过小”。共同出现的症状并不意味着因果关系。它会明确检查上游是否先出现降级然后再判断应该归咎于上游还是排除上游。没有证据并不等于证据缺失。如果查询返回零行它会报告“没有可用数据”而不是凭空编造一种故障模式。它会诚实地说明置信度。假设会标记为high、medium或low。当有两种故障模式都符合现有证据时工作流会同时列出两种并说明它认为哪一种是根本原因以及为什么。制造虚假的确定性本身就会被视为调查失败。这与 Elastic 的observability-k8s-investigationSkill 中编码的诊断流程相同。该故障模式分类体系涵盖 16 种不同的 Kubernetes 故障模式从 OOMKilled 和 CPU 限流一直到调度和网络问题。更多内容请参阅第 2 部分。还想再确认一下仪表板、Discover 和 APM工作流会直接给你答案。但一个优秀的根本原因分析工具也应该让你能够轻松地验证这个答案因为有时你就是想亲眼看看有时工作流返回的是medium置信度这时你需要自己补上这一环。工作流进行推理时使用的所有数据你都可以直接访问。仪表板 —— 直观确认重启级联。Kubernetes 仪表板专为逐层深入调查而构建。从集群的概览开始在这里“按容器重启次数排名的顶级命名空间”会一眼显示出问题。点击进入标记的命名空间然后找到导致重启的 Pod。Pods视图会标记recommendationPod 中的容器重启并随着时间绘制内存使用量与请求值和限制值的对比情况——你会看到工作集内存正好逼近限制值与工作流描述的情况完全一致。从集群到容器大约只需要四次点击。Discover——读取原始证据。Pod 详情仪表板会直接链接到 Discover 中经过关联的 Pod 日志和事件。在这里你可以从原始日志和事件流中确认OOMKilled事件以及重启频率如果你想以不同方式切分数据也可以运行自己的 ES|QL 查询。APM —— 验证影响范围确实受到了限制。工作流发现影响范围被限制在 recommendation 服务frontend唯一调用方承受了 0.14% 的错误率。你可以在 APM UI 中独立验证这一点打开服务地图检查事件时间窗口内调用方的延迟和错误率然后自行与每周基线进行比较。重点并不是说你必须完成这些操作而是工作流得出的结论完全可审计。你信任它时它可以快速给出结果当你想进行检查时它又足够透明。从你的 IDE 进行同样的调查MCP App并不是每次调查都从 Kibana 告警开始。有时开发人员只是在编辑器中问一句“为什么这个服务会崩溃”Elastic 的Observability MCP App技术预览版将相同的遥测数据以及相同的调查工作流作为 AI 可调用的工具提供并可以在你的聊天或 IDE 中直接以内嵌方式渲染交互式视图无需切换到 Kibana。对于我们的 CrashLoopBackOff 场景如果使用 Claude Desktop 或 VS Code 等兼容 MCP 的客户端流程如下“哪里出问题了”→ 集群健康汇总会在一个内嵌视图中返回整体健康状态标记、发生降级的服务、内存使用量最高的服务以及 Kubernetes 详细情况CPU、内存、重启次数、节点。在这里它将集群标记为严重状态其中payment、cart、frontend和frontend-proxy处于降级状态。“recommendation Pod 是否存在异常”→ 内存分析视图确认这次突增是由负载驱动的而不是内存泄漏——发生崩溃的788dc88c6cPod 报告的内存数据为null它们崩溃得太快来不及生成采样数据而健康 Pod 的内存使用量稳定在 45MB这与工作流所使用的 ML 结果完全一致。“为什么 recommendation 服务会崩溃”→ agent 会返回你在告警中看到的相同结构化根本原因分析并以内嵌方式呈现内存限制设置得低于容器启动所需的内存ReplicaSet 已经间歇性地发生 OOM 数周并给出具体的缓解措施先回滚然后修复内存限制整个过程无需离开编辑器。相同的证据相同的根本原因无论你在哪里工作都能直接获得。有关 MCP App 视图和架构的完整介绍请参阅第 2 部分。从收到告警到做出决策完全跳过 Kubernetes 调查流程这里的变化并不是“更好的仪表板”而是改变了你收到告警后要做什么。以前告警是调查的起点。你收到通知然后开始寻找答案。现在告警到来时调查已经完成证据已经收集错误方向已经排除经过校准的假设已经形成后续步骤也已经准备就绪。你可以直接从“收到通知”进入“做出决策”同时完整保留仪表板、Discover 和 APM 中的调查记录随时可以进行验证或深入调查。对于单次事件来说这只是节省了几分钟。但如果放到一个季度的所有值班轮次中再考虑每一位不再需要在凌晨 3 点重复执行同样六个步骤的工程师这就意味着真正节省下来的时间以及大幅减少的告警疲劳。亲自试试看你不需要等到生产环境发生事件才能看到这一点。OpenTelemetry Astronomy Shop演示环境提供了一个功能开关服务可以让你按需触发故障场景。启用购物车/结账故障观察重启级联展开CrashLoopBackOff 告警规则就会触发而调查工作流也会紧随其后运行。开始设置安装 Kubernetes 集成——仪表板会立即可用。第 1 部分开始使用部署数据采集——通过 EDOT CollectorOpenTelemetry或独立的 Elastic Agent两者都基于 Helm。启用告警规则模板——在 Observability Alerts 中启用 CrashLoopBackOff 等规则并连接你的通知渠道。让 ML 模块预热——等待 24–48 小时让异常基线准备就绪以便在需要时使用。启用调查工作流技术预览版——从 Workflows 页面导入 Kubernetes Crashloop Investigation Workflow并将其配置为由告警触发。第 2 部分开始使用安装 MCP App技术预览版——在你喜欢的 agentic 客户端上安装将调查带入你的 IDE。你现在是否正在 Elastic 上运行 Kubernetes告诉我们你在每次事件中仍然需要手动重复执行哪些调查步骤以及哪些修复措施是你愿意让工作流提出的。欢迎加入Elastic Community Discussion。本文中所描述的任何功能或特性的发布时间和发布情况均由 Elastic 自行决定。目前尚未提供的任何功能或特性可能无法按时交付甚至可能完全不会交付。原文CrashLoopBackOff to root cause: automate Kubernetes triage — Elastic Observability Labs