明明正常,为什么配送失败?
一句话总结
Service 存在、Pod 正在运行、用户请求成功,是三种完全不同的证据。
为什么需要它
快递查询服务的页面停止响应。负责人看到 kubectl get pods 显示 Running,便回答“Kubernetes 正常”。但客户请求仍然失败。谁的观测错了?两者都可能为真。Running 是 Pod 生命周期状态,不代表从用户请求的地址得到了正确响应。把不同问题的答案压缩成一个词,会让故障分析走向错误方向。
本课程中,你会亲自成为故障制造者。在实验 VM 中创建一个小型 HTTP 服务,再依次修改 Service selector、readiness 路径和容器命令。先预测症状,再观察真实响应,然后缩小原因并恢复。实验对象仅限 labhub-mystery namespace 中的 parcel。任务不要求停止宿主集群的节点、CoreDNS、CNI 或 etcd,也没有理由触碰他人的服务器。
开始前应了解 YAML 缩进、Deployment 与 Service 的基本职责,以及 kubectl get、describe、patch 的用法。这不是初学命令行的课程,而是学习:即使命令执行成功,业务仍可能失败。所有故障都由学员主动制造,且必须先保留故障时的证据,再进行恢复。
如何工作
Deployment 声明期望的 Pod 模板与 replica 数量,控制器通过创建 ReplicaSet 和 Pod 实现声明。Service 承担另一种职责:使用 app=parcel 这类 selector 选择目标 Pod,并提供固定 ClusterIP 与端口。EndpointSlice 会显示该 Service 选中的地址及其就绪状态。创建 Service 对象,并不意味着它会自动选中正确 Pod。
Service selector ── 비교 ── Pod metadata.labels
│ 일치한 대상
▼
EndpointSlice의 주소와 ready 조건
│ 대상 포트로 전달
▼
컨테이너의 HTTP 응답
实验的正常值是 Service 与 Pod 都使用 app=parcel,Service 端口和目标端口都是 8080。应用访问 / 时返回一行 labhub-mystery-v1。之所以不仅检查端口是否打开,还核对响应正文,是为了区分其他进程或错误服务返回的成功。只有 200 这个数字,却没有说明请求目标与响应正文,并不足以作为证据。
把 Service selector 改为 app=missing 后,什么会最先变化?因为 Deployment 的 Pod 模板没有改变,没有理由重启 Pod。直接请求应用的 Pod IP,仍会正常响应;但没有符合 selector 的 Pod,Service 的 EndpointSlice 中目标会消失,Service IP 请求则失败。此时重建容器镜像或删除 Pod,都是与原因不相符的操作。
读取空 EndpointSlice 的程序也要谨慎。endpoints 可能是空数组,也可能表示为 null,两者都应视为没有选中地址,不能因解析器异常而放弃观测。反过来,有一个地址也不能立即判断正常。如下一模块所示,其中可能记录 ready 为 false 的地址。应区分地址是否存在,与可路由目标的数量。
实验中,变化不会瞬间同时出现在所有位置。修改 Service 后,控制器更新 EndpointSlice 需要短暂时间。命令退出码 0 只表示 API 接受了修改,不表示整个数据路径已经生效。观测工具会在一段时间内重复读取状态,但不会修复错误或伪造状态。等待后仍不符合条件,应重新比较修改值与观测值。
在实际项目中
rollout 后请求失败时,应先缩小范围:是全部请求还是特定路径,是全部 Pod 还是部分 Pod,Service IP 是否失败,Pod IP 是否响应。一次猜测 DNS、Ingress、TLS 与应用依赖,会引入太多假设。本实验比较不经过 DNS 名称或外部 Ingress 的 ClusterIP 请求与 Pod 直接请求。因此,本实验通过不代表互联网 DNS 与 TLS 也已验证。
例如,Pod 直接响应成功而只有 Service 失败时,“服务器进程完全死亡”的假设就变弱。下一步应检查 selector、EndpointSlice、targetPort。若 selector 一致且存在 Ready 地址,但只有 Service 失败,就应询问 targetPort 数值是否等于实际监听端口。若连 Pod 直接请求也失败,则有理由先检查进程监听地址、端口、日志与退出状态。
支持某个假设的证据,与最终确认该假设的证据并不相同。Pod IP 请求成功不代表所有网络层正常,只能说明被观测的请求路径成功。生产环境还可能有多个 replica、NetworkPolicy、服务网格和外部负载均衡器。本课程是一次只改变一个变量、把症状与原因关联起来的基础实验,并非把所有故障归为三类的万能诊断法。
与岗位要求的联系也要划清范围。2026-09-10 查阅的 Canonical SRE 职位 涉及 Linux、Python、网络与 Kubernetes 运维能力。本课程把观测、原因分离与恢复练习转化为学习任务,并不是该公司的招聘考试或合作课程。重点不在背诵大量命令,而在说明检查了哪个层级,并让下一位工程师能够复现同样的观测。
详细诊断顺序可与 Kubernetes 官方 Service 调试文档 对照。本实验中的端口、正文与 namespace 均为教学目的设定。
下一次检查要做什么
在测验中区分 Running、EndpointSlice 与真实 HTTP 的含义。最终模块实验的第 1~3 步会分别把正常基线、selector 错误和 selector 恢复保存为观测 JSON。修复故障后,无法再看到当时的空目标列表,所以必须在恢复前记录。该记录是学员编写的实验笔记,不是不可伪造的审计日志。