Kubernetes GPU 节点 Xid 119 后 Pod 一直重启:Startup probe failed connection refused 排查
结论
这次故障可以收敛成两个结论:
- 节点
Ready不代表每张 GPU 都健康。 某张卡已进入GPU requires reset、内核报Xid 119和Xid 154,但kubectl get node仍是Ready,CPU、内存、Pod 状态都正常。只看控制面会得到"节点没问题"的误导性结论。 - GPU 修好后 Pod 仍反复重启,真因不是 GPU 二次故障,而是
startupProbe窗口太紧、误杀了慢启动的 vLLM。 应用在:8000/ping还没监听时探针连续connection refused,kubelet 判定启动失败、杀容器重启。最后一次能起来,是因为第二轮启动完整跑完了 vLLM 初始化,并在下一轮 startup probe 杀它之前把 HTTP 服务拉起来。
排查时间线(从入口到定位):
- 入口不是 Kubernetes 告警,而是云厂商发来的维修任务通知:某台 GPU 云服务器存在硬件隐患,要求在计划维护时间前授权停机维修。
- 登录 Kubernetes 工具机后,节点本身仍是
Ready,CPU、内存、Pod 状态也没有明显异常。 - 继续下钻到 GPU 层,才确认某张卡进入
GPU requires reset,内核有Xid 119和Xid 154。节点虽然仍是Ready,但该卡已经不能正常服务。 - 节点重启或 GPU 重新初始化后 GPU 恢复,但某个业务 Pod 仍反复重启,问题转移到了 startup probe。
环境
以下版本号均为占位,替换成你自己的即可。
- Kubernetes: v1.34.x(containerd + crictl)
- GPU: NVIDIA GeForce RTX 5090 D ×8 / 驱动 <DRIVER_VERSION> / CUDA <CUDA_VERSION>
- 推理服务: vLLM <VLLM_VERSION>,冷启动约 600–800s(含 graph capture + warmup)
- OS / 内核: <OS_RELEASE> / <KERNEL_VERSION>
- 探针: startupProbe 走 httpGet :8000/ping
原始告警:云服务器维修任务通知
这次排查的入口是一条云厂商通知,核心内容大致如下,敏感字段已替换:
监控到您的服务器存在隐患,可能导致云服务器高负载或宕机。
云账号:<CLOUD_ACCOUNT_ID>
影响主机内网 IP:192.168.1.1
机器别名:<GPU_NODE_NAME>
项目:<PROJECT_NAME>
实例 ID:<INSTANCE_ID>
实例规格:<GPU_INSTANCE_TYPE>
可用区:<REGION_ZONE>
触发时间:2026-05-29 08:15:53
计划维护时间:2026-06-02 08:15:52
为尽快修复隐患,需要授权停机处理。
如超过 48 小时未授权,系统将在计划维护时间默认发起维护。
这类告警的关键点是:它不是 Kubernetes 控制面直接报错,而是云服务器底层维修通知。第一反应不能直接重启或删除 Pod,而是先确认三件事:
- 这台机器是否仍在集群里 Ready。
- 节点上的业务是否已经受影响。
- 云厂商提示的硬件隐患是否已经能在操作系统或 GPU 驱动层看到证据。
因此排查顺序应从低风险只读命令开始:先看节点和 Pod,再看 GPU exporter、nvidia-smi、内核 Xid。
节点 Ready,但单卡已经异常
先看节点,容易得到一个误导性的结论:节点是正常的。
kubectl get node 192.168.1.1 -o wide
示例输出:
NAME STATUS ROLES AGE VERSION INTERNAL-IP
192.168.1.1 Ready <none> 80d v1.34.x 192.168.1.1
节点 condition 也可能都是好的:
kubectl describe node 192.168.1.1 | sed -n '/Conditions:/,/Addresses:/p'
关键输出:
MemoryPressure False KubeletHasSufficientMemory
DiskPressure False KubeletHasNoDiskPressure
PIDPressure False KubeletHasSufficientPID
Ready True KubeletReady
但 GPU exporter 日志已经在报错:
kubectl logs -n kube-system <GPU_EXPORTER_POD> --since=2h \
| egrep -i 'error|fail|xid|critical|warn|unknown' \
| tail -20
示例输出:
E0529 08:24:54 exporter.go:199] Can't get device 0, error Unknown Error
E0529 08:25:09 exporter.go:199] Can't get device 0, error Unknown Error
这类错误说明不能只看 kubectl get node。节点 Ready 只能说明 kubelet 还在上报,不代表每张 GPU 都健康。
nvidia-smi 能枚举 8 张卡,但一张卡需要 reset
进入节点后执行只读检查:
nvidia-smi -L
nvidia-smi --query-gpu=index,uuid,pci.bus_id,temperature.gpu,power.draw,power.limit,utilization.gpu,memory.used,memory.total --format=csv,noheader,nounits
nvidia-smi
异常时,某张卡仍能被枚举,但字段已经异常:
GPU 7: NVIDIA GeForce RTX 5090 D (UUID: GPU-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
nvidia-smi 表格里会看到:
| 7 NVIDIA GeForce RTX 5090 D | 00000000:E1:00.0 N/A |
| ERR! 40C P5 N/A / N/A | 11969MiB / 32607MiB | N/A |
| | | ERR! |
如果查更详细字段,可能出现:
retired_pages.pending: [N/A]
remapped_rows.failure: [GPU requires reset]
继续看内核日志:
dmesg -T | egrep -i 'NVRM|Xid|GSP|reset' | tail -120
关键输出:
NVRM: Xid (PCI:0000:e1:00): 119, Timeout after 45s of waiting for RPC response from GPU GSP
NVRM: Xid (PCI:0000:e1:00): 154, GPU recovery action changed from None to GPU Reset Required
到这里可以确认:这不是 Kubernetes 调度层的假异常,而是 GPU/驱动层已经把这张卡标记为需要 reset。
定位影响哪个 Pod
GPU 异常时,业务 Pod 可能仍然是 Running/Ready,因为探针只测 HTTP,不一定真实测 GPU 推理。
先看节点上的 Pod:
kubectl get pods -n <NAMESPACE> -o wide --field-selector spec.nodeName=192.168.1.1
再在节点上把异常 GPU UUID 映射到容器。示例思路如下:
BAD_UUID=GPU-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
for id in $(crictl ps -q); do
crictl inspect "$id" 2>/dev/null \
| egrep -A3 -B8 "$BAD_UUID|NVIDIA_VISIBLE_DEVICES|io.kubernetes.pod.name|io.kubernetes.pod.namespace"
done
如果看到:
"io.kubernetes.pod.name": "<AFFECTED_POD>"
"io.kubernetes.pod.namespace": "<NAMESPACE>"
"NVIDIA_VISIBLE_DEVICES": "GPU-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
就能确定这张卡对应哪个业务实例。
在 Pod 内再验证一次:
kubectl exec -n <NAMESPACE> <AFFECTED_POD> -- sh -lc '
echo NVIDIA_VISIBLE_DEVICES=$NVIDIA_VISIBLE_DEVICES
timeout 8 nvidia-smi
curl -sS --max-time 3 http://127.0.0.1:8000/ping || true
'
异常时可能看到:
NVIDIA_VISIBLE_DEVICES=GPU-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
ERR! / N/A / No running processes found
这说明 Pod 的 HTTP 层可能还活着,但 GPU 计算链路已经不可信。
GPU 恢复后,为什么 Pod 还会重启
节点重启或 GPU 重新初始化后,nvidia-smi 可能已经恢复正常:
0, GPU-..., 00000000:21:00.0, 61, 362.04, 575.00, 81, 18440, 32607
1, GPU-..., 00000000:31:00.0, 38, 21.75, 575.00, 0, 11865, 32607
...
7, GPU-..., 00000000:E1:00.0, 49, 69.57, 575.00, 0, 11845, 32607
内核里也没有新的 Xid:
dmesg -T | egrep -i 'Xid|GSP|GPU Reset Required|requires reset' | tail -20
这时如果某个 Pod 仍然反复重启,需要看 Pod 事件,而不是继续盯着 GPU。
kubectl describe pod -n <NAMESPACE> <POD_NAME>
典型事件:
Warning Unhealthy Startup probe failed: Get "http://192.168.1.1:8000/ping": dial tcp 192.168.1.1:8000: connect: connection refused
Normal Killing Container <CONTAINER_NAME> failed startup probe, will be restarted
这说明 kubelet 杀容器的原因是 startup probe 失败。connection refused 代表端口没监听,不是网络超时。
进 Pod 内部测试同样能验证:
kubectl exec -n <NAMESPACE> <POD_NAME> -- sh -lc '
date
(command -v ss >/dev/null && ss -lntp || netstat -lntp 2>/dev/null || true) | grep 8000 || true
curl -sS --max-time 2 -v http://127.0.0.1:8000/ping || true
'
示例输出:
* Trying 127.0.0.1:8000...
* connect to 127.0.0.1 port 8000 failed: Connection refused
curl: (7) Failed to connect to 127.0.0.1 port 8000
为什么最后一次又起来了
看容器状态:
kubectl get pod -n <NAMESPACE> <POD_NAME> -o wide
kubectl describe pod -n <NAMESPACE> <POD_NAME> | egrep -A5 -B3 'State:|Last State:|Ready:|Restart Count|Started|Finished|Exit Code|Reason:'
恢复后的状态:
State: Running
Started: Fri, 29 May 2026 10:27:02 +0800
Last State: Terminated
Reason: Completed
Exit Code: 0
Finished: Fri, 29 May 2026 10:27:01 +0800
Ready: True
Restart Count: 1
日志里能看到启动耗时:
INFO gpu_model_runner.py: Graph capturing finished in 575 secs
INFO core.py: init engine (profile, create kv cache, warmup model) took 615.09 seconds
后面开始有业务请求:
INFO service_func: Received infer_param: {...}
所以最后一次起来的原因是:第二轮启动跑完了模型初始化,并在下一轮 startup probe 杀它之前把 8000/ping 服务拉起来。前面的 Triton 报错更像 autotuning 中的候选配置失败和回退,会拖慢启动,但没有成为最终致命错误:
OutOfMemoryError: out of resource: triton_mm Required: 110592 Hardware limit:101376
处理建议
1. 先止血:不要把 GPU 异常节点继续当健康节点使用
当出现 GPU requires reset、Xid 119/154 时,不建议只因为节点 Ready 就继续调度业务。至少要先保护调度入口:
kubectl cordon 192.168.1.1
如果已有业务占着其他正常 GPU,是否 drain 要看业务容忍度。生产环境不要无脑驱逐。
2. 确认影响面:定位异常卡对应的 Pod
重点确认三件事:
- 异常 GPU UUID 是哪张卡
- 哪个 Pod 的
NVIDIA_VISIBLE_DEVICES绑定了这张卡 - 这个 Pod 的 HTTP 探针是否仍然能代表真实 GPU 推理健康
如果 HTTP 活着但 GPU 不可用,探针需要改造,否则会出现"Pod Ready 但计算不可用"。
3. 恢复 GPU:选择 GPU reset 或节点重启
如果卡已经是 GPU Reset Required,只读排查无法恢复。常见恢复方式是:
- 业务确认窗口后做 GPU reset
- 或重启节点,让驱动和 GPU 重新初始化
本次恢复后可以看到新的 GPU UUID,说明节点或驱动层完成了重新初始化。
4. 防止启动探针误杀慢启动服务
这类 vLLM 服务启动阶段可能超过 10 分钟,startup probe 不能按普通 HTTP 服务配置。
原配置示例:
startupProbe:
httpGet:
path: /ping
port: 8000
initialDelaySeconds: 600
periodSeconds: 10
timeoutSeconds: 1
failureThreshold: 20
如果实际启动耗时经常在 600 到 800 秒之间,这个窗口太紧。可以考虑:
startupProbe:
httpGet:
path: /ping
port: 8000
initialDelaySeconds: 900
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 30
更好的做法是让应用暴露分层健康检查:
/startup:模型加载和 warmup 完成后返回成功/livez:进程存活即可/readyz:能接真实请求时才成功
这样 startup probe 不会误杀慢启动进程,readiness probe 也不会过早放流量。
快速参考
判断 GPU 是否真的异常
nvidia-smi
nvidia-smi --query-gpu=index,uuid,pci.bus_id,temperature.gpu,power.draw,power.limit,utilization.gpu,memory.used,memory.total --format=csv,noheader,nounits
dmesg -T | egrep -i 'NVRM|Xid|GSP|reset' | tail -120
重点看:
ERR!N/AGPU requires resetXid 119Xid 154GSP Timeout
定位异常 GPU 对应 Pod
BAD_UUID=GPU-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
for id in $(crictl ps -q); do
crictl inspect "$id" 2>/dev/null \
| egrep -A3 -B8 "$BAD_UUID|NVIDIA_VISIBLE_DEVICES|io.kubernetes.pod.name|io.kubernetes.pod.namespace"
done
判断是不是探针导致重启
kubectl describe pod -n <NAMESPACE> <POD_NAME> \
| egrep -A5 -B3 'State:|Last State:|Ready:|Restart Count|Unhealthy|Killing|Started|Finished|Exit Code|Reason:'
如果看到:
Startup probe failed: connect: connection refused
Container failed startup probe, will be restarted
说明是 startup probe 杀的,不是进程自己崩。
排查端口是否监听
kubectl exec -n <NAMESPACE> <POD_NAME> -- sh -lc '
(command -v ss >/dev/null && ss -lntp || netstat -lntp 2>/dev/null || true) | grep 8000 || true
curl -sS --max-time 2 -v http://127.0.0.1:8000/ping || true
'
三条铁律
- 节点
Ready不代表每张 GPU 都健康。 - HTTP
/ping不等于 GPU 推理链路健康。 - 慢启动模型服务要给 startup probe 足够窗口,否则 kubelet 会制造重启循环。

浙公网安备 33010602011771号