1. 概述

在 Kubernetes 中,Service 是一种用于为一个或多个 Pod 提供统一访问入口的资源。它通过一个统一的 IP 和域名将一组 Pod 暴露给网络。当请求到达 Service 时,Kubernetes 的 kube-proxy 会将其转发到其中一个后端 Pod。

Headless Service 是一种特殊的 Service,它不分配 ClusterIP,这意味着它不会提供负载均衡能力,但可以直接暴露后端 Pod 的 IP 地址。这种特性在某些场景下非常有用,比如需要直接访问某个 Pod 的情况。

本文将介绍 Headless Service 的基本配置方式,并通过实际演示展示其典型应用场景。

2. 什么是 Headless Service

Headless Service 就是 不分配 ClusterIP 的 Service。在定义时,只需要将 spec.clusterIP 字段设置为 None 即可。

以下是一个 Headless Service 的 YAML 示例:

apiVersion: v1
kind: Service
metadata:
  name: headless-svc
spec:
  clusterIP: None
  selector:
    app: web
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

创建完成后,可以使用如下命令验证其 clusterIP 是否为 None

$ kubectl get svc -o go-template='{{ .spec.clusterIPs }}' headless-svc
[None]

注意:Kubernetes 控制平面不会为 Headless Service 分配 ClusterIP。

3. Headless Service 的特性

普通 Service 在 DNS 解析时会返回一个固定的 ClusterIP,而 Headless Service 则会返回所有匹配 Pod 的 IP 地址列表。这使得我们可以直接访问特定 Pod,而不是通过负载均衡器。

举个例子:

  • ✅ 普通 Service:DNS 返回单个 IP(ClusterIP)
  • ✅ Headless Service:DNS 返回多个 IP(每个 Pod 的 IP)

这种机制非常适合需要访问具体 Pod 的场景,比如:

  • 监控服务直接向每个 Pod 发送健康检查
  • 状态类服务(如数据库)需要固定访问某个 Pod

4. 实战演示

接下来我们通过一个实际例子来演示 Headless Service 的使用。

4.1. 创建 Headless Service

首先创建一个 Headless Service:

$ kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: headless-svc-stateful
spec:
  clusterIP: None
  selector:
    app: web-stateful
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
EOF

4.2. 创建 StatefulSet

接下来创建一个 StatefulSet,部署三个 Pod:

$ kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: app-stateful
  labels:
    app: server-stateful
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-stateful
  serviceName: headless-svc-stateful
  template:
    metadata:
      labels:
        app: web-stateful
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
EOF

注意:StatefulSet 必须指定 serviceName,且必须指向已有的 Headless Service。

创建完成后,查看 Pod 状态:

$ kubectl get pods -l app=web-stateful
NAME             READY   STATUS    RESTARTS   AGE
app-stateful-0   1/1     Running   0          32m
app-stateful-1   1/1     Running   0          31m
app-stateful-2   1/1     Running   0          31m

4.3. 创建调试容器

为了测试 DNS 解析,我们需要一个包含 nslookup 的调试容器。可以使用 kubectl debug 命令创建一个临时容器:

$ kubectl debug -it app-stateful-0 --image=slongstreet/bind-utils:latest -- bash
Defaulting debug container name to debugger-2crmp.
$

4.4. 解析 Headless Service 的 IP

在调试容器中执行 DNS 查询:

$ nslookup headless-svc-stateful
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   headless-svc-stateful.default.svc.cluster.local
Address: 10.244.0.11
Name:   headless-svc-stateful.default.svc.cluster.local
Address: 10.244.0.12
Name:   headless-svc-stateful.default.svc.cluster.local
Address: 10.244.0.10

结果说明:返回了三个 Pod 的 IP 地址。

4.5. 解析特定 Pod 的 IP

如果需要解析某个特定 Pod 的 IP,可以使用如下格式:

<Pod名称>.<Service名称>

例如查询 app-stateful-1 的 IP:

$ nslookup app-stateful-1.headless-svc-stateful
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   app-stateful-1.headless-svc-stateful.default.svc.cluster.local
Address: 10.244.0.11

结果说明:只返回了 app-stateful-1 的 IP。

5. 总结

Headless Service 是 Kubernetes 中一种非常有用的 Service 类型,尤其适用于以下场景:

  • 需要直接访问 Pod IP 的情况
  • 使用 StatefulSet 部署有状态应用
  • 需要对每个 Pod 进行独立健康检查

它通过 DNS 返回 Pod 列表的方式,使得服务发现更加灵活,避免了负载均衡带来的不确定性。

Headless Service 的核心价值
让服务发现更精细,让 Pod 地址可见


原始标题:Kubernetes Headless Service