HTTPRoute 显示 Accepted、ResolvedRefs=True 但 NGINX Gateway Fabric 仍返回 503 时,检查状态代际、EndpointSlice、生成配置和控制面日志,并给出验证与回退步骤。
NGINX Gateway Fabric 的 HTTPRoute 即使显示 Accepted=True 和 ResolvedRefs=True,请求仍可能返回 503。这两个条件只说明路由已被控制器接受、引用能够解析,不等于当前 NGINX 数据面已经拿到可用后端。先不要直接重启整个集群:依次核对状态代际、Service 与 EndpointSlice、生成的 NGINX 配置和控制面日志,才能判断是应用没有就绪、配置尚未收敛,还是数据面确实保留了 fallback upstream。
本文面向使用 Kubernetes Gateway API 和 NGINX Gateway Fabric 的运维人员。只读检查不会产生云资源费用,也不会改动业务;后面的滚动重启会替换控制面 Pod,单副本部署可能出现短暂的配置更新空窗,必须先保存证据并安排变更窗口。
先确认 503 是谁返回的
从集群外请求真实域名,同时保存响应头和状态码。把 HOST 与 URL 替换为实际值:
curl -vk --resolve HOST:443:GATEWAY_IP https://HOST/health
curl -vk https://URL/health
如果直连 Gateway IP 与正常 DNS 都立即返回相同 503,问题更接近 Gateway 路由或上游选择;如果直连正常而公网异常,应转查 CDN、负载均衡、DNS 或防火墙。记录响应中的 server、时间和请求 ID,但不要仅凭一个响应头断言故障层。
第一步:比较 HTTPRoute 的状态与代际
下面命令只读取资源。替换命名空间和路由名:
kubectl -n APP_NAMESPACE get httproute ROUTE_NAME \
-o jsonpath='{.metadata.generation}{"\n"}{range .status.parents[*].conditions[*]}{.type}{"="}{.status}{" reason="}{.reason}{" observed="}{.observedGeneration}{"\n"}{end}'
kubectl -n APP_NAMESPACE describe httproute ROUTE_NAME
metadata.generation 是当前规则版本,条件里的 observedGeneration 是控制器已经处理的版本。二者不相等时,即使页面仍显示旧的 True,也不能证明新配置已经生效。先等待一次正常调和周期并查看控制器日志,不要反复编辑资源制造更多代际。
Accepted=True 表示路由被某个监听器接受;ResolvedRefs=True 表示 Service 等引用可解析。它们都不检查业务 Pod 是否 Ready,也不保证当前数据面配置已经包含正确 Endpoint。
第二步:核对 Service 和 EndpointSlice
先从 HTTPRoute 找出 backendRefs 中的 Service 名和端口,再执行:
kubectl -n APP_NAMESPACE get service SERVICE_NAME -o wide
kubectl -n APP_NAMESPACE get endpointslice \
-l kubernetes.io/service-name=SERVICE_NAME -o wide
kubectl -n APP_NAMESPACE get pods -o wide --show-labels
EndpointSlice 没有地址时,优先检查 Service 选择器是否命中 Pod、Pod 的 Readiness Probe 是否通过、HTTPRoute 端口是否对应 Service 的 port。此时重启 Gateway 控制面不会让应用端点凭空出现。
EndpointSlice 有地址还不够。确认端点端口与 Service 目标端口一致,并从集群内临时调试 Pod 访问 Service。若 Service 自身也返回 503 或连接失败,继续处理应用、NetworkPolicy、端口监听和健康检查,不要把问题归咎于 NGINX Gateway Fabric。
第三步:读取控制面和数据面日志
先列出 NGINX Gateway Fabric 的 Pod 和容器名,避免猜名称:
kubectl -n nginx-gateway get pods -o wide
kubectl -n nginx-gateway get deployment
kubectl -n nginx-gateway get events --sort-by=.lastTimestamp
随后读取控制面日志。把 Pod 名替换为实际值;若容器名不是 nginx-gateway,先从 kubectl describe pod 确认:
kubectl -n nginx-gateway logs NGF_CONTROL_POD -c nginx-gateway --since=60m
kubectl -n nginx-gateway logs NGF_CONTROL_POD -c nginx-gateway -p --tail=300
重点找资源处理失败、发送配置失败、重连、reload 错误和与故障时间一致的异常。Credential watcher has detected changes 或连接重建本身不能单独证明故障;要继续确认重连后是否出现成功发送并应用配置的日志。
第四步:确认当前 NGINX 配置到底指向哪里
NGINX 官方排障文档建议查看生成配置。先定位数据面 Pod,再读取 nginx -T;这条命令只输出当前配置:
kubectl -n DATA_PLANE_NAMESPACE get pods -o wide
kubectl -n DATA_PLANE_NAMESPACE exec DATA_PLANE_POD -c nginx -- nginx -T
在输出中查真实域名、路径、Service 名或 Endpoint IP。若 upstream 已包含当前 EndpointSlice 地址,503 更可能来自应用返回、上游连接失败或健康状态;结合 NGINX error log 和应用日志继续查。若 HTTPRoute 状态和 EndpointSlice 都正确,但配置仍指向内部 503 fallback 或没有该后端,才有证据指向控制面到数据面的配置未收敛。
| 检查结果 | 下一步 | 不要做什么 |
|---|---|---|
| observedGeneration 落后 | 查控制器调和与错误日志 | 连续编辑路由 |
| EndpointSlice 为空 | 修 Service 选择器、Pod Ready 或端口 | 重启 Gateway 代替修应用 |
| 生成配置已有正确 Endpoint | 查应用、NetworkPolicy、端口和 NGINX error log | 把所有 503 当控制器故障 |
| 状态与 Endpoint 正常,但配置仍是 fallback | 保存证据后评估受控重启控制面 | 删除 Gateway、CRD 或全量重建集群 |
证据指向未收敛时怎样受控恢复
先导出相关资源和日志,文件中可能含域名、内部地址与注解,保存到受控位置,不要公开上传:
kubectl -n APP_NAMESPACE get httproute ROUTE_NAME -o yaml > httproute-before.yaml
kubectl -n APP_NAMESPACE get service SERVICE_NAME -o yaml > service-before.yaml
kubectl -n APP_NAMESPACE get endpointslice \
-l kubernetes.io/service-name=SERVICE_NAME -o yaml > endpoints-before.yaml
确认 NGINX Gateway Fabric 控制面 Deployment 的真实名称与副本数。多副本且 PodDisruptionBudget、资源容量正常时,可滚动重启控制面 Deployment:
kubectl -n nginx-gateway rollout restart deployment/NGF_DEPLOYMENT
kubectl -n nginx-gateway rollout status deployment/NGF_DEPLOYMENT --timeout=5m
rollout restart 会创建新的控制面 Pod,不应删除 HTTPRoute、Service 或业务数据,但配置更新在新 Pod 就绪前可能延迟。单副本部署、集群资源紧张或镜像无法拉取时,重启可能放大故障;先确认镜像可用、节点有容量,并保留原版本信息。
恢复后如何验证,失败怎样退出
重启完成不等于故障解决。再次检查四件事:HTTPRoute 的 observedGeneration 与 generation 一致;EndpointSlice 仍有 Ready 地址;nginx -T 已出现正确 upstream;真实请求由 503 恢复到预期状态。连续请求时同时观察应用日志与 NGINX 日志,避免只验证一次缓存响应。
如果新控制面 Pod 无法 Ready,立即停止继续编辑路由。查看 rollout 状态、Pod 事件与日志;若这次操作伴随镜像或 Helm 版本变化,按原发布工具回退到已验证版本。单纯执行 restart 不改变 Deployment 模板版本,因此“撤销 restart”通常没有新的镜像版本可回滚,恢复重点是让原配置的健康 Pod 重新运行,而不是执行无意义的 rollout undo。
如果重启后配置恢复,但随后再次回到 fallback,说明问题尚未根治。保留首次故障到恢复期间的 HTTPRoute YAML、EndpointSlice、控制面日志、数据面日志和生成配置差异,并核对当前 NGINX Gateway Fabric 版本的已知 Issue;不要把周期性重启当作长期修复。
费用、停机和数据风险
这些 Kubernetes 读取命令通常不产生独立费用,但日志存储、额外副本和底层云负载均衡仍按所在平台计费。控制面滚动重启不应修改业务持久卷;错误删除 Gateway、Service、CRD 或数据面 Deployment 却可能导致入口中断。本文不建议删除资源来“强制刷新”。
相关阅读
官方与上游来源
- NGINX Gateway Fabric Issue #5869:HTTPRoute 状态正常但数据面保留 503 fallback
- NGINX Gateway Fabric Issue #5658:控制面连接重建的相关上游讨论
- NGINX Gateway Fabric 官方排障文档
- NGINX Gateway Fabric:HTTPRoute 基础路由
- Kubernetes:kubectl rollout restart
资料核验日期:2026 年 9 月 26 日。上游 Issue 用于证明该故障现场真实存在,是否属于同一缺陷仍要由本集群证据判断。黑鲨云不是 NGINX 或 Kubernetes 官方;本稿未发现需要补充确认的黑鲨云业务事实。

