headless service 通过将 spec.clusterip 设为 none 实现无头行为,不分配虚拟 ip,dns 直接返回后端 pod 的真实地址;需配合 statefulset 使用以提供稳定 dns 名称(如 mysql-0.mysql-headless.default.svc.cluster.local),并通过 nslookup 验证多 a 记录解析。

Headless Service 不是“启用”某个功能,而是通过明确禁用 ClusterIP 来实现无头行为。核心就一条:把 spec.clusterIP 设为 None,Kubernetes 就不会分配虚拟 IP,DNS 会直接返回后端 Pod 的真实地址。
怎么定义一个 Headless Service
只需在 Service 清单中设置 clusterIP: None,其余结构和普通 Service 一致:
- 必须有
selector,用于匹配目标 Pod(比如app: mysql) -
ports字段仍需定义,指定服务端口与容器端口映射关系 - 名称、命名空间、标签等元信息按需填写,无特殊限制
示例:
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306怎么让 Pod 获得稳定 DNS 名称
单独定义 Headless Service 并不能自动赋予 Pod 固定名字——这需要搭配 StatefulSet:
- StatefulSet 会按顺序创建 Pod,命名为
<name>-0</name>、<name>-1</name>等 - Headless Service 必须在 StatefulSet 的
serviceName字段中被引用 - 此时每个 Pod 会解析出唯一 DNS 名:
mysql-0.mysql-headless.default.svc.cluster.local
重启或重调度后,Pod 名称和对应 DNS 记录保持不变,IP 可能变,但域名始终指向当前实例。
怎么验证它是否生效
不查 ClusterIP(它不存在),而是查 DNS 解析结果:
- 进一个集群内 Pod,执行
nslookup mysql-headless—— 应返回多个 A 记录(每个 Pod 一条) - 执行
nslookup mysql-0.mysql-headless—— 应精确返回该 Pod 的 IP -
kubectl get svc mysql-headless中CLUSTER-IP列显示为None
怎么在应用里真正用起来
客户端不再访问 Service 名,而是基于 DNS 发现做连接决策:
- 数据库客户端可解析
mysql-headless获取全部节点 IP,自行选主/分片 - ZooKeeper 或 Etcd 集群中,各成员通过
zk-0.zk-headless、zk-1.zk-headless相互寻址 - 若需固定访问某实例(如只读副本),直接使用带序号的完整 DNS 名即可











