Kubernetes生产运维06:Service访问不通,怎么顺着EndpointSlice和kube-proxy找到断点
2026/8/27 20:41:43 网站建设 项目流程

Kubernetes生产运维06:Service访问不通,怎么顺着EndpointSlice和kube-proxy找到断点

写在前面

Service访问不通时,常见的第一反应是怀疑网络出了问题,然后开始抓包、重启kube-proxy或者重建Service。

但Service只是一层抽象,它把稳定的访问入口和一组随时变化的Pod关联起来。请求从客户端到达真正的容器,中间要经过DNS解析、ClusterIP、Service、EndpointSlice、kube-proxy规则、Pod就绪状态、容器端口,还可能受NetworkPolicy约束。任何一段断了,表现都是访问不通,但根因和修复完全不同。

因此,Service排查要沿着这条链路逐段确认断点在哪:

访问不通 → 确认要访问的Service和端口是什么 → Service是否有Endpoint → 没有Endpoint:Selector不匹配还是Pod未就绪 → 有Endpoint:端口、kube-proxy、NetworkPolicy还是应用本身 → 定位断点后针对性修复 → 补链路监控与配置校验

本文按照Kubernetes官方机制和命令参考整理。由于当前没有连接可验证的实验集群,命令没有在统一版本的真实集群完整执行,案例和终端输出均为C级生产化重建,不是生产原始记录。不同Kubernetes版本、CNI插件、kube-proxy模式、DNS实现和云厂商可能改变字段、命令和行为,执行前应以目标集群的kubectl explain、命令帮助和实际状态为准。


一、先理解Service到Pod的链路

1.1 EndpointSlice是Service和Pod之间的名册

对于带Selector的Service,控制平面会自动创建EndpointSlice,其中引用所有匹配Selector且就绪的Pod。kube-proxy根据这些端点在节点上编程转发规则,DNS把Service名解析到ClusterIP。

这条链路里有几个关键事实:

  • Service通过Selector选择Pod,匹配关系体现在EndpointSlice里。
  • 只有通过就绪检查的Pod才会作为可用端点被加入。
  • 一个Service可能对应多个EndpointSlice,需要合并看全部端点。
  • kube-proxy把端点转成内核转发规则,规则没生效时即使有端点也连不上。

1.2 没有Endpoint和连接被拒是两回事

两种现象都表现为访问不通,但断点位置不同:

现象含义断点位置
Service没有Endpoint没有匹配且就绪的后端PodSelector或Pod就绪
连接超时请求发出后没有响应网络策略、路由、kube-proxy或节点网络
连接被拒绝目标可达但端口上无人监听或拒绝端口不匹配、容器未监听、应用拒绝

先判断是"落空"(没有后端)还是"被拒/超时"(有后端但连不上),能快速把排查范围减半。

1.3 端口的三段对应

Service访问涉及三个端口,必须一一对应:

  • Service的port:客户端访问Service用的端口。
  • Service的targetPort:转发到Pod上的端口。
  • 容器的containerPort与实际监听端口:应用真正监听的端口。

targetPort要对上Pod实际监听的端口。如果targetPort写错,或应用监听的端口和声明不一致,即使有端点也会连接被拒或超时。


二、Service排查决策树

访问不通 │ ├─ 确认目标Service、命名空间和端口 │ ├─ Service有Endpoint吗 │ ├─ 无端点 │ │ ├─ Selector与Pod标签不匹配 │ │ ├─ Pod未就绪(Readiness失败) │ │ └─ Pod不存在或不在同命名空间 │ └─ 有端点 │ ├─ 端口/targetPort不匹配 → 连接被拒 │ ├─ NetworkPolicy拦截 → 超时 │ ├─ kube-proxy规则未生效 → 超时 │ └─ 应用本身错误 → 有响应但报错 │ ├─ 定位断点后针对性修复 │ └─ 补链路监控与校验

先用一条命令区分有没有端点:

NS='<namespace>'SVC='<service-name>'kubectl get endpointslices-n"$NS"-l"kubernetes.io/service-name=$SVC"-owide

有就绪端点则往端口、策略、kube-proxy查;没有端点则往Selector和Pod就绪查。


三、取证:逐段确认

3.1 确认Service本身

kubectl get svc"$SVC"-n"$NS"-owide kubectl describe svc"$SVC"-n"$NS"

关注:

  • TypeClusterIPPorts(port和targetPort)
  • Selector
  • describe底部的Endpoints一行是否为空

3.2 确认端点

kubectl get endpointslices-n"$NS"-l"kubernetes.io/service-name=$SVC"\-ocustom-columns='NAME:.metadata.name,ADDRESSES:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port'
  • 如果没有任何EndpointSlice或地址为空,是"没有端点"分支。
  • 如果有地址但ready为false,说明匹配到了Pod但未就绪。

3.3 没有端点:查Selector和就绪

对比Service的Selector和Pod的标签:

kubectl get svc"$SVC"-n"$NS"-ojsonpath='{.spec.selector}{"\n"}'kubectl get pods-n"$NS"--show-labels kubectl get pods-n"$NS"-l'<selector-from-service>'-owide
  • 用Service的Selector去筛Pod,如果筛不到,是Selector不匹配。
  • 如果筛得到但READY不是全就绪,是Pod未就绪,转向Readiness探针和应用启动。

3.4 有端点:查端口、策略和kube-proxy

kubectl get svc"$SVC"-n"$NS"\-ojsonpath='{range .spec.ports[*]}{.name}{" port="}{.port}{" targetPort="}{.targetPort}{"\n"}{end}'kubectl get pod'<backend-pod>'-n"$NS"\-ojsonpath='{range .spec.containers[*]}{.name}{" ports="}{.ports}{"\n"}{end}'kubectl get networkpolicy-n"$NS"
  • targetPort要对上Pod实际监听端口。
  • 有NetworkPolicy时,确认是否放行了来源到该端口的流量。
  • 如果端口和策略都正常仍超时,再查kube-proxy和节点网络,这类问题往往需要节点侧和CNI排查,属于更深一层。

3.5 边界

  • kubectl get endpointslices受版本和权限影响,旧集群也可用kubectl get endpoints作为补充视角。
  • NetworkPolicy行为取决于CNI是否支持,未安装支持的CNI时策略可能不生效。
  • 抓包和内核规则排查会改变现场或需要节点权限,属于只读命令之后的深入手段。

四、常见断点与判断

现象更可能的断点优先检查不能直接得出的结论
Service无Endpoint,Selector筛不到PodSelector或Pod标签错Service selector与Pod labels不一定是网络问题
Service无Endpoint,Pod能筛到但未就绪Readiness未通过Readiness探针、应用启动不一定是Service配置错
有Endpoint但连接被拒targetPort或监听端口不符targetPort与容器实际监听不一定是应用崩溃
有Endpoint但连接超时NetworkPolicy或网络NetworkPolicy、CNI、kube-proxy不一定是应用无响应
有响应但返回错误应用本身应用日志、依赖不一定是Service链路问题
跨命名空间访问不通DNS名或策略FQDN、NetworkPolicy命名空间选择器不一定是Selector问题

一个关键区分:没有Endpoint时,问题几乎一定在Service到Pod的关联(Selector或就绪),而不在更下层的网络;有Endpoint但不通时,才需要往端口、策略和网络查。先看端点能避免一开始就抓包走弯路。


五、C级生产化重建案例:改了标签后Service突然没有后端

5.1 先说明哪些是真的,哪些是重建的

下面不是作者声称亲历的生产事故,而是根据Kubernetes Service、Selector和EndpointSlice机制构造的生产化重建,用于展示从访问不通走到可验证根因的取证过程。

内容证据属性
Service、Selector、EndpointSlice和就绪端点之间的机制Kubernetes官方机制
改动标签后Service端点变空、访问返回无后端机制一致的重建场景
Namespace、资源名、标签、相对时间和终端输出为讲解构造的说明性信息
Deployment模板的Pod标签被改动模拟根因,不是作者生产记录
修正单一变量后验证端点恢复受控验证设计,不声称已在当前集群执行

所有输出按真实对象关系编排,但没有连接实际集群采集,读者不能把下面的时间、标签或输出引用为真实事故数据。

5.2 现场卡片

一次发布后,某内部服务的调用方开始报连接失败。被调用的Deployment Pod看起来都在Running。团队最初怀疑是网络或kube-proxy问题。

重建的相对时间线:

相对时间观察或动作当时能够得出的结论
T+00发布更新Deployment只能确认发生了配置变更
T+02调用方报连接失败,Pod仍Running访问不通,原因未知
T+04有人怀疑网络或kube-proxy待验证假设
T+06查到Service没有任何Endpoint断点在Service到Pod关联,不在下层网络
T+09对比Selector与Pod标签发现不一致得到可验证的主假设
T+验证只修正标签,观察端点是否恢复单变量验证

相对时间只表示排查顺序,不代表真实恢复时长。

5.3 先确认有没有端点

NS=example-prodSVC=orders-internal kubectl get svc"$SVC"-n"$NS"-owide kubectl get endpointslices-n"$NS"-l"kubernetes.io/service-name=$SVC"\-ocustom-columns='NAME:.metadata.name,ADDRESSES:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready'

机制一致的说明性输出:

NAME TYPE CLUSTER-IP PORT(S) SELECTOR orders-internal ClusterIP 10.96.12.34 80/TCP app=orders,tier=api NAME ADDRESSES READY orders-internal-abcde <none> <none>

Service存在、有ClusterIP,但EndpointSlice没有任何地址。这把断点直接定位到Service与Pod的关联,不是下层网络或kube-proxy。因此先不抓包。

5.4 判断是Selector不匹配还是未就绪

kubectl get svc"$SVC"-n"$NS"-ojsonpath='{.spec.selector}{"\n"}'kubectl get pods-n"$NS"-lapp=orders --show-labels kubectl get pods-n"$NS"-l'app=orders,tier=api'-owide

机制一致的说明性输出:

map[app:orders tier:api] NAME READY STATUS LABELS orders-api-newhash-a1 1/1 Running app=orders,tier=backend orders-api-newhash-b2 1/1 Running app=orders,tier=backend (使用 app=orders,tier=api 精确筛选) No resources found in example-prod namespace.

关键发现:

  • Pod都是Running且Ready,不是就绪问题。
  • Service的Selector要求tier=api,但Pod标签是tier=backend
  • 用Service的完整Selector精确筛选,筛不到任何Pod。

因此不是网络问题,也不是Pod未就绪,而是Selector与Pod标签不匹配,导致EndpointSlice为空。

5.5 对比新旧模板确认来源

helm list-n"$NS"helm get values'<release-name>'-n"$NS">release-values.yamlgrep-n-A3'labels'release-values.yamlgitdiff'<known-good-ref>..<candidate-ref>'-- values-prod.yaml

机制一致的说明性差异:

labels: app: orders - tier: api + tier: backend

证据链:

Service存在且有ClusterIP + EndpointSlice为空 + Pod都Running且Ready + Service Selector要求tier=api + 本次发布把Pod标签tier改成backend + 用完整Selector筛不到Pod = 强烈支持本次标签改动导致Service失去后端

这仍是主假设,验证前不写成根因已闭环。

5.6 止损与单变量验证

调用方正在报错,最安全的止损通常是回滚到已知可用版本,或在变更窗口修正标签。两者都属于变更操作,执行前确认可用副本、PDB、maxUnavailablemaxSurge、兼容性和可回退版本。

修正时只把Pod模板标签tier改回api,不同时改Service Selector、端口和其他配置(同时改两端会让人无法判断到底哪边错):

spec:template:metadata:labels:app:orderstier:api

验证并保存修复后证据:

kubectl rollout status deployment/orders-api-n"$NS"--timeout=5m kubectl get endpointslices-n"$NS"-l"kubernetes.io/service-name=$SVC"\-ocustom-columns='NAME:.metadata.name,ADDRESSES:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port'

机制一致的说明性输出:

deployment "orders-api" successfully rolled out NAME ADDRESSES READY PORTS orders-internal-abcde 10.244.1.7,10.244.2.9 true,true 8080

端点恢复后,从集群内做一次连通性确认:

kubectl run netcheck--rm-it--restart=Never-n"$NS"\--image=<approved-debug-image>--\sh-c'wget -qO- --timeout=3 http://orders-internal.example-prod.svc/healthz'

这条命令会临时创建一个调试Pod,属于主动操作,需使用经审批的调试镜像并在完成后清理。它用于确认链路已通,不是必需步骤。

这些输出分别证明不同范围的事实:

输出能够支持不能单独证明
rollout成功Deployment滚动完成所有调用方立即恢复
EndpointSlice有就绪地址Selector重新匹配到就绪Pod端口和策略一定都正确
连通性探测成功该路径当前可达所有来源和端口都放行

5.7 根因闭环条件

  1. 修正版与失败版只有Pod标签这一项主要差异。
  2. 修正后EndpointSlice重新出现就绪地址。
  3. Service Selector未改动,说明是Pod侧标签错。
  4. 调用方连接恢复。
  5. 观察窗口内端点稳定,没有再次变空。

如果修正标签后仍无端点,就要停止把标签当作唯一原因,重新检查就绪探针、命名空间和Selector两端。


六、修复方案要分六层

层次本文场景中的动作关键边界
应急止损回滚到已知可用版本或修正标签先查可用副本、PDB、兼容性和回退版本
现场取证保存Service、EndpointSlice、Pod标签、端口和NetworkPolicy端点和标签随发布变化,尽快留存
根因验证只改一端的一个变量并观察端点恢复不同时改Pod标签和Service Selector
永久修复修正Git或Helm源配置的标签或Selector防止下次发布再次改错
监控预防监控Service端点数、就绪比例和连接失败端点为0应触发告警
运行治理标签与Selector一致性校验、端口约定、发布校验标签契约纳入模板校验

临时恢复不等于根因确认。端点恢复只说明变更与故障相关,仍需配置差异、端点变化和单变量验证共同支撑。

不要在没看端点前就抓包或重启kube-proxy。没有端点时问题在关联层,重启网络组件无效还可能扩大影响。


七、可直接使用的只读Service采集脚本

脚本只读取对象,不修改Service、不改标签、不重启组件、不创建调试Pod。

#!/usr/bin/env bashset-uset-opipefailNS=${1:?用法:$0 <namespace> <service-name>}SVC=${2:?用法:$0 <namespace> <service-name>}STAMP=$(date+%Y%m%d-%H%M%S)OUT="svc-evidence-${NS}-${SVC}-${STAMP}"mkdir-p"$OUT"umask077capture(){localfile=$1shiftprintf'采集 %s\n'"$file"if!"$@">"$OUT/$file"2>"$OUT/$file.err";thenprintf'失败: %s,查看 %s.err\n'"$file""$file">&2fi}capture context.txt kubectl config current-context capture version.txt kubectl version capture service.yaml kubectl get svc"$SVC"-n"$NS"-oyaml capture service-describe.txt kubectl describe svc"$SVC"-n"$NS"capture selector.txt kubectl get svc"$SVC"-n"$NS"\-ojsonpath='{.spec.selector}{"\n"}'capture ports.txt kubectl get svc"$SVC"-n"$NS"\-ojsonpath='{range .spec.ports[*]}{.name}{" port="}{.port}{" targetPort="}{.targetPort}{" protocol="}{.protocol}{"\n"}{end}'capture endpointslices.txt kubectl get endpointslices-n"$NS"\-l"kubernetes.io/service-name=$SVC"-owide capture endpointslices.yaml kubectl get endpointslices-n"$NS"\-l"kubernetes.io/service-name=$SVC"-oyaml capture pods.txt kubectl get pods-n"$NS"--show-labels-owide capture networkpolicy.yaml kubectl get networkpolicy-n"$NS"-oyamlprintf'采集完成: %s\n'"$OUT"printf'如需连通性测试,请另用经审批镜像的临时Pod,属于主动操作\n'printf'分享前请检查地址、标签、镜像和策略中的敏感信息\n'

使用方式:

bashcollect-svc-evidence.sh'<namespace>''<service-name>'

脚本边界:

  • 只做只读采集,连通性测试需另行创建临时Pod,属于主动操作
  • endpointslices受版本和权限影响,旧集群可补充kubectl get endpoints
  • NetworkPolicy是否生效取决于CNI,采集到策略不代表一定被执行
  • 脚本用于保存首轮现场,不能替代按端点结果选择下一步

八、监控、就绪与治理

8.1 监控什么

  • 每个Service的就绪端点数量,端点为0应告警
  • 就绪Pod比例与Readiness探针失败
  • 服务间连接失败率和超时率
  • NetworkPolicy变更与拒绝计数(若CNI支持)
  • 发布前后端点数量对比

告警不能只监控Pod是否Running。Pod Running但未就绪、标签改错、端口不符都会让端点为空或不通,需要以端点数量和连接成功率为准。

8.2 发布前校验

  • Pod模板标签与Service Selector保持一致
  • Service的targetPort与容器实际监听端口一致
  • 命名空间内外访问用正确的Service名或FQDN
  • NetworkPolicy放行必要的来源和端口
  • 变更标签或Selector时同时检查两端

8.3 契约与治理

  • 把标签和端口作为服务契约的一部分,纳入模板校验
  • Selector和Pod标签由同一模板生成,避免两端漂移
  • 关键服务配置端点数量告警,快速发现失去后端
  • 建立Service排障Runbook,先看端点再看网络

九、常见误区

误区1:一访问不通就抓包或重启kube-proxy

先看端点。没有端点时问题在关联层,抓包和重启网络组件无效。

误区2:Pod是Running就以为一定是后端

只有就绪的Pod才会成为端点。Running不等于Ready。

误区3:只改一端标签或Selector

改错的一端和排查时改动的一端要一致,同时改两端会掩盖真正问题。

误区4:忽略targetPort与实际监听端口

端口对不上会连接被拒,即使有端点也不通。

误区5:忘了NetworkPolicy

有端点但超时可能是策略拦截,尤其是默认拒绝的命名空间。

误区6:跨命名空间用短名

跨命名空间要用带命名空间的名字或FQDN,否则解析不到。

误区7:把连接被拒和连接超时混为一谈

被拒是端口层面,超时更多是策略或网络,处理路径不同。

误区8:只看Service不看EndpointSlice

Service配置正确但端点为空时,问题在Selector或就绪,不看端点会漏判。


十、面试怎么说

60秒版本

Service不通我不会先抓包。先确认要访问的Service和端口,再看有没有Endpoint。没有端点几乎一定是Selector不匹配或Pod未就绪,我用Service的Selector去筛Pod,筛不到就是标签错,筛得到但没就绪就查Readiness。有端点还不通,才往targetPort、NetworkPolicy和kube-proxy查,区分连接被拒和连接超时。修复只改一端一个变量并观察端点恢复,最后补端点数量和连接成功率监控。

3分钟场景版本

假设发布后调用方连接失败,被调Pod都Running。我先看这个Service的EndpointSlice,发现没有任何地址,这就把断点定位到Service与Pod的关联,不用去抓包。我用Service的Selector精确筛Pod,筛不到;再看Pod标签,发现这次发布把tier从api改成了backend,而Service Selector还是tier=api,所以端点变空。我确认Pod都Ready,排除就绪问题,然后回到Helm和Git确认是Pod模板标签改错。我只把Pod标签改回api,不动Service Selector和端口,滚动完成后EndpointSlice重新出现就绪地址,调用恢复。这样我能区分是标签契约问题而不是网络故障,也不会用重启kube-proxy这种无关动作去掩盖配置错误。


十一、延伸问答

1. Service没有Endpoint一定是Selector错吗

不一定。也可能是匹配到的Pod未就绪,或Pod不在同一命名空间。要先用Selector筛Pod再看就绪状态。

2. Pod是Running为什么不在端点里

只有通过Readiness的Pod才会作为可用端点。Running不等于Ready。

3. 连接被拒和连接超时怎么区分处理

被拒通常是端口层面,查targetPort和监听端口;超时更多是NetworkPolicy或网络,查策略和CNI。

4. 一个Service会有多个EndpointSlice吗

会。端点较多时会分片,需要按service-name标签合并看全部端点。

5. 改了Selector后要注意什么

Selector和Pod标签是两端契约,改一端就要同步另一端,否则端点会变空。

6. NetworkPolicy会导致有端点但不通吗

会。默认拒绝的命名空间里,没有放行规则的流量会被拦截,表现为超时。

7. 跨命名空间访问要注意什么

要用带命名空间的Service名或FQDN,并确认NetworkPolicy放行了对方命名空间。

8. 什么时候才需要抓包和查kube-proxy

在确认有就绪端点、端口正确、策略放行之后仍不通时,才深入节点网络、kube-proxy和CNI。


小结

  1. Service只是抽象,请求要经过DNS、ClusterIP、EndpointSlice、kube-proxy、端口和策略多段。
  2. 排查先看有没有Endpoint,能把范围直接减半。
  3. 没有端点几乎一定在Selector或Pod就绪,不在下层网络。
  4. 有端点不通才查targetPort、NetworkPolicy和kube-proxy。
  5. 连接被拒和连接超时断点不同,处理不同。
  6. 标签和Selector是两端契约,改一端要同步另一端。
  7. 修复只改一端一个变量并观察端点恢复。
  8. 长期治理覆盖标签契约、端口约定、端点监控和排障Runbook。

下一篇预告

下一篇进入CoreDNS与域名解析故障。我们会沿着DNS链路、解析超时、缓存、上游DNS和ndots配置,区分解析失败、解析慢和解析到错误地址,并整理一份DNS排查清单。

参考资料

  1. Kubernetes官方文档:Service
  2. Kubernetes官方文档:EndpointSlices
  3. Kubernetes官方文档:Debug Services
  4. Kubernetes官方文档:Connecting Applications with Services
  5. Kubernetes官方文档:Virtual IPs and Service Proxies
  6. Kubernetes官方文档:Network Policies
  7. Kubernetes官方文档:Liveness, Readiness and Startup Probes
  8. Kubernetes官方文档:DNS for Services and Pods
  9. Kubernetes官方文档:Service Internal Traffic Policy
  10. Kubernetes官方文档:Debug Running Pods

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询