机制定位
Headless Service 把 clusterIP 设为 None,不分配虚拟 IP,DNS 查询直接返回后端 Pod 的地址列表;再配合 StatefulSet 的稳定命名,每个副本还独享一条 <pod>.<svc>.<ns>.svc.cluster.local 记录。适用平台是 Kubernetes。这是有状态集群(数据库、消息队列、ZK/etcd 类)互相发现的基石:客户端需要知道具体是哪一个实例,而虚拟 IP 只能做无差别转发。
基本信息
| 适用平台 | Kubernetes,Service 与 StatefulSet 配合 |
|---|---|
| Headless 标志 | spec.clusterIP: None |
| 记录形式 | 服务级 <svc>.<ns>.svc.cluster.local、Pod 级 <pod>.<svc>.<ns>.svc.cluster.local |
| 就绪影响 | 未就绪的 Pod 默认不进可用后端,可用 publishNotReadyAddresses 改变 |
典型使用场景
- 数据库主从发现:客户端按固定名字连接某个具体实例
- 集群成员配置:把 Pod 级 DNS 名写进集群的成员列表
- 滚动重启期间的连接保序:先连指定序号再重建
- 排查连接错实例:确认解析返回的是 Pod 地址列表还是虚拟 IP
- 无头服务的调试:用临时 Pod 逐个解析各实例名字验证暴露情况
Headless Service
Headless Service
apiVersion: v1
kind: Service
metadata:
name: db-headless
spec:
clusterIP: None
selector:
app: db
ports:
- name: pg
port: 5432DNS 记录验证
DNS 记录验证
kubectl run dns-test --rm -it --image=busybox:1.36 --restart=Never -- sh
# 容器内:
nslookup db-headless.prod.svc.cluster.local
nslookup db-0.db-headless.prod.svc.cluster.local
nslookup db-1.db-headless.prod.svc.cluster.local
kubectl get endpoints db-headless # 对比 DNS 返回的地址列表
kubectl get pods -l app=db -o wide # 核对实例与就绪状态两种 Service 的差别
| 对比项 | ClusterIP | Headless |
|---|---|---|
| 解析结果 | 返回虚拟 IP | 返回后端 Pod 地址列表 |
| 客户端选择 | 由 kube-proxy 转发决定 | 客户端自行选择实例 |
| 每实例记录 | 无 | 有(StatefulSet 场景) |
| 适用场景 | 无状态服务的负载均衡入口 | 有状态集群的成员发现 |
Pod 级 DNS 形如 <pod>.<headless-svc>.<ns>.svc.cluster.local;Headless 的 DNS 直接返回 Pod IP 列表,由客户端自行选择,因此负载均衡策略落在客户端。
未就绪的 Pod 默认不会出现在可用地址里,重建期间成员列表会短暂缺少该实例,集群软件要能容忍这种情况。
落地时的核对点
- 确认 StatefulSet 的 serviceName 指向 Headless Service,写错时 Pod 级记录不会生成
- 确认 Pod 就绪:未就绪的实例默认不解析,重建期间成员列表会短暂变短
- 确认客户端行为:Headless 不提供转发,连接失败要由客户端重试与重选实例
- 确认证书与成员配置使用了 Pod 级名字,改 serviceName 时要同步更新这两处