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服务的更多相关文章

  1. Kubernetes master服务定制编译docker镜像

    前言 之前部署了Kubernetes 1.13.0,发现master服务的启动方式与1.10.4版本有所区别,kube-apiserver.kube-controller-manager和kube-s ...

  2. Istio技术与实践02:源码解析之Istio on Kubernetes 统一服务发现

    前言 文章Istio技术与实践01: 源码解析之Pilot多云平台服务发现机制结合Pilot的代码实现介绍了Istio的抽象服务模型和基于该模型的数据结构定义,了解到Istio上只是定义的服务发现的接 ...

  3. 如何发现 Kubernetes 中服务和工作负载的异常

    大家好,我是来自阿里云的李煌东,今天由我为大家分享 Kubernetes 监控公开课的第二节内容:如何发现 Kubernetes 中服务和工作负载的异常. 本次分享由三个部分组成: 一.Kuberne ...

  4. 从零入门 Serverless | 一文讲透 Serverless Kubernetes 容器服务

    作者 | 张维(贤维) 阿里云函数计算开发工程师 导读:Serverless Kubernetes 是以容器和 kubernetes 为基础的 Serverless 服务,它提供了一种简单易用.极致弹 ...

  5. Kubernetes之服务发现及负载Services

    Service 概述 kubernetes 中的pod是有生生灭灭的,时刻都有可能被新的pod所代替,而不可复活(pod的生命周期).一旦一个pod生命终止,通过ReplicaSets动态创建和销毁p ...

  6. kubernetes 微服务西游记(持续更新中...)

    随着微服务架构的流行,迈向云原生的趋势,容器化微服务就成为了持续集成最好的手段,镜像成为了持续交付最好的产物,容器成为了镜像运行最好的环境,kubernetes成了部署容器最好的生态系统和规范.实践出 ...

  7. Centos7部署kubernetes API服务(四)

    1.准备软件包 [root@linux-node1 bin]# pwd /usr/local/src/kubernetes/server/bin [root@linux-node1 bin]# cp ...

  8. Kubernetes DNS服务配置案例

    首先创建DNS服务的RC配置文件skydns-rc.yaml apiVersion: v1 kind: ReplicationController metadata: name: kube-dns-v ...

  9. Kubernetes Headless Service

    1. Headless Service headless service 需要将 spec.clusterIP 设置成 None. 因为没有ClusterIP,kube-proxy 并不处理此类服务, ...

  10. 4.kubernetes的服务发现插件-CoreDNS

    1.1.部署K8S内网资源清单http服务 1.2.部署coredns 部署K8S内网资源清单http服务 在运维主机HDSS7-200.host.com上,配置一个nginx虚拟主机,用以提高k8s ...

随机推荐

  1. 【翻译】listener.ora

    今天仔细过一遍oracle的监听配置文件描述. cat $ORACLE_HOME/network/admin/samples/listener.ora # copyright (c) 1997 by ...

  2. 基于.Net 的 AvaloniUI 多媒体播放器方案汇总

    基于.Net 的 AvaloniUI 多媒体播放器方案汇总 摘要 随着国产化的推进,相信.Net的桌面端的小伙伴的可能已经有感受到了. 为了让.Net的桌面框架能够跨桌面平台,首选的就是Avalona ...

  3. 山东大学&安恒校赛CTF

    1.babyshell 这段代码是一个函数seccom,它使用seccomp机制来限制进程的系统调用权限.seccomp是一种Linux内核的安全模块,可以用于过滤或限制进程可以执行的系统调用. 具体 ...

  4. 面向生产的 LLM 优化

    注意 : 本文同时也是 Transformers 的文档. 以 GPT3/4.Falcon 以及 LLama 为代表的大语言模型 (Large Language Model,LLM) 在处理以人为中心 ...

  5. Godot - 创建翻译文件(常量表)

    版本 Godot 3.1.2 背景 Godot的UI系统封装的很难受, 一些东西很难改动, 比如这个AcceptDialog的"确定""取消"按钮, 特别是在编 ...

  6. Apache Hudi Timeline:支持 ACID 事务的基础

    Apache Hudi 维护在给定表上执行的所有操作的Timeline(时间线),以支持以符合 ACID 的方式高效检索读取查询的数据. 在写入和表服务期间也会不断查阅时间线,这是表正常运行的关键. ...

  7. hci0 command 0xfc20 tx timeout(Realtek 8761B Chipset, Bluetooth 5.0)

    当前使用的Linux内核版本: 4.4.189 插上USB Bluetooth 5.0 Adapter后,dmesg显示如下log: [ 240.348480] usb 3-1.2: new full ...

  8. 持续集成指南:GitHubAction 自动构建+部署AspNetCore项目

    前言 之前研究了使用 GitHub Action 自动构建和发布 nuget 包:开发现代化的.NetCore控制台程序:(4)使用GithubAction自动构建以及发布nuget包 现在更进一步, ...

  9. 一、Linux发展史

    一.Linux发展史及红帽认证 红帽授权培训合作伙伴 木兰宽松许可证 1. Linux系统发展史 1. Unix发展历程 上世纪六十年代贝尔实验室(Bell).麻省理工学院(MIT)以及通用电气(GE ...

  10. 【Android】【外包杯】后台管理系统 | 进度day01

    外包杯官方提示:平台不要太大,只是一些小东西包括支付宝和微信小程序打开,无需安装口香糖,餐巾纸有一块屏幕,不需要很大,只需要满足顾客可以看到传播的内容打开橱窗不要有锋利边角,不要求一体,提高场景利用率 ...