7.3 Service 与 Ingress
一句话
Service 是 “一个稳定的虚拟 IP + 一组随时变化的 Endpoint”,Ingress 是 “一张七层路由表”;前者解决 “Pod IP 会变”,后者解决 “一个入口怎么分发给多个 Service”——两者都不做流量治理(限流、熔断、鉴权在别处)。
Service 的四种类型
| 类型 | 可从哪访问 | 代价 | 典型用途 |
|---|---|---|---|
| ClusterIP | 集群内 | 无 | 服务间调用(默认) |
| NodePort | 节点 IP + 30000–32767 端口 | 端口有限、暴露节点、无健康检查 | 调试、临时暴露 |
| LoadBalancer | 云 LB 的公网/内网地址 | 每个 Service 一个 LB,成本随服务数涨 | 少量需独立 IP 的服务 |
Headless(clusterIP: None) | 直接返回 Pod IP 列表 | 客户端自己做负载均衡与发现 | StatefulSet、客户端分片 |
Endpoint 才是真相:Service 只是引用
Service(selector: app=web) ──► EndpointSlice ──► [10.1.2.3:8080, 10.1.3.7:8080]
▲
只收 readiness 通过的 Pod
| 现象 | 原因 |
|---|---|
| Service 有 IP,但请求超时 | Endpoint 为空:没有 Pod 通过 readiness,或 selector 拼错 |
| 部分请求失败 | Endpoint 里有未就绪的 Pod(没配 readinessProbe) |
| 滚动更新时零星 502 | 摘除 Endpoint 与进程退出存在竞态(优雅下线没做对) |
| 改了 Pod 标签后流量断 | Service 按标签挑 Pod,改标签等于换成员 |
排查顺序固定为:kubectl get endpointslices -l kubernetes.io/service-name=<svc> → 有没有地址 → 再查 Pod readiness。
kube-proxy 三种转发模式
| 模式 | 机制 | 特点 |
|---|---|---|
| iptables | 每条 Service 生成 DNAT 规则,随机选 Endpoint | 通用;连接多时规则多、更新慢;无真正负载均衡(概率均分) |
| IPVS | 内核哈希表 + 多种调度算法 | 大规模更稳、支持 rr/lc 等算法;需要内核模块 |
| eBPF(Cilium 等) | 绕过 iptables,用 eBPF 程序转发 | 性能最好、可观测性强;排错要换工具链 |
两种 “保留客户端 IP” 的开关要分清:
externalTrafficPolicy: Local:只把流量转给本节点上的 Pod,源 IP 得以保留,但流量分布不均(节点上没 Pod 就丢)。sessionAffinity: ClientIP:同一客户端固定到同一 Pod,代价是负载不均、Pod 重启后粘性失效。
Ingress:只做七层路由
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
spec:
ingressClassName: nginx # 必须有,否则会被忽略
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend: {service: {name: api, port: {number: 8080}}}
- path: /
pathType: Prefix
backend: {service: {name: web, port: {number: 80}}}
tls:
- hosts: [app.example.com]
secretName: app-tls
kubectl get ingress web
# NAME CLASS HOSTS ADDRESS PORTS AGE
# web nginx app.example.com 10.0.0.12 80,443 5m
kubectl describe ingress web | tail -5 # 看后端 Endpoint 是否解析出来
四条判据:ingressClassName 是否匹配、pathType 是否写清(Prefix / Exact)、TLS Secret 是否在同命名空间、后端 Service 是否有 Endpoint。四条都过,剩下才是 Ingress Controller 自身配置。
Ingress 的表达力天花板:它只覆盖 “host + path → service”,做不了 header/权重/重试/超时(各控制器用自己的注解补,互不兼容)。需要这些能力时,方向是 Gateway API(HTTPRoute 等)或服务网格,而不是继续堆注解。
反模式
| 反模式 | 后果 |
|---|---|
| 不给 Pod 配 readinessProbe | Endpoint 包含未就绪 Pod,滚动更新必炸 |
| 用 NodePort 当生产入口 | 无健康检查、暴露节点、端口冲突难管 |
| 每个服务一个 LoadBalancer | 云账单随服务数线性上涨 |
| Ingress 里做鉴权与限流 | 注解碎片化,换控制器就重写;治理逻辑应在网关/网格 |
| 客户端硬编码 Service IP | Service 重建后 IP 变化(ClusterIP 也可能变),调用全挂 |
用 ping 测 ClusterIP | ClusterIP 是虚拟 IP,ICMP 通常不转发,ping 不通不代表服务不通 |
忘了 ingressClassName | Ingress 被静默忽略,表现为 “404 但配置看着没问题” |
三条铁律
🔑 Service 靠 Endpoint 转发:先看 Endpoint 再看 Service,顺序反了会浪费半小时。
🔑 readiness 决定 “能不能接流量”;没有它,Service 只是把流量赌在运气上。
🔑 入口治理分层:Service 管连通、Ingress 管路由、网关/网格管限流鉴权;混在一起必然碎片化。
自检
Q1 Service 的 ClusterIP 能 ping 通吗?为什么?
▸ 答案:通常不能,而且这不说明服务坏了。ClusterIP 是 kube-proxy(或 eBPF)在数据面实现的虚拟地址,不落在任何网卡上;ICMP 一般不被 DNAT 规则处理,所以 ping 无响应。验证连通性要用 curl/nc 打具体端口,或看 endpointslices 是否有地址。
Q2 滚动更新时出现零星 502,Service/Endpoint 层面最可能的原因是什么?
▸ 答案:摘除与退出存在竞态:kubelet 在收到删除请求时,Endpoints 摘除与 SIGTERM 几乎同时发生,而 kube-proxy 的规则更新有延迟,于是 “流量还在进来,进程已经开始退出”。修法三件套:preStop 里 sleep 几秒、terminationGracePeriodSeconds 留足、应用收到 SIGTERM 后先停止接新连接再优雅关闭。
Q3 externalTrafficPolicy: Local 有什么代价?
▸ 答案:流量分布不均:只有本节点上有 Pod 时才转发,没有就丢弃(不会跨节点转)。好处是保留客户端源 IP(否则经过 SNAT 后只能看到节点 IP),对风控与审计很重要。取舍是:要么用 LB 的 “节点本地健康检查” 配合,要么接受部分节点没有 Pod 时的可用性下降。
Q4 为什么 Ingress 的 YAML 看起来正确,访问却是 404?
▸ 答案:四查:① ingressClassName 与集群里实际安装的 Controller 不匹配(最常见的静默忽略);② pathType 写成 Prefix 但 Controller 是老版本不认;③ 后端 Service 在同命名空间但没有 Endpoint;④ TLS Secret 缺失导致整条规则不生效。判断方法:kubectl describe ingress 看 Address 是否被 Controller 填上,以及后端 Endpoint 是否列出。
Q5 什么时候该从 Ingress 换到 Gateway API?
▸ 答案:当需求出现 header/query 级路由、按权重灰度、重试与超时策略、跨命名空间的路由归属 时。Ingress 用注解实现这些,导致 “换控制器即重写”;Gateway API 把这些变成一等字段(HTTPRoute 的 matches/filters/backendRefs),且支持角色分离(基础设施 owner 管 Gateway,应用管 Route)。只是 “host + path” 的话,Ingress 足够且更简单。
跨篇相关:Service 的虚拟 IP 与四层/七层的分工见 8.9 四层与七层负载均衡;反向代理与转发策略见 8.10 反向代理与转发策略;API 网关与入口治理见 47.2 API 网关、47.4 鉴权与限流应放在哪一层;Endpoint 的成员来自 Pod 就绪状态,见 7.6 自愈、滚动更新与回滚;网络策略见 [7.8 网络模型[7.8 网络模型 (CNI / NetworkPolicy);对象与选择器语义见 7.2 K8s 对象模型 (Pod / ReplicaSet / Deployment / StatefulSet / DaemonSet / Job)。