排障助手先给证据,再给动作
Kubernetes 现场信息变化很快,助手应先把它引用的 Pod 状态、事件时间和日志片段列出来,再说明为什么建议某一步。它可以帮助缩小范围,不能在没有人工确认时删除、扩容或重启工作负载。特别是 OOM、节点异常这类问题,单条日志很容易误导判断。
上下文采集也要有限度。只取目标命名空间和必要时间窗,避免把整集群配置、凭证或无关租户日志一起送入检索链。
容器集群智能排障的适用性评审
遇到 NodeNotReady 或跨可用区网络拥塞时,直接将完整的kubectl get po -o yaml交给模型分析,可能得到未经验证的 YAML 或高风险操作建议。模型输出应当只作为诊断线索,不能替代变更评审。
AI 不能替代 Kubernetes 的确定性诊断路径。多数运行时故障都有可观察的状态和日志信号;不加约束地引入 LLM 会增加调用成本、延迟和误操作风险。引入 AI 辅助排障前,应先划清智能检索与上下文编排的边界。
1. 适用边界:K8s 运维中 AI 的“甜点区”与“禁飞区”
到底什么时候该用 AI?什么时候该死守确定性脚本?我们用一张决策矩阵表来划清界限:
适合 AI 处理的“甜点区”
- 海量异构日志的语义检索:当包含上千个微服务的日志流集中在 ES/Loki 中时,用自然语言提取“过去 1 小时内由于 DNS 丢包导致的数据库重连失败异常”。
- 故障上下文摘要与知识增强:结合公司内部的 SRE Wiki 知识库(RAG),将当下的 Pod 异常事件与历史 Post-Mortem 进行匹配,生成诊断思路。
严禁 AI 主导的“禁飞区”
- Pod 状态机变更:例如
OOMKilled、CrashLoopBackOff。此类故障原因极其明确(cgroup 内存超限或进程退出码非 0),直接通过kubectl describe和 Kubelet 日志就能定位,死套大模型纯属浪费时间。 - 集群核心组件配置变更:涉及 Etcd 集群扩缩容、CoreDNS Upstream 变更等,必须依靠 GitOps 和确定性 Terraform/Ansible 交付。
2. 上下文编排:只保留诊断所需字段
如果你直接把kubectl get pod <pod-name> -o yaml(通常包含几百行冗余的managedFields和状态历史)塞给 LLM,不仅会迅速刷爆 Token 窗口,还会让模型淹没在垃圾信息中。
一个合格的 K8s AI 上下文编排器,必须在探针侧完成结构化降噪与确定性提取:
3. 生产级上下文提取与 RAG 组装代码
下面的 Python 代码演示了如何构建一个针对 K8s 异常 Pod 的确定性上下文提取与 RAG 向量准备器:
import re import json from typing import Dict, Any, List class KubernetesContextCompressor: def __init__(self, max_log_lines: int = 50): self.max_log_lines = max_log_lines self.sensitive_patterns = [ (r'bearer\s+[a-zA-Z0-9\-\._~\+\/]+=*', '[REDACTED_TOKEN]'), (r'password["\']?\s*:\s*["\']?[^"\'\s]+', 'password: "[REDACTED]"'), ] def sanitize_text(self, text: str) -> str: """敏感凭证与私密信息正则脱敏""" for pattern, repl in self.sensitive_patterns: text = re.sub(pattern, repl, text, flags=re.IGNORECASE) return text def compress_pod_object(self, raw_pod: Dict[str, Any]) -> Dict[str, Any]: """精简 Pod YAML,剔除系统元数据冗余,节省 90% Token""" metadata = raw_pod.get("metadata", {}) status = raw_pod.get("status", {}) spec = raw_pod.get("spec", {}) # 剔除无用的元数据 metadata.pop("managedFields", None) metadata.pop("ownerReferences", None) metadata.pop("annotations", None) # 提取容器状态关键指标 container_statuses = [] for cs in status.get("containerStatuses", []): container_statuses.append({ "name": cs.get("name"), "ready": cs.get("ready"), "restartCount": cs.get("restartCount"), "state": cs.get("state"), "lastState": cs.get("lastState") }) compressed = { "name": metadata.get("name"), "namespace": metadata.get("namespace"), "nodeName": spec.get("nodeName"), "phase": status.get("phase"), "reason": status.get("reason"), "containerStatuses": container_statuses, "conditions": status.get("conditions", []) } return compressed def build_prompt_context(self, pod_json: Dict[str, Any], events: List[str], logs: str) -> str: """组装最终送入 LLM 的 Prompt""" clean_pod = self.compress_pod_object(pod_json) clean_logs = self.sanitize_text(logs) prompt = f"""[K8s 诊断任务] 你是一个 K8s 诊断助手。请根据提供的精简上下文分析 Pod 异常原因。 ### 1. Pod 状态信息 {json.dumps(clean_pod, indent=2, ensure_ascii=False)} ### 2. 最近关键事件 (Events) {json.dumps(events, indent=2, ensure_ascii=False)} ### 3. 容器异常日志摘要 (Last {self.max_log_lines} Lines) {clean_logs} ### 输出要求: 1. 给出 Top-1 最可能的根因。 2. 给出 2 条只读复核命令(例如 kubectl describe/get)。 严禁生成删除集群资源的命令! """ return prompt if __name__ == "__main__": compressor = KubernetesContextCompressor() sample_pod = { "metadata": { "name": "cart-service-v1-abc12", "namespace": "shop", "managedFields": [{"manager": "kube-controller-manager", "fields": "..."}], "annotations": {"kubectl.kubernetes.io/last-applied-configuration": "..."} }, "spec": {"nodeName": "node-worker-03"}, "status": { "phase": "Failed", "containerStatuses": [{ "name": "cart-app", "ready": False, "restartCount": 5, "state": {"terminated": {"exitCode": 137, "reason": "OOMKilled"}} }] } } events = ["Warning OOMKilling 2m ago kubelet, node-worker-03 System OOM killed process 4123 (cart-app)"] logs = "2026-08-22 10:00:12 [ERROR] Out of memory: Java heap space... Authorization: Bearer secret-token-12345" final_prompt = compressor.build_prompt_context(sample_pod, events, logs) print(final_prompt)4. 现场实战排障与命令组合
面对复杂集群故障,先用命令行工具确认现象,再验证 AI 辅助分析程序的准确性。
1. 现场抓取 Containerd 容器错误日志与资源限制
首先定位是否为 cgroup 限制触发的物理打爆:
# 查看目标 Pod 所在的 Worker 节点 kubectl get po cart-service-v1-abc12 -n shop -o jsonpath='{.spec.nodeName}' # 登入 Worker 节点使用 crictl 查看容器运行时底层状态 crictl inspect --output json c7f8a9b0c1d2 | jq '.info.runtimeSpec.linux.resources.memory' # 检索节点内核层面的 OOM 杀死记录 dmesg -T | grep -i "killed process"2. 验证智能 RAG 知识检索系统
在本地触发针对本地 SRE Wiki 的向量检索,确认是否有类似历史故障记录:
# 调用本地嵌入式 vector 搜索 API 校验答案 curl -X POST http://sre-rag-knowledge.internal/v1/search \ -H "Content-Type: application/json" \ -d '{ "query": "Java Pod exit code 137 exit state terminated", "top_k": 2 }'输出的知识库匹配示例:
{ "matches": [ { "title": "SRE-SOP-2025-09: Java 服务未配置 -XX:MaxRAMPercentage 导致的容器 OOM 诊断规程", "score": 0.91, "recommendation": "在 Deployment env 中显式设置 JAVA_TOOL_OPTIONS: -XX:MaxRAMPercentage=75.0" } ] }5. 避免“AI 运维陷阱”的三条铁律
- 拒绝“闭眼复制命令”:AI 生成的所有
kubectl指令必须在只读模式下打印出来。必须禁止 AI 生成kubectl delete、kubectl apply -f或带-o yaml的全量修改命令直接落地执行。 - 警惕冷门 CRD 的“胡言乱语”:对于企业内部自研的 Custom Resource Definition(如
VirtualApp或TrafficPolicy),通用大模型根本没有训练数据。如果没有配合专有的 CRD Schema 注入,LLM 一定会瞎编字段。 - 把预算用在复杂关联上:简单的容器状态和资源阈值可先由规则处理。只有多项信号相互矛盾、告警难以归并时,再调用模型收拢上下文;是否值得调用,应由延迟、成本和人工复核结果共同决定。