前言: 上一篇我们用 Deployment 让图片预览接口的 Pod 消失后还能补回来,可我接着画调用链时又卡住了:前端到底该把请求发给谁?按理说,新实例起来后,页面应该继续调用接口。我第一反应是记住旧 Pod 的地址,结果它一换,请求就找不到人了。翻了 Kubernetes 官方的 Service 文档后,我想弄清两个问题:没有 Service 时该怎么找实例?有了 Service,是不是就保证接口一定可用了?
这篇先讲集群内部访问,不展开公网暴露。下面的图片预览接口是示意场景,清单和命令依据官方文档核对;我没有连接真实集群执行它们。
一. 新 Pod 回来了,旧地址却没回来
-
假设网页服务要请求图片预览接口。我们已经把接口交给 Deployment ,期望它始终有两份 Pod 。接口刚部署好时,我从
kubectl get pods -o wide看到两个地址,顺手把其中一个写进网页服务的配置。第一次请求当然能通,感觉问题已经解决。 -
麻烦发生在其中一个 Pod 被替换后。Deployment 会补出新实例,但新 Pod 是新对象,可能得到另一个 IP。网页服务还握着旧地址,补位成功这件事对它毫无帮助。更别说两份实例时,写死一个地址会让另一份闲着。

这张图重点看右边:Pod 数量恢复了,请求目标却没有跟着更新。
二. 我先试了两种找人的办法
-
最粗暴的办法,是每次替换 Pod 后手动改客户端配置。它适合临时调试,却把应用能不能继续访问绑在人的反应速度上。就像餐厅换了服务员,每位客人都得重新记住这个人的手机号,换班一次就失联一次。
-
稍微好一点,可以写脚本定期查询当前 Pod IP,再刷新客户端的地址列表。可这又把"哪些实例还活着、哪些该接请求、何时更新配置"变成了我们自己的维护任务。脚本查询和客户端刷新之间还有时间差,扩成多份时也得自己决定流量怎么分。
| 办法 | 客户端记住什么 | Pod 更换后要做什么 |
|---|---|---|
| 写死 Pod IP | 某一份实例地址 | 人工修改并重启或刷新配置 |
| 自己维护地址表 | 当前所有实例地址 | 持续发现、删旧添新、处理可用状态 |
| 使用 Service | 一个稳定的服务名 | 核对选择器与后端就绪状态 |

两条路的共同问题是:客户端仍然在操心"今天是哪一个 Pod"。
三. Service 把"找谁"变成一个稳定名字
-
到这里才需要 Service 。可以把它想成餐厅前台:客人只记前台电话,不记每位值班员的手机;有人换班,前台更新值班名单。对应到这里,网页服务是客人,Service 是稳定入口,符合条件的 Pod 是当班的实例。
-
这层入口通常靠标签来找后端。比如接口 Pod 带
app: preview-api,Service 的selector也写app: preview-api。Kubernetes 根据匹配结果维护后端端点;Pod 换了,调用方仍访问同一个 Service 名称。普通ClusterIPService 的名字会由集群 DNS 解析到服务的集群内地址。
text
网页服务 → preview-api 这个 Service 名称
Service → 符合标签且可用的后端端点
Pod 更换 → 后端端点更新,调用方不改地址

重点看入口与后端的分离:稳定的是访问入口 ,不是某个 Pod 的身份。
四. 最小清单里,先盯住标签和端口
- 如果前一篇的 Deployment 模板给 Pod 设置了
app: preview-api,可以另建一个集群内部使用的 Service 。下面假设容器确实在8080端口监听;实际使用时,镜像、标签和监听端口都要与自己的应用一致。
yaml
apiVersion: v1
kind: Service
metadata:
name: preview-api
spec:
type: ClusterIP
selector:
app: preview-api # !!! 注意:要匹配 Pod 模板的标签
ports:
- port: 80 # Service 对调用方开放的端口
targetPort: 8080 # Pod 内应用实际监听的端口
-
把清单保存为
preview-service.yaml后,在有权限的测试集群里可用kubectl apply -f preview-service.yaml创建,再用kubectl get service preview-api看入口。集群内同命名空间的调用方可尝试访问http://preview-api:80。这些是预期的验证步骤,不是本文已经取得的运行结果。 -
我后来发现,最容易写错的不是对象名字,而是"前台名单":
selector不匹配时,Service 对象仍会存在,却可能没有可用后端。官方 Service 文档 和 EndpointSlice 文档 分别说明了选择器与后端端点的关系。

图里分成两道检查:先匹配标签,再把 80 转到应用实际监听的 8080。
五. 有了 Service,也得看后端能不能接单
-
前台电话能打通,不代表厨房一定能出餐。Service 提供稳定入口和后端选择,但它不会替应用修复启动失败、错误端口或未就绪状态。默认情况下,EndpointSlice 的
ready条件会反映 Pod 是否就绪;服务代理通常会避开未就绪端点。还要留意删除中的端点、连接保持等细节,所以不要把"有 Service"理解成"每次请求必定成功"。 -
排查时先看
kubectl get pods -l app=preview-api是否真的选中了预期 Pod ,再看kubectl get endpointslice -l kubernetes.io/service-name=preview-api。如果前者为空,是标签或命名空间的问题;前者有实例而后者没有可用端点,就继续看 Pod 的就绪状态与应用监听端口。官方文档还提醒:ClusterIP只提供集群内部访问,浏览器从集群外直接打开preview-api并不会自动连上它。 -
前面餐厅的比方到这里也有边界:前台负责转接,并不保证每位值班员都能完成任务。如果后端全都没准备好,稳定的号码也不能凭空变出一次成功响应。

橙色的检查点是排错入口,别看到对象存在就跳过它们。
六. 总结:换的是 Pod,不该换调用地址
-
回到开头的图片预览接口:Deployment 负责维持实例数量,Service 负责给调用方一个稳定入口。前者补了新 Pod ,后者通过匹配标签更新后端端点;网页服务继续使用服务名,不用追着每次换班的 Pod IP 改配置。
-
下次遇到"副本已经补回,请求还是打不到"的情况,可以先按这条路检查:
text
调用方访问的是 Service 名称吗?
Service 的 selector 匹配到预期 Pod 吗?
后端端点就绪、应用端口正确吗?
调用方是否在这个 ClusterIP 的可达范围内?

这张图把全文压成一条线:入口稳定 解决"找谁",后端就绪解决"能不能处理"。下一次我们再动手观察一次实际请求如何到达这些 Pod。