K8s 集群里 Ray Serve 启动失败怎么排查?
Ray Serve 在 K8s 里跑不起来,先别急着改代码。
大多数问题集中在三类:Pod 根本没进入 Running、Pod 起来了但服务访问不到、Ray head 与 worker 之间连不上。
按下面顺序查,基本能在十几分钟内定位到原因。
先确认现象和排查入口
登录到能执行 kubectl 的机器,先确认当前命名空间和部署名称。
假设应用部署在 ray 命名空间,Deployment 名为 rayserve-demo。
kubectl -n ray get pods -o wide
kubectl -n ray get deploy rayserve-demo
kubectl -n ray get svc
看三件事:
STATUS是Running、Pending、CrashLoopBackOff还是Error。READY是否为1/1或预期副本数。RESTARTS是否持续增加。
如果 Pod 不是 Running,优先看 kubectl -n ray describe pod 底部 Events。
如果 Pod 是 Running 但服务不通,直接跳到网络与 Service 检查。
按状态定位常见启动失败
Pending:资源或调度问题
Pending 通常说明没有节点能满足调度条件。
执行:
kubectl -n ray describe pod | tail -n 30
重点看 Events 里的 Insufficient cpu、Insufficient memory、node(s) had taint。
处理方式:
- 调整 Deployment 的
resources.requests,不要超过节点可分配量。 - 如果节点有污点,确认是否加了对应的
tolerations。 - 检查
nodeSelector或affinity是否写死了不存在的标签。
CrashLoopBackOff:容器启动后退出
这种状态说明容器反复启动又退出。
先看当前日志和上一次退出日志:
kubectl -n ray logs --tail=100
kubectl -n ray logs --previous --tail=100
常见原因包括:
- Ray head 启动参数写错,比如
--ray-address指向了不存在的地址。 - Serve 应用导入时报
ModuleNotFoundError。 - 端口被占用或监听地址写成
127.0.0.1,导致容器外无法访问。
如果日志里出现 Connection refused 或 Failed to connect to Ray head,
先确认 head Pod 是否已经 Running,
再检查 worker 的启动命令里地址和端口是否与 head Service 一致。
ImagePullBackOff:镜像拉取失败
执行 kubectl -n ray describe pod ,看 Events 里的镜像地址和错误。
常见情况是镜像名拼错、私有仓库没配 imagePullSecrets,或者节点无法访问镜像仓库。
kubectl -n ray get secret
确认 Deployment 的 spec.template.spec.imagePullSecrets 引用了存在的 secret 名称。
检查 Ray head 与 worker 的连接
Ray Serve 在 K8s 中通常由一个 head 和若干 worker 组成。
worker 连不上 head 时,Serve 部署会一直卡住。
先确认 head Service 是否存在并且有 Endpoint:
kubectl -n ray get svc ray-head
kubectl -n ray get endpoints ray-head
如果 ENDPOINTS 为空,说明 head Pod 没有通过 readiness 检查,或者 Service 的 selector 与 Pod 标签不匹配。
用下面命令核对标签:
kubectl -n ray get pod --show-labels
kubectl -n ray describe svc ray-head
worker 的启动命令里常见的 Ray 地址格式是:
ray start --address=ray-head.ray.svc.cluster.local:6379
如果这里写的是 localhost 或 127.0.0.1,worker 会连到自己而不是 head,需要改成 head Service 的 DNS 名称。
服务起来了但访问不到怎么办
Pod 和 Endpoint 都正常,但外部访问失败,按下面顺序查。
先确认 Service 类型和端口映射:
kubectl -n ray get svc rayserve-demo -o yaml
重点看 spec.type、spec.ports[].port 和 targetPort。
如果 targetPort 写成了容器里没有监听的端口,流量会转发失败。
再看容器实际监听端口:
kubectl -n ray exec -it -- ss -lntp
如果容器里没有 ss,可以试 netstat -lntp 或 curl localhost:<端口>。
如果使用 Ingress,检查 Ingress 的后端 Service 名称、端口和路径是否与 Serve 暴露的路径一致。
Ray Serve 默认路径和应用中定义的路由要对应,否则会返回 404。
避坑与复查清单
- 不要把所有问题都归因于 Ray Serve 本身,先确认 Pod 状态和 Events。
- 修改 Deployment 后记得
kubectl -n ray rollout status deploy/rayserve-demo观察滚动更新结果。 - 资源限制不要只写
limits不写requests,否则调度可能不符合预期。 - 如果节点时间不同步,Ray 集群可能报连接异常,检查节点 NTP 状态。
- 生产环境改配置前先备份当前 YAML:
kubectl -n ray get deploy rayserve-demo -o yaml > backup.yaml。
验证修复是否生效
执行下面命令确认副本就绪:
kubectl -n ray get pods
kubectl -n ray get endpoints rayserve-demo
然后在集群内测试服务:
kubectl -n ray run curl-test --rm -it --image=curlimages/curl -- sh
curl http://rayserve-demo.ray.svc.cluster.local:<端口>/<路径>
如果返回预期响应,说明 K8s 集群中的 Ray Serve 已经恢复。
如果仍然失败,回到日志和 Events,优先看最近一次重启前后的错误信息。
常见疑问
Ray Serve 部署后一直 Pending,但节点资源看起来够用?
检查是否有其他 Pod 占用了大量资源,或者节点有污点、亲和性限制。describe pod 的 Events 会直接说明调度失败原因。
worker 日志显示连接 head 超时,但 head Pod 是 Running?
确认 head Service 的 Endpoint 是否为空,以及 worker 使用的地址是否为 Service DNS 名称而不是 Pod IP。
Pod 重建后 IP 会变化,用 Service 名称更稳定。
服务在集群内能访问,从外部不行?
先确认 Service 类型是 NodePort、LoadBalancer 还是通过 Ingress 暴露,再检查防火墙、安全组和 Ingress 规则是否放行对应端口和路径。
Ray Serve 排错的核心思路是:先看 Pod 状态,再看 Events 和日志,最后检查网络与 Service。
按这个顺序执行,大部分 K8s 集群中的启动失败和访问异常都能找到明确原因。