无头服务
无头服务(Headless Service)是 Kubernetes 中的一种特殊服务类型,主要用于提供稳定的网络标识,而不需要通过负载均衡来分配流量。它允许直接访问 Pod,而不经过集群内的负载均衡器,并且通常用于有状态的应用场景(如 StatefulSet)。无头服务的典型用例是数据库、缓存、或者有状态的集群应用。
无头服务的特点
- 没有 Cluster IP:与普通服务不同,无头服务不分配
ClusterIP
,因此不会通过服务的 IP 地址进行负载均衡。 - 直接解析到 Pod IP:当客户端通过无头服务的 DNS 名称查询时,Kubernetes 会直接返回与该服务匹配的 Pod 的 IP 地址列表。客户端可以直接与这些 Pod 通信。
- 有状态应用:无头服务常用于有状态的应用,如 Kafka、Elasticsearch、Zookeeper 等,这类应用需要能够直接访问特定 Pod,而不是通过负载均衡器随机访问。也会通常与 StatefulSet 结合使用,以便于有状态应用能够通过稳定的网络标识直接访问各个 Pod
- 自定义负载均衡:在某些情况下,应用可能希望自己管理负载均衡,而不依赖 Kubernetes 提供的负载均衡功能。
无头服务的 DNS 解析
无头服务的 DNS 解析与普通服务不同。普通服务通过单个 ClusterIP 提供服务,而无头服务返回的 DNS 记录是所有匹配的 Pod 的 IP 地址列表。以下是几种 DNS 解析方式:
- Pod 级别的 DNS 解析:客户端可以通过
<pod-name>.<svc-name>.namespace.svc.cluster.local
直接访问特定 Pod。 - 服务级别的 DNS 解析:无头服务会返回一个包含所有相关 Pod 的 IP 地址的列表,客户端可以选择其中一个进行通信。
无头服务与 Pod 的关联
无头服务(Headless Service)与 Pod 的关联主要是通过选择器(selector)来完成的。无头服务通过选择器将流量路由到符合条件的 Pod,而 Deployment 负责创建和管理这些 Pod,它定义了要运行的 Nginx Pod 的副本和配置。使用标签(label)来标识这些 Pod。Kubernetes 中的服务选择器只能选择与服务位于同一命名空间中的 Pod。因此,定义无头服务的 selector
必须匹配它所管理的 Pod 的标签,而这些 Pod 必须在同一命名空间中。
关联流程
- 创建 Deployment:Deployment 会创建多个 Pod,并将这些 Pod 赋予
app: nginx
标签。 - 创建无头服务:无头服务根据选择器
app: nginx
查找所有带有该标签的 Pod。 - DNS 解析:无头服务会为每个 Pod 创建 DNS 记录,格式为
<pod-name>.nginx-headless.<namespace>.svc.cluster.local
,允许直接通过 DNS 名称访问每个 Pod。
创建无头服务
要创建一个无头服务,只需在服务的 spec
中将 clusterIP
字段设置为 None
。以下是一个创建无头服务的示例:
apiVersion: v1
kind: Service
metadata:
name: nginx-headless
namespace: test
spec:
clusterIP: None # 无头服务,不分配 ClusterIP
selector:
app: nginx-headless # 选择带有 app: nginx 标签的 Pod
ports:
- port: 80
targetPort: 80
clusterIP: None
:表示这是一个无头服务,不会分配 ClusterIP。无头服务直接返回匹配 Pod 的 IP 地址。selector: app: nginx-headless
:选择所有带有app: nginx-headless
标签的 Pod。ports
:定义服务监听的端口和目标端口,port: 80
是服务端口,targetPort: 80
是 Pod 上的容器端口。
创建 nginx deployment
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-headless
name: nginx-headless
namespace: test
spec:
replicas: 2
selector:
matchLabels:
app: nginx-headless
template:
metadata:
labels:
app: nginx-headless
spec:
containers:
- image: m.daocloud.io/docker.io/library/nginx:latest
name: nginx
ports:
- name: http
containerPort: 80 #容器端口
metadata.labels
和spec.selector.matchLabels
:确保 Deployment 和 Service 的标签匹配,使无头服务能够选择这些 Pod。replicas: 2
:指定运行两个 Nginx Pod。template.metadata.labels
:Pod 模板中的标签,确保 Pod 带有app: nginx-headless
标签。containers
:定义容器的镜像和端口设置,containerPort: 80
是容器中的端口。
测试
测试部署的 nginx 的 PodIP 分别为
pod/nginx-headless-69db456d87-k4x4b 10.244.2.212 node2
pod/nginx-headless-69db456d87-ztdt4 10.244.1.62 node1
本地测试
测试本地服务解析
<service>.<namespace>.svc.cluster.local
# 测试本地DNS解析无头服务
kubectl exec -it nginx -n test -- nslookup nginx-headless.test.svc.cluster.local
测试本地单个 Pod 解析
<pod-name>.nginx-headless.<namespace>.svc.cluster.local
# 测试本地DNS解析单个pod
kubectl exec -it nginx -n test -- nslookup nginx-headless-69db456d87-k4x4b.nginx-headless.test.svc.cluster.local
跨域测试
导出无头服务
# 导出服务
subctl export service --namespace test nginx-headless
# 查看serviceimport
kubectl get serviceimport -A
# 查看serviceexport
kubectl get serviceexport -A
测试跨域服务解析
<service>.<namespace>.svc.clusterset.local
或者
<clusterid>.<service>.<namespace>.svc.clusterset.local
kubectl exec -it nginx -n test -- nslookup nginx-headless.test.svc.clusterset.local
# 或者
kubectl exec -it nginx -n test -- nslookup pve3.nginx-headless.test.svc.clusterset.local
测试跨域单个 Pod 解析
<pod-name>.<clusterid>.<service>.<namespace>.svc.clusterset.local
kubectl exec -it nginx -n test -- nslookup nginx-headless-69db456d87-ztdt4.pve3.nginx-headless.test.svc.clusterse
t.local