【k8s、docker】Headless Service(无头服务)

发布于:2025-08-18 ⋅ 阅读:(14) ⋅ 点赞:(0)

问题背景

zookeeper ClusterIP None 这中svc作用是什么,为什么没有cluster ip

1、什么是Headless Service

在 Kubernetes 中,ClusterIP 类型的 Service 被设置为 None(即 ClusterIP: None)时,表示这是一个 Headless Service(无头服务)。这种设计有特定的用途和行为模式:
Headless Service 的核心作用:

  1. 直接访问 Pod IP,跳过 Service 代理

    • 普通 Service:会分配一个虚拟 ClusterIP,流量通过 kube-proxy 负载均衡到后端 Pod。

    • Headless Service:没有 ClusterIP,DNS 查询直接返回所有后端 Pod 的 IP 地址(而非 Service 的虚拟 IP)。

  2. 适用场景

  • 有状态应用(如 Zookeeper、Kafka、MongoDB):需要直接访问特定 Pod(如通过 Pod 域名)。

  • 自定义服务发现:应用需要自行处理负载均衡或直接连接 Pod。

  • StatefulSet 配套使用:StatefulSet 的 Pod 具有稳定的域名(如 pod-name.svc-name.namespace.svc.cluster.local)。

1.2 为什么 Zookeeper 使用 Headless Service?

简单来说,当一个pod 是sts类型,每个副本的名称,都是固定的(固定名称是前提,不像deployment生成的pod都会带随机字符串 ),如 zk-0、zk-1,此时需要无头服务,被访问时,都是指定访问,不能直接负载均衡随机调度。

Zookeeper 是一个有状态分布式协调服务,它的典型配置需求:

支持应用层的负载均衡或服务发现:

  • 客户端应用(或应用内置的逻辑)可以获取到所有后端 Pod 的 IP 列表,然后自己决定如何连接(例如,轮询、根据角色选择 leader 等)。
  • 对于像 ZooKeeper 这样的集群,成员之间需要互相知道彼此的地址来形成集群,Headless Service 提供了完美的解决方案。

支持直接的 Pod-to-Pod 通信:

  • 当你需要直接连接到某个特定的 Pod 实例时(比如访问主节点进行写操作,或进行健康检查),可以通过其唯一的 DNS 名称直接访问。:StatefulSet + Headless Service 能为每个 Pod 提供固定域名

1.2 Headless Service 的 DNS 行为

对于 Service zookeeper:

  • 普通查询(非 Headless):

    nslookup zookeeper.mano-2.svc.cluster.local
    

    返回一个虚拟 ClusterIP。

  • Headless 查询:

    nslookup zookeeper.mano-2.svc.cluster.local
    

    返回所有后端 Pod 的 IP 地址(例如):

    Name:   zookeeper.mano-2.svc.cluster.local
    Address: 10.244.1.10  # zk-0 的 IP
    Address: 10.244.2.20  # zk-1 的 IP
    Address: 10.244.3.30  # zk-2 的 IP
    

如果您的 ZooKeeper StatefulSet 有 3 个副本,名为 zk-0, zk-1, zk-2,那么 DNS 会解析:

  • zookeeper.default.svc.cluster.local -> 返回 zk-0, zk-1, zk-2 的 IP 地址列表(A 记录)。
  • zk-0.zookeeper.default.svc.cluster.local -> 返回 zk-0 Pod 的 IP 地址。
  • zk-1.zookeeper.default.svc.cluster.local -> 返回 zk-1 Pod 的 IP 地址。
  • zk-2.zookeeper.default.svc.cluster.local -> 返回 zk-2 Pod 的 IP 地址。

1.3 验证示例

1、查看 Service 定义

kubectl get svc zookeeper -o yaml
输出关键字段:

spec:
  clusterIP: None  # 明确标记为 Headless
  ports:
  - port: 2181
    targetPort: 2181
  selector:
    app: zookeeper

2、通过 DNS 直接访问 Pod
每个 StatefulSet 的 Pod 会获得独立域名:

# 查询单个 Pod 的 DNS
nslookup zk-0.zookeeper.mano-2.svc.cluster.local

# 客户端连接示例(Zookeeper 客户端)
zkCli.sh -server zk-0.zookeeper:2181,zk-1.zookeeper:2181,zk-2.zookeeper:2181

与普通 Service 的对比:

特性 Headless Service 普通 Service
ClusterIP None 自动分配虚拟 IP (如 10.96.x.x)
DNS 解析结果 返回所有 Pod IP 返回 Service 的 ClusterIP
负载均衡 由客户端或应用层实现 由 kube-proxy 实现(iptables/IPVS)
典型应用场景 有状态服务(如 Zookeeper、MySQL) 无状态服务(如 Nginx、微服务)

1.4 如何创建 Headless Service?

Headless 示例:

apiVersion: v1
kind: Service
metadata:
  name: zookeeper
  namespace: default
spec:
  clusterIP: None # 这是关键,指定为 None
  ports:
  - port: 2181
    name: client
  - port: 2888
    name: server
  - port: 3888
    name: leader-election
  selector:
    app: zookeeper # 选择后端 Pod 的标签
  # 注意:Headless Service 通常不指定 type,默认就是 ClusterIP
  • clusterIP: None:这不是“不想要 IP”,而是明确地、主动地要求创建一个 Headless Service(无头服务)。它告诉 Kubernetes:“我不要你为这个服务分配一个虚拟的 ClusterIP,我要直接访问后端的 Pod”。
  • 自动分配 ClusterIP:这是 Kubernetes Service 的默认行为。你不需要做任何特殊配置来“开启”自动分配。

有头示例:

apiVersion: v1
kind: Service
metadata:
  name: my-web-service
spec:
  # 注意:这里完全不写 clusterIP 字段
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
      name: http
  selector:
    app: my-web-app
  # type: ClusterIP # type 字段也可以省略,默认就是 ClusterIP

当你创建这个 Service 时,Kubernetes 会:

  • 自动从集群的 Service IP 池(由 --service-cluster-ip-range 参数定义)中选择一个可用的 IP 地址。
  • 将这个 IP 地址分配给该 Service。
  • 你可以在 kubectl get svc 的输出中看到这个分配的 IP(不再是 None)。

2. zk-0.zookeeper.default.svc.cluster.local 域名是如何创建出来的? 是无头服务自动映射的吗

是的,zk-0.zookeeper.default.svc.cluster.local 这个域名是由 Kubernetes 的 Headless Service(无头服务)机制自动创建的,其核心原理依赖于 Kubernetes DNS 系统(如 CoreDNS)的自动服务发现功能。

下面简述其工作原理:

1、 前提条件:Headless Service + StatefulSet
这个域名的自动生成,通常发生在以下组合中:

  • 一个 Headless Service:clusterIP: None
  • 一个 StatefulSet:管理有状态应用的 Pod,如 zk-0, zk-1, zk-2

2、DNS 自动映射原理
当满足上述条件时,Kubernetes DNS 组件(如 CoreDNS)会根据以下规则自动为每个 Pod 生成稳定的 DNS 记录:

规则一:Pod 主机名 DNS 记录
对于每一个由 StatefulSet 创建的 Pod(如 zk-0),DNS 会生成一条 A 记录:

<pod-name>.<service-name>.<namespace>.svc.cluster.local  -->  <pod-ip>

在你的例子中:

pod-name = zk-0
service-name = zookeeper
namespace = default
cluster.local = 集群默认域名

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到