不给虚拟 IP 的服务
Headless Service 是不分配集群虚拟 IP 的 Service(把 clusterIP 设为 None):查询服务名时,DNS 直接返回各个后端 Pod 的地址列表,而不是一个统一的代理地址。有状态集群的稳定 DNS 标识与自研服务发现都依赖它,因为客户端需要看到全部实例,而不是被隐藏在一层转发之后。
基本信息
| 声明方式 | spec.clusterIP 设为 None |
|---|---|
| DNS 行为 | 查询服务名得到全部就绪 Pod 的地址记录 |
| 单实例访问 | Pod 名.服务名.命名空间.svc.cluster.local 可直达指定实例 |
| 典型搭配 | StatefulSet 通过 serviceName 关联,自研选主与分片逻辑 |
| 对比普通 Service | 普通 Service 的 DNS 只返回一个集群地址,看不到后端列表 |
| 无选择器时 | 可手工维护端点对象,用于把外部服务以固定名称接入集群 |
典型使用场景
- 有状态数据库集群的节点发现与成员管理
- 分片与选主逻辑需要完整的实例视图
- 客户端自己做负载均衡(如一致性哈希)的场景
- 在集群内按实例名精确访问某个副本
- 把集群外部的服务以固定名称接入,由手工端点维护地址
Headless 示例与验证
Headless 示例与验证
apiVersion: v1
kind: Service
metadata:
name: db-headless
spec:
clusterIP: None # 无头服务:不分配虚拟 IP
selector:
app: db
ports:
- port: 3306
targetPort: 3306
# 验证
kubectl get svc db-headless -o jsonpath='{.spec.clusterIP}' # 应输出 None
kubectl run -it --rm netshoot --image=nicolaka/netshoot -- nslookup db-headless.default.svc.cluster.local检查项读法
| 检查项 | 正常表现 | 异常表现 |
|---|---|---|
| clusterIP | 显示 None | 显示具体地址说明不是无头服务 |
| 服务名 DNS 查询 | 返回多个后端地址 | 只返回一个地址说明是普通 Service |
| 单实例名查询 | 解析到对应 Pod 地址 | 解析失败说明实例名或命名空间写错 |
| Endpoints | 列出全部就绪后端 | 为空说明选择器不匹配或 Pod 未就绪 |
| 未就绪实例 | 默认不出现在 DNS 结果中 | 客户端拿到未就绪地址说明发布策略被改动过 |
客户端拿到多个地址后如何选择由应用决定:数据库类场景常见「连第一个可用实例」或按分片路由。无头服务本身不提供负载均衡与故障转移,重试与健康检查要由客户端实现。
把无头服务当负载均衡用会出问题:DNS 多值轮询不是四层负载均衡,客户端可能持续命中同一实例,或反复尝试已经故障的地址,表现为「扩容了但压力没分散」。