本文中的服务名、命名空间和地址均为虚构示例。事故期间应按自己的变更审批流程操作。
一次微服务故障里,日志可能同时出现 Load balancer does not have available server、connect timed out、Nacos 重连和 Redis 连接失败。它们不必只有一个根因,更不代表应该同时重启 Nacos、Redis、业务 Pod 与 kube-proxy。
正确顺序是先确定故障发生在哪一跳。
flowchart TD
A[业务请求失败] --> B{DNS 能解析 Service 吗?}
B -- 否 --> C[检查 Pod DNS 与 CoreDNS]
B -- 是 --> D{Endpoint 有 Ready 后端吗?}
D -- 否 --> E[检查目标 Pod、selector、readiness]
D -- 是 --> F{Pod 内可连接 Service 吗?}
F -- 否 --> G[检查 kube-proxy、CNI、NetworkPolicy 与节点路径]
F -- 是 --> H{客户端仍依赖 Nacos 实例吗?}
H -- 是 --> I[检查注册、namespace、group 与实例健康]
H -- 否 --> J[检查应用超时、连接池和下游延迟]
先把 Service 证据收齐
以 payment-api 为例:
kubectl -n <ns> get svc payment-api
kubectl -n <ns> get endpointslice -l kubernetes.io/service-name=payment-api
kubectl -n <ns> get pod -l app=payment-api -o wide
kubectl -n <ns> exec <caller-pod> -- \
sh -c 'getent hosts payment-api.<ns>.svc.cluster.local'
DNS 解析正确但 Endpoint 为空,优先检查 selector、readiness 和目标 Pod;不应先改 Nacos 配置。Endpoint 正常但仅某些节点连接超时,才把范围收敛到 Service 转发、CNI 或节点网络。
把同一次取证的 YAML、事件和调用方连通性一起保存,才能判断问题是全局还是单节点:
export NS=<namespace>
export SVC=payment-api
export CALLER=<caller-pod>
export PORT=8080
kubectl -n "$NS" get svc "$SVC" -o yaml > /tmp/$SVC-service.yaml
kubectl -n "$NS" get endpointslice \
-l kubernetes.io/service-name="$SVC" -o yaml > /tmp/$SVC-endpoints.yaml
kubectl -n "$NS" get events --sort-by=.lastTimestamp | tail -50
# DNS、TCP、HTTP 必须分开判断。镜像没有 nc 时可用临时调试容器。
kubectl -n "$NS" exec "$CALLER" -- getent hosts "$SVC.$NS.svc.cluster.local"
kubectl -n "$NS" exec "$CALLER" -- sh -ec \
"timeout 3 sh -c '</dev/tcp/$SVC.$NS.svc.cluster.local/$PORT'"
kubectl -n "$NS" exec "$CALLER" -- \
curl -fsS --connect-timeout 3 "http://$SVC.$NS.svc.cluster.local:$PORT/actuator/health"
若 CALLER 没有 shell 或 curl,不要为了排障改业务镜像。使用与业务 Pod 同命名空间、相同 ServiceAccount 的临时调试 Pod,完成后删除:
kubectl -n "$NS" run network-debug --rm -it --restart=Never \
--image=<approved-debug-image> -- sh
# 在容器内依次运行 getent、nc -vz 和 curl;退出后 --rm 自动清理。
固定地址应该迁到 Service DNS
业务配置中不应长期保存 ClusterIP。它会因重新部署、Service 重建或环境迁移而变化。对于明确的内部 HTTP 依赖,优先使用:
payment.api.url=http://payment-api.platform.svc.cluster.local:8080
spring.data.redis.host=redis-service.platform.svc.cluster.local
这解决的是“地址稳定性”,并不能自动修复 Nacos 注册失败或客户端负载均衡空列表。两条调用链必须分别验证。
Nacos、Redis 和节点网络分别怎样验证
Load balancer does not have available server 是客户端没有获得可用实例的结果,不是 Nacos 本身必然故障。先确认应用连接的 Nacos namespace、group、serviceName 与实际注册信息一致。推荐临时本地转发管理接口,避免把管理端口长期暴露到集群外。
export NACOS_NS=<nacos-namespace>
kubectl -n "$NACOS_NS" port-forward svc/<nacos-service> 8848:8848
# 在另一个终端执行;认证参数从受控 Secret 注入,绝不写入 shell history。
curl -fsSG 'http://127.0.0.1:8848/nacos/v1/ns/instance/list' \
--data-urlencode 'serviceName=payment-api' \
--data-urlencode 'namespaceId=<namespace-id>'
Redis 问题同样先区分“Redis 不健康”与“到 Redis Service 的路径不通”。密码用环境变量或 Secret 文件传递,避免粘贴到终端和日志:
export REDIS_NS=<redis-namespace>
export REDIS_POD=<redis-pod>
kubectl -n "$REDIS_NS" exec "$REDIS_POD" -- redis-cli --no-auth-warning PING
kubectl -n "$NS" exec "$CALLER" -- \
sh -ec "timeout 3 sh -c '</dev/tcp/redis-service.$REDIS_NS.svc.cluster.local/6379'"
只在“Endpoint 正常、调用方 DNS 正常、但故障稳定集中在同一节点”时检查 kube-proxy/CNI。先看版本、节点分布和日志,再决定是否做受控重建:
kubectl -n kube-system get pod -l k8s-app=kube-proxy -o wide
kubectl -n kube-system logs <kube-proxy-pod-on-affected-node> --tail=200
kubectl -n kube-system get pod -l k8s-app=calico-node -o wide
不要因为日志中同时出现 Feign、Nacos、Redis 就批量重启全部组件;那会抹掉事件证据,并扩大短暂网络抖动。
事故中的最小变更原则
每次只改变一个已经被证据指向的层,并在变更后复测原始请求:
- 保存
previous日志、Events、Endpoint 与节点分布; - 修复一个明确故障,例如无 Ready Endpoint 或单节点 kube-proxy 规则未同步;
- 从调用方 Pod 复测 DNS、TCP 和 HTTP;
- 最后才滚动业务服务或修改 Nacos。
这样即使 Nacos、Redis 和 Feign 同时出现在日志里,也不会把可恢复的小故障扩展成全环境重启。
每一步都要有可验证的回退
配置改动前先导出原 ConfigMap、Nacos 配置或 Deployment 修订号;改动后立即重放原始请求。若修改未改善对应证据,回退该单项而不是叠加下一项:
kubectl -n "$NS" get deploy <caller-deployment> -o yaml > /tmp/caller.before.yaml
kubectl -n "$NS" rollout history deploy/<caller-deployment>
# 仅在本次变更确实由 Deployment 触发时回退。
kubectl -n "$NS" rollout undo deploy/<caller-deployment>
kubectl -n "$NS" rollout status deploy/<caller-deployment> --timeout=5m
事故记录中应保留原始错误、Endpoint 快照、调用方复测结果、变更对象和回退条件。这些证据比“重启后好了”更能防止同类问题再次发生。
DISCUSSION
讨论与反馈