Kubernetes Service 让会更换的 Pod 有稳定访问入口

前言: 上一篇我们用 Deployment 让图片预览接口的 Pod 消失后还能补回来,可我接着画调用链时又卡住了:前端到底该把请求发给谁?按理说,新实例起来后,页面应该继续调用接口。我第一反应是记住旧 Pod 的地址,结果它一换,请求就找不到人了。翻了 Kubernetes 官方的 Service 文档后,我想弄清两个问题:没有 Service 时该怎么找实例?有了 Service,是不是就保证接口一定可用了?

这篇先讲集群内部访问,不展开公网暴露。下面的图片预览接口是示意场景,清单和命令依据官方文档核对;我没有连接真实集群执行它们。

一. 新 Pod 回来了,旧地址却没回来

  1. 假设网页服务要请求图片预览接口。我们已经把接口交给 Deployment ,期望它始终有两份 Pod 。接口刚部署好时,我从 kubectl get pods -o wide 看到两个地址,顺手把其中一个写进网页服务的配置。第一次请求当然能通,感觉问题已经解决。

  2. 麻烦发生在其中一个 Pod 被替换后。Deployment 会补出新实例,但新 Pod 是新对象,可能得到另一个 IP。网页服务还握着旧地址,补位成功这件事对它毫无帮助。更别说两份实例时,写死一个地址会让另一份闲着。

这张图重点看右边:Pod 数量恢复了,请求目标却没有跟着更新。

二. 我先试了两种找人的办法

  1. 最粗暴的办法,是每次替换 Pod 后手动改客户端配置。它适合临时调试,却把应用能不能继续访问绑在人的反应速度上。就像餐厅换了服务员,每位客人都得重新记住这个人的手机号,换班一次就失联一次。

  2. 稍微好一点,可以写脚本定期查询当前 Pod IP,再刷新客户端的地址列表。可这又把"哪些实例还活着、哪些该接请求、何时更新配置"变成了我们自己的维护任务。脚本查询和客户端刷新之间还有时间差,扩成多份时也得自己决定流量怎么分。

办法 客户端记住什么 Pod 更换后要做什么
写死 Pod IP 某一份实例地址 人工修改并重启或刷新配置
自己维护地址表 当前所有实例地址 持续发现、删旧添新、处理可用状态
使用 Service 一个稳定的服务名 核对选择器与后端就绪状态

两条路的共同问题是:客户端仍然在操心"今天是哪一个 Pod"。

三. Service 把"找谁"变成一个稳定名字

  1. 到这里才需要 Service 。可以把它想成餐厅前台:客人只记前台电话,不记每位值班员的手机;有人换班,前台更新值班名单。对应到这里,网页服务是客人,Service 是稳定入口,符合条件的 Pod 是当班的实例。

  2. 这层入口通常靠标签来找后端。比如接口 Pod 带 app: preview-api,Service 的 selector 也写 app: preview-api。Kubernetes 根据匹配结果维护后端端点;Pod 换了,调用方仍访问同一个 Service 名称。普通 ClusterIP Service 的名字会由集群 DNS 解析到服务的集群内地址。

text 复制代码
网页服务 → preview-api 这个 Service 名称
Service → 符合标签且可用的后端端点
Pod 更换 → 后端端点更新,调用方不改地址

重点看入口与后端的分离:稳定的是访问入口 ,不是某个 Pod 的身份。

四. 最小清单里,先盯住标签和端口

  1. 如果前一篇的 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 内应用实际监听的端口
  1. 把清单保存为 preview-service.yaml 后,在有权限的测试集群里可用 kubectl apply -f preview-service.yaml 创建,再用 kubectl get service preview-api 看入口。集群内同命名空间的调用方可尝试访问 http://preview-api:80。这些是预期的验证步骤,不是本文已经取得的运行结果。

  2. 我后来发现,最容易写错的不是对象名字,而是"前台名单":selector 不匹配时,Service 对象仍会存在,却可能没有可用后端。官方 Service 文档 和 EndpointSlice 文档 分别说明了选择器与后端端点的关系。

图里分成两道检查:先匹配标签,再把 80 转到应用实际监听的 8080。

五. 有了 Service,也得看后端能不能接单

  1. 前台电话能打通,不代表厨房一定能出餐。Service 提供稳定入口和后端选择,但它不会替应用修复启动失败、错误端口或未就绪状态。默认情况下,EndpointSlice 的 ready 条件会反映 Pod 是否就绪;服务代理通常会避开未就绪端点。还要留意删除中的端点、连接保持等细节,所以不要把"有 Service"理解成"每次请求必定成功"。

  2. 排查时先看 kubectl get pods -l app=preview-api 是否真的选中了预期 Pod ,再看 kubectl get endpointslice -l kubernetes.io/service-name=preview-api。如果前者为空,是标签或命名空间的问题;前者有实例而后者没有可用端点,就继续看 Pod 的就绪状态与应用监听端口。官方文档还提醒:ClusterIP 只提供集群内部访问,浏览器从集群外直接打开 preview-api 并不会自动连上它。

  3. 前面餐厅的比方到这里也有边界:前台负责转接,并不保证每位值班员都能完成任务。如果后端全都没准备好,稳定的号码也不能凭空变出一次成功响应。

橙色的检查点是排错入口,别看到对象存在就跳过它们。

六. 总结:换的是 Pod,不该换调用地址

  1. 回到开头的图片预览接口:Deployment 负责维持实例数量,Service 负责给调用方一个稳定入口。前者补了新 Pod ,后者通过匹配标签更新后端端点;网页服务继续使用服务名,不用追着每次换班的 Pod IP 改配置。

  2. 下次遇到"副本已经补回,请求还是打不到"的情况,可以先按这条路检查:

text 复制代码
调用方访问的是 Service 名称吗?
Service 的 selector 匹配到预期 Pod 吗?
后端端点就绪、应用端口正确吗?
调用方是否在这个 ClusterIP 的可达范围内?

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

相关推荐
不是万能的豆学长1 小时前
排查Go服务40天后的内存泄漏问题
开发语言·后端·golang·go
阿狗童鞋1 小时前
SpringSecurity权限认证实战指南
java·后端·spring
用户125758524361 小时前
Golang后台管理框架推荐:XYGo Admin与devinggo怎么选?
后端·go·ai编程
花间相见1 小时前
【计算基础|网络13】UDP 与可靠传输
后端·面试
tachibana21 小时前
Go 语言 Map 的底层实现原理
开发语言·后端·golang·make
九零HTTP1 小时前
从 Cookie 到 Token,登录态到底是怎么维持的
后端
Gopher_HBo2 小时前
go-grpc服务端调用链
后端
程序边界2 小时前
用了三年数据同步软件,我想好好聊聊KFS这套东西到底强在哪(上)
后端
sp422 小时前
简单的 Spring 文件上传与下载组件
后端