Kubernetes Headless服务
1、概述
Headless Services是一种特殊的service,其spec:clusterIP表示为None,这样在实际运行时就不会被分配ClusterIP,也被称为无头服务,通过DNS解析提供服务发现。与普通服务不同的是Headless Services不提供负载均衡功能,每个Pod都有唯一的DNS记录,直接映射到其IP地址,适用于有状态应用的场景,如与StatefulSet一起部署数据库。这种服务使得直接访问单个Pod成为可能,而不经过负载均衡器。
因为 Headless Service 属于 Service ClusterIp 类型,所以在讲解Headless Service前,先简单说下 Service 和服务发现。
2、Service与服务发现
2.1 Service概述
Service主要用于实现对一组Pod的访问,Service 通过标签选择器来关联 Pod 资源,Service 根据访问的端口将对应的请求转发至后端Pod的端口上。Service对象的IP地址(ClusterIP)是虚拟IP地址,仅在 Kubernetes集群内可访问,外部无法访问,可以通过配置 NodePort 或 LoadBalancer 类型的 Service 将集群内的服务暴露给 Kuberenetes 集群外的客户端访问。

备注:Kubernetes部署的服务实例(Pod)不仅可以通过 Service nodePort 和 loadbalancer 的方式暴露给集群外客户端,一般还有以下几种方式暴露给外部访问:
- 通过hostPort方式在单一节点上做端口映射;
- 通过Pod的hostNetwork配置让Pod资源使用工作节点上的网络;
- 使用Ingress 资源。
2.2 Service服务访问原理
本质上来讲,一个Service 对象对应于工作节点内核之中的一组路由规则,这些规则能够将到达Service对象的ClusterIP的流量转发至相应Pod对象的IP地址和端口。
每个工作节点的kube-proxy组件通过API Server持续监听各个Service及其关联的Pod对象,并将Service对象的创建或变动,实时写入到当前工作节点的路由规则上。客户端、Service及Pod对象的关系如下图所示:

2.3 Service类型
Service 一般分为3种类型:ClusterIP、NodePort、LoadBalancer。
(1)ClusterIP
通过集群内部IP 地址暴露服务,CusterIP地址仅在集群内部可以访问,无法被集群外部的客户端访问。
(2)NodePort
NodePort类型,将Service的端口号映射到每个Node的一个端口号上,然后分发给后端的Pod处理。这种类型的Service 既可以被集群内部客户端通过 CIusterIP 直接访问,也可以在集群外部客户端通过nodeIP:nodePort进行访问。
(3)LoadBalancer
LoadBalancer类型建立在 NodePort基础上,将Service映射到一个负载均衡器的IP 地址上,通常在公有云环境中使用。
客户端通过负载均衡器的IP和Service的端号就可以访问到具体的服务,无须再通过 kube-proxy提供的负载均衡机制进行流量转发,可以直接将流量转发到后端 Pod上。
如果是本地搭建LoadBalancer,一般采用metallb方案,官网地址:https://metallb.universe.tf/,有兴趣的朋友自行搭建。
3、Headless Service
简单讲完 Service 和服务发现后,现在回归本文主题,接下来详细讲解下 Headless Service。
3.1 观察Headless Service
由于现有 Kubernetes 集群里面有现成的 headless 服务,所以本文不再创建新的 headless 服务,下面观察下集群已创建的一个名为 openldap 的 headless 服务,以下是 openldap 服务规格定义文件。
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/instance: cb-openldap
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: openldap-ha
name: openldap
spec:
clusterIP: None #这使得服务成为headless
ports:
- name: ldap
port: 389
protocol: TCP
targetPort: 389
selector:
app.kubernetes.io/instance: cb-openldap
app.kubernetes.io/name: openldap-ha
sessionAffinity: None
type: ClusterIP
通过 kubectl get 和 kubectl describe 来查看服务,可以发现他没有集群 IP。
[root@cloud ~]# kubectl get svc openldap
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
openldap ClusterIP None <none> 389/TCP 185d
并且它的后端包含与pod选择器匹配的(部分)pod。“部分”是因为pod包含就绪探针,所以只有准备就绪的pod会被列出作为服务转发的上游服务,通过 kubectl describe 命令可以看出openldap 服务有两个就绪Pod(10.233.0.214:389,10.233.9.73:389)。
[root@cloud ~]# kubectl describe svc openldap
Name: openldap
Namespace: default
Labels: app.kubernetes.io/instance=cb-openldap
app.kubernetes.io/managed-by=Helm
app.kubernetes.io/name=openldap-ha
Annotations: meta.helm.sh/release-name: cb-openldap
meta.helm.sh/release-namespace: default
Selector: app.kubernetes.io/instance=cb-openldap,app.kubernetes.io/name=openldap-ha
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: None
IPs: None
Port: ldap 389/TCP
TargetPort: 389/TCP
Endpoints: 10.233.0.214:389,10.233.9.73:389
Session Affinity: None
Events: <none>
3.2 通过DNS发现Pod
Kubernetes允许客户通过DNS查找发现 Pod IP。对于普通 Kubernetes Service,当执行服务的DNS查找时,DNS服务器会返回单个IP——ClusterIP;但是对于 Headless Service,进行DNS 查找时,DNS服务器将返回的则是 Pod IP 而不是单个服务IP。
DNS服务器不会返回单个DNS A记录,而是会为该服务返回多个A记录,每个记录指向当时支持该服务的单个pod的IP。客户端因此可以做一个简单的DNS A 记录查找并获取属于该服务一部分或者所有pod的IP。客户端可以使用该信息连接到其中的一个、多个或全部。
3.2.1 DNS发现Pod示例
准备一个具有nslooup命令的 Pod(此步骤本文不再赘余,最简单的话可以运行一个 busybox pod),运行此 Pod 后,通过进入 Pod 内部通过执行DNS查找以查看是否获得了实际的pod IP。
(1)对于普通 Kubernetes Service
[root@108 ~]# kubectl get svc -n=istio-system |grep jaeger-query
jaeger-query ClusterIP 10.233.49.189 <none> 16686/TCP,16685/TCP 661d
进入具有nslooup命令Pod内部。
[root@108 ~]# kubectl exec -it busybox-848d7987f9-wbqq8 /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 169.254.25.10
options ndots:5
执行服务DNS查找。

注意:经测试使用nslooup命令解析域名时候,不走search域,所以需要拼全服务名。
(2)对于普通 Headless Service
[root@108 ~]# kubectl get svc -n=xxx-middleware |grep kafka-zookeeper-headless
kafka-zookeeper-headless ClusterIP None <none> 2181/TCP,3888/TCP,2888/TCP 646d
[root@108 ~]# kubectl describe svc -n=xxx-middleware kafka-zookeeper-headless
Name: kafka-zookeeper-headless
Namespace: xxx-middleware
Labels: app=zookeeper
app.kubernetes.io/managed-by=Helm
chart=zookeeper-2.1.0
heritage=Helm
release=kafka
Annotations: meta.helm.sh/release-name: kafka
meta.helm.sh/release-namespace: xxx-middleware
Selector: app=zookeeper,release=kafka
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: None
IPs: None
Port: client 2181/TCP
TargetPort: client/TCP
Endpoints: 10.233.66.179:2181,10.233.66.181:2181,10.233.69.223:2181
Port: election 3888/TCP
TargetPort: election/TCP
Endpoints: 10.233.66.179:3888,10.233.66.181:3888,10.233.69.223:3888
Port: server 2888/TCP
TargetPort: server/TCP
Endpoints: 10.233.66.179:2888,10.233.66.181:2888,10.233.69.223:2888
Session Affinity: None
Events: <none>
进入具有nslooup命令Pod内部。
[root@108 ~]# kubectl exec -it busybox-848d7987f9-wbqq8 /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 169.254.25.10
options ndots:5
执行服务DNS查找,解析地址正是服务标签关联Pod Ip(Endpoints: 10.233.66.179,10.233.66.181,10.233.69.223)。

Headless Services还有一个用处,即Headless Service的对应的每一个Endpoints,都会有对应的DNS域名;这样Pod之间就可以互相访问。我们还是看上面的这个例子,通过statefulSet管理,共三个 Pod 实例。
[root@108 ~]# kubectl get pods -n=xxx-middleware |grep zoo
kafka-zookeeper-0 1/1 Running 0 85d
kafka-zookeeper-1 1/1 Running 1 96d
kafka-zookeeper-2 1/1 Running 1 96d
现在直接解析指定 Pod 的DNS域名,对应的pod的域名为kafka-zookeeper-0、kafka-zookeeper-1、kafka-zookeeper-2,它们之间可以互相访问,这样对于一些集群类型的应用就可以解决互相之间身份识别的问题了。

注意:尽管headless服务看起来可能与常规服务不同,但在客户端的视角上它们并无不同。即使使用headless服务,集群内客户端也可以通过连接到服务的DNS名称来连接到pod上,就像使用常规服务一样。但是对于headless服务,由于DNS返回了pod的IP, 客户端直接连接到该pod,而不是通过服务代理。headless服务仍然提供跨pod的负载平衡,但是是通过DNS轮询机制,不是通过kube-proxy在工作节点提供的iptables/ipvs路由规则。
3.3 发现所有的Pod--包括未就绪的Pod
只有准备就绪的pod能够作为服务的后端。但有时希望即使pod没有准备就绪,服务发现机制也能够发现所有匹配服务标签选择器的pod。
幸运的是,不必通过查询KubernetesAPI服务器,可以使用DNS查找机制来查找那些未准备好的pod。要告诉Kubernetes无论pod的准备状态如何,希望将所有pod添加到服务中。必须将以下注解添加到服务中:
kind: Service
metadata:
annotations:
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
示例:
[root@cloud ~]# kubectl describe svc -n=xxx-system redis-ha-announce-0
Name: redis-ha-announce-0
Namespace: xxx-system
Labels: app=redis-ha
app.kubernetes.io/managed-by=Helm
chart=redis-ha-3.9.0
heritage=Helm
release=cb-redis
Annotations: meta.helm.sh/release-name: cb-redis
meta.helm.sh/release-namespace: xxx-system
service.alpha.kubernetes.io/tolerate-unready-endpoints: true
Selector: app=redis-ha,release=cb-redis,statefulset.kubernetes.io/pod-name=redis-ha-server-0
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.234.235.210
IPs: 10.234.235.210
Port: server 6379/TCP
TargetPort: redis/TCP
Endpoints: 10.233.0.213:6379
Port: sentinel 26379/TCP
TargetPort: sentinel/TCP
Endpoints: 10.233.0.213:26379
Session Affinity: None
Events: <none>
3.4 其他
Headless服务就是一组Pod组成的只供集群内访问(没有ClusterIP)的Service,一般结合StatefulSet用于部署有状态应用的场景,如果想让部署的有状态应用暴露给集群外部客户端访问的话,可以新建个普通(有ClusterIP)的服务,通过标签选择关联有状态服务实例。
示例:

4、总结
在某些场景中,无需对外提供访问能力,只需要在内部找到自己想找到的Pod资源时,可以通过Headless Service来实现。这种不具有ClusterIP的Service资源就是Headless Service,该 Service 的请求流量不需要 kube-proxy 处理,也不会有负载均衡和路由规则,而是由ClusterDNS的域名解析机制直接去访问固定的Pod资源。
既然是Headless Service,那首先它是Service,一般的Service能被内部和外部访问。之所以叫Headless Service,是因为只对内提供访问,既然只对内访问,那肯定就需要提供稳定的访问能力了,否则就没什么作用了。比如说拥有固定的Pod名称和存储,所以一般会结合StatefulSet一起使用,用来部署有状态的应用。
如果想让部署的有状态应用暴露给集群外部客户端访问的话,可以新建个普通(有ClusterIP)的服务,通过标签选择关联有状态服务实例。
参考:https://www.cnblogs.com/lizexiong/p/14778359.html
参考:http://www.mangod.top/articles/2023/09/04/1693799594643.html
参考:https://www.jianshu.com/p/a6d8b28c88a2
Kubernetes Headless服务的更多相关文章
- Kubernetes master服务定制编译docker镜像
前言 之前部署了Kubernetes 1.13.0,发现master服务的启动方式与1.10.4版本有所区别,kube-apiserver.kube-controller-manager和kube-s ...
- Istio技术与实践02:源码解析之Istio on Kubernetes 统一服务发现
前言 文章Istio技术与实践01: 源码解析之Pilot多云平台服务发现机制结合Pilot的代码实现介绍了Istio的抽象服务模型和基于该模型的数据结构定义,了解到Istio上只是定义的服务发现的接 ...
- 如何发现 Kubernetes 中服务和工作负载的异常
大家好,我是来自阿里云的李煌东,今天由我为大家分享 Kubernetes 监控公开课的第二节内容:如何发现 Kubernetes 中服务和工作负载的异常. 本次分享由三个部分组成: 一.Kuberne ...
- 从零入门 Serverless | 一文讲透 Serverless Kubernetes 容器服务
作者 | 张维(贤维) 阿里云函数计算开发工程师 导读:Serverless Kubernetes 是以容器和 kubernetes 为基础的 Serverless 服务,它提供了一种简单易用.极致弹 ...
- Kubernetes之服务发现及负载Services
Service 概述 kubernetes 中的pod是有生生灭灭的,时刻都有可能被新的pod所代替,而不可复活(pod的生命周期).一旦一个pod生命终止,通过ReplicaSets动态创建和销毁p ...
- kubernetes 微服务西游记(持续更新中...)
随着微服务架构的流行,迈向云原生的趋势,容器化微服务就成为了持续集成最好的手段,镜像成为了持续交付最好的产物,容器成为了镜像运行最好的环境,kubernetes成了部署容器最好的生态系统和规范.实践出 ...
- Centos7部署kubernetes API服务(四)
1.准备软件包 [root@linux-node1 bin]# pwd /usr/local/src/kubernetes/server/bin [root@linux-node1 bin]# cp ...
- Kubernetes DNS服务配置案例
首先创建DNS服务的RC配置文件skydns-rc.yaml apiVersion: v1 kind: ReplicationController metadata: name: kube-dns-v ...
- Kubernetes Headless Service
1. Headless Service headless service 需要将 spec.clusterIP 设置成 None. 因为没有ClusterIP,kube-proxy 并不处理此类服务, ...
- 4.kubernetes的服务发现插件-CoreDNS
1.1.部署K8S内网资源清单http服务 1.2.部署coredns 部署K8S内网资源清单http服务 在运维主机HDSS7-200.host.com上,配置一个nginx虚拟主机,用以提高k8s ...
随机推荐
- 本计划在 .NET 8 中推出的 WASI 推迟到 .NET 9
本计划在 .NET 8 中推出的 WASI 已推迟到 .NET 9,请参阅 Github 上的 WASI 跟踪问题. 在.NET 8 Preview 4 开始支持生成与 WASI 兼容的 .wasm ...
- 第一次git上传的完整流程
第一次git上传的完整流程 使用git简单命令上传代码push到远程仓库 + 简单介绍了一个.git文件结构. 代码上传到gitee和github流程一样的,不过你上传到github可能网不行失败,所 ...
- TopCoder 15903 EllysNim
TopCoder 15903 EllysNim(https://vjudge.net/problem/TopCoder-15903) \(n\)看似有点东西,实际上就只是一个贪心... 设\(i\)表 ...
- 一文搞懂深度信念网络!DBN概念介绍与Pytorch实战
本文深入探讨了深度信念网络DBN的核心概念.结构.Pytorch实战,分析其在深度学习网络中的定位.潜力与应用场景. 关注TechLead,分享AI与云服务技术的全维度知识.作者拥有10+年互联网服务 ...
- 20.2 OpenSSL 非对称RSA加解密算法
RSA算法是一种非对称加密算法,由三位数学家Rivest.Shamir和Adleman共同发明,以他们三人的名字首字母命名.RSA算法的安全性基于大数分解问题,即对于一个非常大的合数,将其分解为两个质 ...
- JUC并发编程学习笔记(九)阻塞队列
阻塞队列 阻塞 队列 队列的特性:FIFO(fist inpupt fist output)先进先出 不得不阻塞的情况 什么情况下会使用阻塞队列:多线程并发处理.线程池 学会使用队列 添加.移除 四组 ...
- Error running 'TestAlterNickname.test': Command line is too long. Shorten command line for TestAlterNickname.test or also for JUnit default configuration
问题描述 如图IDEA报错问题,发生在我用JUnit进行测试时. 解决方法 1. 直接点击 default 2. Modify options -> Shorten command line 3 ...
- 计算网络之IPv6配置DHCP服务及acl
一.DHCPv6服务 DHCP即动态主机地址分配协议,在前面已经启动过IPv4的动态主机分配了, 还是来介绍两种方式 接口模式 全局模式 现在需要了解的就是DHCHv6,即基于IPv6的动态主机地址分 ...
- DP:三角形的最小路径和
给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上. 例如,给定三角形: [ [2], [3,4], [6,5,7], [4,1,8,3]] 自顶向下的 ...
- execl表格if函数and和or的使用方法?
当在Excel中处理数据时,IF函数是非常有用的函数之一.它允许您根据指定的条件执行不同的操作.在IF函数中,AND和OR函数可以帮助您组合多个条件以实现更复杂的逻辑判断.接下来,我将详细描述IF函数 ...
