首页/云/Kubernetes 速查/Headless 与 ClusterIP 的行为差异
网络与服务55 条

Headless 与 ClusterIP 的行为差异

Headless(clusterIP: None)不分配虚拟 IP,DNS 直接返回后端 Pod IP;ClusterIP 返回虚拟 IP 由 kube-proxy 转发。两者用途不同。

Kubernetes 速查云更新于 2026-10-13

Headless 与 ClusterIP 是什么

两者都是 Service,差别在有没有虚拟 IP。ClusterIP 会分配一个仅集群内可达的虚拟地址,kube-proxy 把访问这个地址的流量转发到后端 Pod;Headless 把 clusterIP 显式写成 None,不分配虚拟地址,集群 DNS 直接返回后端 Pod 的地址列表,由客户端挑一个连。选择哪一种,本质上是在选「谁来负载均衡」。

基本信息

关键字段spec.clusterIP: None 表示 Headless
DNS 返回Headless 返回 Pod 地址列表,ClusterIP 返回一个虚拟地址
转发主体Headless 由客户端直连,ClusterIP 由 kube-proxy 转发
后端来源两者都由选择器匹配 Pod,或由手工 EndpointSlice 提供
常见搭配StatefulSet 的 serviceName 必须指向 Headless Service

行为对比

维度ClusterIPHeadless
DNS 返回一个虚拟 IP就绪 Pod 的地址列表
流量路径kube-proxy 规则做四层转发客户端直连某个 Pod
负载均衡由 kube-proxy 承担由客户端库或应用自行实现
端口与协议可映射任意端口,支持 TCP/UDP端口由 Pod 实际监听决定,配合 SRV 记录做发现
典型场景无状态服务的统一入口有状态集群互发现、自定义均衡、直连每个实例

创建与验证

创建与验证
apiVersion: v1
kind: Service
metadata:
  name: db-headless
  namespace: prod
spec:
  clusterIP: None            # 关键:不分配虚拟 IP
  selector:
    app: db
  ports:
    - name: mysql
      port: 3306
      targetPort: 3306

对比解析结果

对比解析结果
kubectl get svc db-headless -o jsonpath='{.spec.clusterIP}'      # 输出 None
kubectl get endpointslices -n prod -l kubernetes.io/service-name=db-headless   # 后端地址来源
kubectl run dns-test --rm -it --restart=Never --image=busybox:1.36 -- \
  nslookup db-headless.prod.svc.cluster.local                     # 返回多个 Pod 地址
kubectl run dns-srv --rm -it --restart=Never --image=busybox:1.36 -- \
  nslookup -type=SRV _mysql._tcp.db-headless.prod.svc.cluster.local   # 带端口的服务发现

典型使用场景

  • 有状态集群互发现:数据库、消息队列的节点需要互相拿到对方地址
  • 稳定网络标识:StatefulSet 配合 Headless 得到 实例名.服务名 这样的固定名字
  • 客户端自定义均衡:应用自己维护连接池并挑选实例,不希望中间再转一层
  • 直连排查:需要确认流量真正落到哪个 Pod,绕开虚拟地址更容易定位
  • 无选择器直连外部地址:用手工 EndpointSlice 把集群外的地址直接暴露成服务名
Headless 的 DNS 默认只返回就绪 Pod:滚动重启期间列表会动态变化,未就绪的实例不在应答里。需要把未就绪地址也发布出去时,设置 publishNotReadyAddresses: true,但要清楚这样客户端可能连到还没准备好的实例。
ClusterIP 模式下业务拿到的是一个虚拟地址,看不到真实后端;排查时先用 kubectl get endpointslices 确认后端列表,再决定是查 kube-proxy 规则还是查 Pod 本身。

易错点

  • 业务代码假设有固定连接地址:Headless 返回的是会随扩缩容变化的地址列表,需要发现逻辑或支持多地址的客户端库
  • 给 Headless 写 clusterIP 值:该字段只能是 None,写了具体地址会被校验拒绝
  • 拿 Headless 当统一入口:没有虚拟 IP 也没有自动均衡,把它当普通 Service 用会放大单实例压力
  • 忽略未就绪地址被排除:缩容或滚动重启时列表变化,客户端连接池里可能残留已下线的地址
  • 手工 EndpointSlice 不随目标变化更新:地址失效后解析仍然成功,故障表现为连接超时而不是解析失败

数据来源与参考

  • Kubernetes 官方文档 · Headless Services
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌