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)。