Skip to content

补充:Kubernetes Service 为什么要用虚拟 IP 而不是 UUID?

本文件记录了对 "Service 中为什么要使用虚拟 IP 而不是 UUID,虚拟 IP 是如何实现的,好处是什么" 这一问题的系统解答。


一、为什么 Service 使用虚拟 IP 而不是 UUID?

1.1 网络协议栈只认识 IP:Port

TCP/UDP 通信的终点是 IP + Port,不是 UUID。如果 Kubernetes 给你一个服务的 UUID,应用程序仍然需要把它解析成 IP 才能建立 socket 连接。

应用调用 connect("uuid-of-service")  →  无法直接通信
应用调用 connect("10.96.123.45:80")  →  正常通信

UUID 只是标识符,没有网络语义。

1.2 UUID 无法直接做负载均衡和路由

Kubernetes Service 的核心能力是把流量分发到多个后端 Pod。负载均衡器、iptables、IPVS、eBPF 这些内核网络机制都是基于 IP 地址工作的。

如果用 UUID,K8s 需要额外开发一套用户态代理来做解析和转发,性能和复杂度都会变差。

1.3 DNS 最终也要解析成 IP

即使通过名字访问服务,比如 curl http://nginx-service,DNS 解析的最后一步也是返回一个 IP 地址:

bash
nslookup nginx-service.default.svc.cluster.local
# 返回:10.96.123.45

所以虚拟 IP 是 Service 的最终暴露形式,名字只是方便人类的入口。


二、ClusterIP 虚拟 IP 是如何实现的?

ClusterIP 是一个不绑定任何网络接口的虚拟 IP。它不会出现在 ip addr 的网卡上,而是通过内核规则"拦截"并转发流量。

2.0 ClusterIP 是"真实 IP"还是"虚拟 IP"?

这个问题需要从两个层面理解:

角度结论原因
从 TCP/IP 协议栈看真实 IP它是从 Service CIDR(如 10.96.0.0/12)里合法分配出来的 IPv4 地址,数据包的目标地址字段里填的就是这个 IP
从网卡/链路层看虚拟 IP没有任何网卡(物理网卡、veth、bridge、dummy 等)配置上这个 IP,ip addr 也看不到它
从"谁持有这个 IP"看虚拟 IP网络中没有设备会 ARP 回应这个 IP,内核只是通过规则"假装"这个地址存在并拦截流量

内核没有给 ClusterIP 创建虚拟网卡。 流量不是先到达某个"虚拟网卡"再被转发,而是直接在内核网络协议栈的转发路径上被截获:

  • iptables 模式:通过 PREROUTING / OUTPUT 等 netfilter 钩子,匹配目的 IP 为 ClusterIP 的数据包,直接做 DNAT 到 Pod IP。
  • IPVS 模式:在内核的 IPVS 子系统里注册一个 Virtual Server(VS),把 ClusterIP:Port 当作 VS 的"服务地址",再调度到 Real Server(Pod IP)。
  • eBPF 模式:在 socket 或 XDP/TC 层用 eBPF 程序改写目的地址。

所以更准确的说法是:ClusterIP 是"逻辑上真实、物理上不存在"的地址。内核认识它、规则匹配它,但它不绑定任何接口,也没有对应的网卡。

Kubernetes 通过 kube-proxy 组件来实现,主要有两种模式:

2.1 iptables 模式(传统默认)

text
客户端 Pod
    |
    v
访问 10.96.123.45:80
    |
    v
iptables PREROUTING 链匹配到这条规则:
    -d 10.96.123.45 --dport 80  -j DNAT --to-destination 10.244.1.5:80 或 10.244.2.7:80
    |
    v
随机选择一个后端 Pod IP

kube-proxy 会:

  1. 监听 API Server 中 Service 和 Endpoint(EndpointSlice)的变化
  2. 在节点上动态创建/更新 iptables 规则
  3. 访问 ClusterIP 时,iptables 做 DNAT,把目标 IP 改成后端 Pod IP
  4. 负载均衡通过 iptables 的 statistic 模块实现随机分发

2.2 ipvs 模式(生产推荐)

text
客户端 Pod
    |
    v
访问 10.96.123.45:80
    |
    v
IPVS 虚拟服务器(VS):10.96.123.45:80
    |
    +--> 真实服务器 RS1: 10.244.1.5:80
    +--> 真实服务器 RS2: 10.244.2.7:80

kube-proxy 会:

  1. 为每个 Service 创建一个 IPVS 虚拟服务器(Virtual Server)
  2. 每个后端 Pod 作为真实服务器(Real Server)
  3. 支持多种负载均衡算法:rr(轮询)、lc(最少连接)、sh(源地址哈希)等

ipvs 性能更好、规则更清晰、支持更多调度算法,大规模集群建议用 ipvs。

2.3 eBPF 模式(未来趋势)

Cilium 等新型 CNI 直接用 eBPF 在数据路径实现 Service 负载均衡,绕过 iptables/ipvs,性能更高。


三、使用虚拟 IP 的好处

好处说明
兼容现有网络应用无需改造,使用标准 IP:Port 访问
稳定的访问入口Pod IP 会变化,但 ClusterIP 不变
自动负载均衡流量自动分发到多个后端 Pod
服务发现简单配合 CoreDNS,可用域名访问
与内核集成利用 iptables/ipvs/eBPF 高效转发
支持多种类型ClusterIP、NodePort、LoadBalancer 都基于同一套虚拟 IP 机制
故障自愈Pod 重建后 IP 变了,Service 后端自动更新,客户端无感知

四、实例理解

假设有一个 Service:

yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
  type: ClusterIP

创建后:

bash
kubectl get svc nginx
# NAME    TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)
# nginx   ClusterIP   10.96.123.45   <none>        80/TCP

kubectl get endpoints nginx
# NAME    ENDPOINTS
# nginx   10.244.1.5:80,10.244.2.7:80

在节点上查看规则(ipvs 模式):

bash
ipvsadm -Ln
# TCP  10.96.123.45:80 rr
#   -> 10.244.1.5:80              Masq    1      0          0
#   -> 10.244.2.7:80              Masq    1      0          0

当 Pod 访问 10.96.123.45:80 时,内核把请求转发到 10.244.1.5:8010.244.2.7:80


五、一句话总结

Service 的 ClusterIP 是"逻辑上的入口",iptables/ipvs/eBPF 是"物理上的转发"。

  • 不用 UUID:UUID 没有网络语义,无法直接用于 TCP/UDP 通信和负载均衡。
  • 虚拟 IP 实现:ClusterIP 不绑定网卡,由 kube-proxy 通过 iptablesipvs 规则将流量 DNAT 到后端 Pod IP。
  • 核心好处:提供稳定、兼容、可负载均衡的服务访问入口,让客户端无需关心后端 Pod 的变化。