关于 troubleshoot-ssi
用于排查 Kubernetes 上 Datadog Single Step Instrumentation(SSI)的技能,适合诊断未注入或缺少 Trace 的情况。它结合集群状态检查与 Datadog 后端诊断,并依据观测信号引导调查。
主要功能
- 01检查 Pod 注入与 Webhook 状态
- 02查询 Trace 和追踪器遥测
- 03查看后端注入错误
- 04根据诊断信号分析原因
适用场景
- 01调查未被注入的 Pod
- 02诊断 Datadog Trace 缺失
- 03跟进 SSI 验证失败
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ datadog-labs/ agent-skills --skill troubleshoot-ssi安装后在 Claude Code 中输入/troubleshoot-ssi确认已加载。
详细介绍
排查 Kubernetes 上的 APM SSI
触发条件
当用户表达以下意图时,调用此技能:
- 调试 Pod 未被插桩的原因
- 调查 Datadog 中未显示追踪的原因
- 诊断准入 Webhook 或 init 容器注入失败
- 跟进
verify-ssi的失败检查 - 报告某个特定服务或 Pod 没有追踪
如果以下情况成立,请勿调用此技能:
- 尚未启用 SSI——请先运行
enable-ssi
前提条件
- 已配置 kubectl,使其指向目标集群 —
kubectl config current-context
pup-cli:检查、安装并进行身份验证
Claude 运行
pup --version
如果未找到,请根据操作系统安装:
Claude 运行
if [[ "$(uname)" == "Darwin" ]]; then
brew tap datadog-labs/pack && brew install pup
else
PUP_VERSION=$(curl -s https://api.github.com/repos/datadog-labs/pup/releases/latest | grep '"tag_name"' | cut -d'"' -f4)
curl -L "https://github.com/datadog-labs/pup/releases/download/${PUP_VERSION}/pup_linux_amd64.tar.gz" | tar xz -C /usr/local/bin pup
chmod +x /usr/local/bin/pup
fi
pup --version
检查身份验证:
pup auth status
如果尚未通过身份验证:
Claude 运行
pup auth login
这会打开浏览器标签页以进行 OAuth。请在其中完成登录——命令退出后,Claude 会继续执行。
如果无法使用浏览器:export DD_APP_KEY=<your-app-key>。
操作前需要确定的上下文
| 变量 | 确定方式 |
|---|---|
AGENT_NAMESPACE | 安装 Datadog Agent 的命名空间 |
APP_NAMESPACE | 缺少追踪的应用所在的命名空间 |
CLUSTER_NAME | kubectl config current-context 或 datadog-agent.yaml 中的 spec.global.clusterName |
SERVICE_NAME | Deployment 上的 tags.datadoghq.com/service 标签,或询问用户 |
ENV | Deployment 上的 tags.datadoghq.com/env 标签,或询问用户 |
POD_NAME | kubectl get pods -n <APP_NAMESPACE>——使用用户提到的特定 Pod |
DEPLOYMENT_NAME | 检查 Deployment 清单中的 metadata.name,或询问用户 |
APP_LABEL | 检查 Deployment 清单中的 spec.selector.matchLabels.app |
SSI 的工作原理 — 领域知识
调查前请先阅读。本节介绍用于分析新型故障的思维模型,而不只是已知故障。
注入链:
- 准入 webhook(由 Cluster Agent 注册)拦截 Pod 创建
- Webhook 修改 Pod 规格 — 添加一个
datadog-lib-<language>-initinit 容器 - Init 容器将追踪器库下载到共享卷
- 设置
LD_PRELOAD环境变量,使其指向库.so文件 - 应用进程在启动时通过
LD_PRELOAD自动加载该库
各诊断层能看到什么:
- pup — 可以看到 Datadog 后端收到的内容。无法看到集群侧注入故障。如果 pup 中没有该服务的追踪器遥测数据,说明追踪器要么从未注入(集群侧问题 — 通过 kubectl init 容器检查确认),要么已注入但尚无法上报(连接问题、DD_SITE、API 密钥或遥测延迟)。不要直接假定是集群问题;请交叉检查 kubectl。
- kubectl — 可以看到集群状态。无法确认数据是否已到达 Datadog。如果 kubectl 显示存在 init 容器,但 pup 中没有追踪数据,问题发生在注入之后。
健康状态应呈现如下:
pup fleet tracers list显示该服务处于活跃状态,且语言符合预期kubectl get pod -o jsonpath='{.spec.initContainers[*].name}'的结果包含datadog-lib-<language>-init
已知的静默故障 — 发生以下情况时,SSI 不会报错:
- 已有 ddtrace 或 OTel 插桩 — SSI 会检测到它并静默禁用自身
- 不支持的运行时版本 — 静默跳过
admission.datadoghq.com/enabled: "false"注解 — webhook 会完全跳过该 Pod- 启用 SSI 后未重启 Pod — 注入发生在启动时;现有 Pod 会继续运行,但未启用插桩
- Pod 位于 Agent 命名空间 — SSI 从不会对其自身命名空间进行插桩
推理捷径:
- 没有 init 容器 → webhook 未触发 → 检查:命名空间目标、pod-selector、退出注解、webhook 注册、Pod 未重启
- 存在 init 容器但没有追踪数据 → 检查
pup fleet tracers list中是否有该服务:不存在 → 追踪器未上报(Agent 连接、DD_SITE 不匹配、API 密钥、出口流量受阻;或追踪器从未加载 — 已有 ddtrace/OTel、不支持的运行时);存在 → 遥测数据已上报,但 span 未到达(没有流量、采样、摄取/保留过滤器)
步骤 1:分诊
同时运行以下七项,并向用户展示正在运行的诊断。此后的所有操作都由此处的检查结果决定。获得 Pod 名称后,通过 kubectl get pod <POD_NAME> -n <APP_NAMESPACE> -o jsonpath='{.spec.nodeName}' 解析 <NODE_HOSTNAME>;如果尚无 Pod 上下文,先运行不带 --hostname 的 pup 命令。
Claude 运行
pup traces search --query "service:<SERVICE_NAME>" --from 1h --limit 5
pup fleet tracers list --filter "service:<SERVICE_NAME>"
pup apm troubleshooting list --hostname <NODE_HOSTNAME> --timeframe 1h
pup apm service-library-config get --service-name <SERVICE_NAME> --env <ENV>
kubectl get pod <POD_NAME> -n <APP_NAMESPACE> \
-o jsonpath='{.spec.initContainers[*].name}'
kubectl describe pod <POD_NAME> -n <APP_NAMESPACE> | grep -A 10 "Events:"
kubectl get mutatingwebhookconfigurations | grep datadog
最后一条命令用于确认 Admission Controller webhook 已在整个集群范围内注册 — 这是 SSI 注入正常工作的前提条件,即使其他大多数服务都已启用插桩,也必须检查这一项(任何一个 webhook 配置出现偏差,都可能导致一部分 Pod 被静默跳过)。
pup apm troubleshooting list 会显示 Datadog 后端从集群收到的注入错误。这些错误指向集群侧的修改故障,单靠 kubectl describe 可能无法发现。pup apm service-library-config get 会显示追踪器所使用的运行时 SDK 配置;意外的取值可能表明存在 UST/配置传播问题。此视图不会列出每个 SDK 的所有设置,因此若缺少某个值,请在断定配置未传播前,先使用 verify-ssi 步骤 3 中的命令检查 Pod 环境变量。
展示调查结果(必需)
最终回复就是交付内容,而不是调查记录。回复必须包含这项技能中你已运行或适用的每一项诊断,并说明每项诊断的用途和发现。请避免以下三种失误:
-
运行检查却不报告。 如果你在调查期间运行了
kubectl get mutatingwebhookconfigurations、命名空间admission.datadoghq.com/mutate-pods标签检查或其他任何命令,都必须在回复中说明命令及其结果。运行了检查却不展示,读者就一无所知;尤其必须明确列出命名空间标签检查和 Webhook 检查。 -
遗漏两项必需的 pup 诊断。 对每个受影响的服务,每次诊断都必须明确包含以下两条命令,逐条列出;这是必需的分诊输出,而非可选项:
pup apm troubleshooting list --hostname <NODE_HOSTNAME>— 显示 Datadog 从节点收到的注入错误pup apm service-library-config get --service-name <SERVICE_NAME> --env <ENV>— 显示追踪器的运行时 SDK 配置
如果
pup可用,就运行这些命令;如果不可用,就建议用户运行。如果不知道<ENV>,请说明你假定的值,并照常运行命令。不要用pup traces search代替;这是另一项检查,不能满足运行手册要求。 -
找到第一个根因就停止。 如果有多个服务受影响,请分别调查和报告;它们的原因可能不同,并且应针对每项服务分别给出修复措施。
步骤 2:陈述你的假设
调查前,请根据分诊输出明确列出按可能性排序的假设。不要跳过此步骤。
当用户报告同一命名空间中有多个受影响的服务时,请分别诊断每个服务。 两个 Pod 的注入失败可能有完全不同的原因(一个有选择退出注解,一个缺少命名空间标签,一个已有 ddtrace)。不要假设它们有共同的根本原因——请分别检查每个服务的 Pod 规范、注解和运行时,并逐个呈现调查结果。
| 分诊信号 | 强假设 |
|---|---|
| 收到跟踪数据 + 服务在 tracers 列表中 | 这两个信号都针对服务,因此在部分滚动发布期间,即使用户提到的特定 Pod 未经过插桩,它们也可能呈现为正向信号。首先确认此 Pod 已经过插桩(在分诊 kubectl 检查中存在 init 容器,或带有 admission.datadoghq.com/status: injected 注解)。如果已经过插桩,则问题可能是 UI 筛选条件或时间范围——告知用户后停止 |
| 没有跟踪数据 + 此 Pod 上没有 init 容器 | 此 Pod 从未进行过注入——请调查:命名空间目标、webhook、Pod 选择器、选择退出注解、Pod 尚未重启(部分滚动发布)。逐 Pod 的 init 容器检查具有权威性:在部分滚动发布期间,服务仍可能因其他 Pod 而出现在 tracers list 中,因此针对服务的正向信号不能掩盖此 Pod 未经过插桩的事实 |
| 没有跟踪数据 + 服务不在 tracers 列表中 + 存在 init 容器 | Tracer 已注入但未上报——tracers list 基于遥测数据,因此无法上报或尚未上报的正确注入 Pod 不会出现在列表中。请调查:与 Agent 的连接、DD_SITE 不匹配、API 密钥、出口流量被阻止或遥测延迟。(真正的注入失败会表现为 init 容器缺失或 init 容器错误——见下方 CrashLoopBackOff 行,而不是这里。) |
| 没有跟踪数据 + 服务在 tracers 列表中 + 存在 init 容器 | Tracer 正在上报遥测数据(因此与 Agent 的连接、API 密钥和 DD_SITE 均正常),但没有跟踪跨度到达——请调查跟踪特定原因:没有流量/应用尚未处理请求、采样规则、摄取/保留筛选器或 trace-agent 接收器 |
| Pod 事件显示 CrashLoopBackOff 或 init 容器错误 | init 容器故障——检查已有的 ddtrace、运行时版本 |
| 收到跟踪数据但 service/env 错误 | Deployment 中缺少或配置错误的 UST 标签 |
明确陈述你认为最可能的 1–3 个假设:"根据分诊结果,我认为最可能的原因是 X,因为 Y。"
步骤 3:调查
仅使用与你的假设相关的工具。每项观察结果都将为下一步行动提供依据。
集群端调查工具
Pod 是否位于 Agent 命名空间中? SSI 不会对与 Datadog Agent 位于同一命名空间中的 Pod 进行插桩。
kubectl get pods -n <AGENT_NAMESPACE>
启用 SSI 后是否重启了 Pod?
重启前请先向用户确认。 告诉用户:“Pod 必须重启,SSI 才能向其中注入内容。我将重启
<DEPLOYMENT_NAME>(位于<APP_NAMESPACE>中)。现在可以继续吗?”等待确认。
Claude 运行
kubectl rollout restart deployment/<DEPLOYMENT_NAME> -n <APP_NAMESPACE>
kubectl wait --for=condition=Ready pod -l app=<APP_LABEL> -n <APP_NAMESPACE> --timeout=120s
Claude runs
# Primary — authoritative and immediate: confirm the freshly-restarted pods carry the init container.
# Label-scoped, not by <POD_NAME>: a rolling restart replaces the old pod with new-suffixed ones.
kubectl get pod -l app=<APP_LABEL> -n <APP_NAMESPACE> \
-o jsonpath='{.items[0].spec.initContainers[*].name}'
# Secondary — eventual: the service reappears here once the restarted pod reports telemetry
# (subject to a propagation delay of a minute or more, and only if the pod serves traffic)
pup fleet tracers list --filter "service:<SERVICE_NAME>"
kubectl init 容器检查是重启后最权威的信号——该 init 容器一出现,Pod 就已注入。tracers list 源自遥测数据,存在延迟,因此不要把重启后立即出现的空结果理解为“未发生注入”。
命名空间是否带有 Admission Controller 的启用标签?
当 Admission Controller 以 mutateUnlabelled: false 运行时,只有明确带有 admission.datadoghq.com/mutate-pods=true 标签的命名空间才会发生注入。缺少此标签的命名空间会导致其中每个 Pod 都跳过 SSI,集群中的大多数服务都已完成检测,但某个命名空间中的服务没有检测,这是一个常见原因。
kubectl get namespace <APP_NAMESPACE> -o jsonpath='{.metadata.labels}'
kubectl get namespace <APP_NAMESPACE> --show-labels
修复:为命名空间添加标签,然后重启受影响的 Deployment,以便 AC 在 Pod 重新创建时对其进行变更。
kubectl label namespace <APP_NAMESPACE> admission.datadoghq.com/mutate-pods=true
命名空间目标是否将该 Pod 过滤掉了?
kubectl get datadogagent datadog -n <AGENT_NAMESPACE> -o yaml | grep -A 15 instrumentation
修复:更新 datadog-agent.yaml 中的 enabledNamespaces。
Claude runs
kubectl apply -f datadog-agent.yaml
podSelector 目标是否将该 Pod 过滤掉了?
如果配置了带有 podSelector 的 targets,则只有标签与选择器匹配的 Pod 才会进行检测。检查应用 Pod 的标签是否与任何目标匹配:
kubectl get datadogagent datadog -n <AGENT_NAMESPACE> -o yaml | grep -A 20 targets
kubectl get pod <POD_NAME> -n <APP_NAMESPACE> --show-labels
修复:在 Pod 模板中添加匹配的标签,或放宽 podSelector,然后应用更改并重启。
Pod 注解是否选择了退出,或者缺少 AC 的注入成功注解? 请检查以下两个注解:
admission.datadoghq.com/enabled: "false"— 明确选择退出,AC 会跳过该 Pod。admission.datadoghq.com/status: injected— AC 成功变更 Pod 后会设置此注解;运行中的 Pod 缺少此注解,有力表明 AC 从未变更该 Pod。
kubectl get pod <POD_NAME> -n <APP_NAMESPACE> -o jsonpath='{.metadata.annotations}'
kubectl get pod <POD_NAME> -n <APP_NAMESPACE> -o yaml | grep -A 10 annotations
修复:从 Deployment 的 Pod 模板中移除选择退出注解,然后应用更改并重启。
运行中的 Pod 是否包含预期的 DD_* 环境变量?
SSI 变更 Pod 时,会将 DD_SERVICE、DD_ENV、DD_VERSION、DD_TRACE_* 和 LD_PRELOAD 注入容器环境变量。缺少这些变量可确认变更未执行;如果变量存在但值不符合预期,则可能是 UST 标签不匹配或 ddTraceConfigs 配置有问题。
kubectl exec -n <APP_NAMESPACE> <POD_NAME> -- env | grep -E '^(DD_|LD_PRELOAD)'
kubectl describe pod <POD_NAME> -n <APP_NAMESPACE> | grep -E 'DD_|LD_PRELOAD'
Claude runs
kubectl apply -f <your-app-deployment.yaml>
重启前请先征得用户同意。 告诉用户:“我需要重启
<DEPLOYMENT_NAME>(位于<APP_NAMESPACE>),此更改才能生效。是否继续?”等待用户确认。
Claude runs
kubectl rollout restart deployment/<DEPLOYMENT_NAME> -n <APP_NAMESPACE>
应用是否已有自定义检测? SSI 检测到现有 tracer 代码时会静默禁用自身。请扫描源文件,查找以下内容:
- Python:
import ddtrace、ddtrace.patch_all() - Node.js:
require('dd-trace')、DD.init() - Java:
GlobalTracer.register(、dd-java-agent - .NET:
Tracer.Instance、DD.Trace - Ruby:
require 'ddtrace'、Datadog.configure - PHP:
DDTrace\
同时检查依赖清单:requirements.txt、package.json、Gemfile、pom.xml。
修复:移除导入项或依赖包,重新构建镜像,将其加载到集群中,然后重启 Pod。
基础镜像是否为 Alpine(musl libc)?
K8s SSI 会将 LD_PRELOAD 作为环境变量注入 Pod,不依赖 /etc/ld.so.preload,因此支持 musl/Alpine 镜像。这不会妨碍 Kubernetes SSI。
运行时版本是否受支持?
kubectl exec -n <APP_NAMESPACE> <POD_NAME> -- python --version
kubectl exec -n <APP_NAMESPACE> <POD_NAME> -- node --version
kubectl exec -n <APP_NAMESPACE> <POD_NAME> -- java -version
请参阅 SSI 兼容性矩阵 进行验证。
Admission Webhook 是否已注册?
kubectl get mutatingwebhookconfigurations | grep datadog
kubectl get pods -n <AGENT_NAMESPACE> -l app=datadog-cluster-agent
kubectl logs -n <AGENT_NAMESPACE> -l app=datadog-cluster-agent --tail=100
注入是否产生错误? 先获取节点主机名,然后在 Datadog 中查询注入错误:
kubectl get pod <POD_NAME> -n <APP_NAMESPACE> -o jsonpath='{.spec.nodeName}'
pup apm troubleshooting list --hostname <NODE_HOSTNAME> --timeframe 1h
Agent 是否正在向 Datadog 发送数据?
kubectl exec -n <AGENT_NAMESPACE> \
$(kubectl get pod -n <AGENT_NAMESPACE> -l app=datadog-agent -o name | head -1) \
-- agent status | grep -A 5 "APM Agent"
Datadog 侧的调查工具
Tracer 是否正在上报?
pup fleet tracers list --filter "service:<SERVICE_NAME>"
APM 是否识别该服务?
pup apm services list --env <ENV>
该服务使用的 SDK 配置是什么?
显示 tracer 配置使用的环境变量(例如 DD_TRACE_ENABLED、DD_SERVICE、DD_ENV、采样规则)。如果未在 enable-ssi 中设置 ddTraceConfigs,则预期输出为空;如果输出有内容但与配置不符,则表示更改未生效。
pup apm service-library-config get --service-name <SERVICE_NAME> --env <ENV>
是否有 trace 到达?
pup traces search --query "service:<SERVICE_NAME>" --from 1h --limit 10
Tracer 连接的是哪个 Agent? 如果怀疑 tracer 与 Agent 之间的连接存在问题,请使用此项。
pup fleet agents list --filter "hostname:<NODE_HOSTNAME>"
pup fleet agents tracers <AGENT_KEY> --filter "service:<SERVICE_NAME>"
第 4 步:得出结论前先反思
应用任何修复之前,请回答:
- 有什么证据能证实我的假设?
- 有什么证据会与之矛盾——我是否已检查过?
- 是否存在我尚未考虑的更简单解释?
如果结论经不起推敲,请带着新的假设返回第 2 步。持续迭代,直到你能针对这三个问题为结论辩护。
第 5 步:修复
针对已确认的根本原因应用修复。如果修复需要更改代码或 Dockerfile,请重新构建并重新加载:
Claude 运行
docker build -f <DOCKERFILE_PATH> -t <IMAGE_NAME> <BUILD_CONTEXT>
[决策:集群类型]
- kind(本地):将镜像加载到集群中
Claude 运行
kind load docker-image <IMAGE_NAME> --name <CLUSTER_NAME>
- 基于 Registry:跳过——镜像将在下次部署时拉取
重启前请先与用户确认。 告知用户:“我需要重启
<DEPLOYMENT_NAME>(位于<APP_NAMESPACE>)以应用修复。是否可以继续?”等待确认。
Claude 运行
kubectl rollout restart deployment/<DEPLOYMENT_NAME> -n <APP_NAMESPACE>
kubectl wait --for=condition=Ready pod -l app=<APP_LABEL> -n <APP_NAMESPACE> --timeout=120s
第 6 步:验证
重新运行排查流程,确认修复是否生效:
Claude 运行
pup traces search --query "service:<SERVICE_NAME>" --from 1h --limit 5
pup fleet tracers list --filter "service:<SERVICE_NAME>"
如果 trace 正在到达——问题已解决(服务可能需要一分钟才会重新出现在 pup fleet tracers list 中;重启后立即看到 tracer 列表为空属于预期的遥测延迟,并非故障)。现在自动继续执行 onboarding-summary——无需征求用户许可。
错误:没有 trace 到达——带着新的排查数据返回第 2 步,并提出更新后的假设。
安全约束
- 切勿将原始 API 密钥写入任何文件或聊天消息
- 未经用户确认,切勿运行
kubectl delete - 切勿直接修改
admissionController设置 - 向 Registry 执行
docker push始终需要用户确认