欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > K8S - 在集群内反向代理外部资源 - headless service 的使用

K8S - 在集群内反向代理外部资源 - headless service 的使用

2025/2/23 22:11:08 来源:https://blog.csdn.net/nvd11/article/details/139909746  浏览:    关键词:K8S - 在集群内反向代理外部资源 - headless service 的使用

在上一篇文章中
K8S - 理解ClusterIP - 集群内部service之间的反向代理和loadbalancer

介绍了 ClusterIP 的主要作用 :
在k8s 集群内部 代理 内部的多实例 service

但是ClusterIP 还有1个变种 -> 无头服务 (headless service)
它用于代理集群外部的 ip资源

当然代理外部资源的方法有很多种, 除了headless service 还有externalName等service。
本文主要讲 headless service





什么是无头服务

referring:
https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/#headless-services

无头服务(Headless Services)
有时你并不需要负载均衡,也不需要单独的 Service IP。遇到这种情况,可以通过显式设置 集群 IP(spec.clusterIP)的值为 "None" 来创建无头服务(Headless Service)。你可以使用无头 Service 与其他服务发现机制交互,而不必绑定到 Kubernetes 的实现。无头 Service 不会获得集群 IP,kube-proxy 不会处理这类 Service, 而且平台也不会为它们提供负载均衡或路由支持。无头 Service 允许客户端直接连接到它所偏好的任一 Pod。 无头 Service 不使用虚拟 IP 地址和代理 配置路由和数据包转发;相反,无头 Service 通过内部 DNS 记录报告各个 Pod 的端点 IP 地址,这些 DNS 记录是由集群的 DNS 服务所提供的。 这些 DNS 记录是由集群内部 DNS 服务所提供的 要定义无头 Service,你需要将 .spec.type 设置为 ClusterIP(这也是 type 的默认值),并进一步将 .spec.clusterIP 设置为 None。字符串值 None 是一种特殊情况,与未设置 .spec.clusterIP 字段不同。DNS 如何自动配置取决于 Service 是否定义了选择器:

其实官方文档写得不明不白 还是要实操才能理解





ClusterIP, headless 和 externalName的区别

这3个都属于 k8s 的services 大类

而且, headless 是ClusterIP 的一种, 是特别的ClusterIP (属性 spec.clusterip = none)

而externalName 是专门做外部资源代理的

为何本文例子不用 externalName service 呢

原因是externalName 有个limitation, 它只能代理外部资源的域名, 而不是能是ip地址。

下面是官网的说明

https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/#externalname

========================================

ExternalName 类型

类型为 ExternalName 的 Service 将 Service 映射到 DNS 名称,而不是典型的选择算符, 例如 my-service 或者 cassandra。你可以使用 spec.externalName 参数指定这些服务。

例如,以下 Service 定义将 prod 名字空间中的 my-service 服务映射到 my.database.example.com:

apiVersion: v1
kind: Service
metadata:name: my-servicenamespace: prod
spec:type: ExternalNameexternalName: my.database.example.com

说明:
type: ExternalName 的服务接受 IPv4 地址字符串,但将该字符串视为由数字组成的 DNS 名称, 而不是 IP 地址(然而,互联网不允许在 DNS 中使用此类名称)。 类似于 IPv4 地址的外部名称无法被 DNS 服务器解析。

如果你想要将服务直接映射到某特定 IP 地址,请考虑使用无头服务。

=======================================================================

考虑到本文的例子 是用 ip address , 所以不深究 externalName





应用场景

在这里插入图片描述

如上图, 为了让bq api service 的实例们可以访问 集群外的 cloud-user , 我们要找个solution

方法一:
把cloud-user 的ip hardcode 在 bq-api-service 配置文件中

缺点:
较难实现 load balance
当 cloud user 被部署到其他server时, 需要修改配置

方法二:
就是本文的例子, 利用headless service 去代理集群外的资源





创建和应用headless service

编写yaml

headless-cloud-user

apiVersion: v1
kind: Service
metadata:name: headless-cloud-usernamespace: defaultlabels:app: cloud-user
spec:clusterIP: None # headless service---
apiVersion: v1
kind: Endpoints
metadata:name: headless-cloud-user # the name must be same with the name of service# because the service will use this endpoint to get the target ip and portnamespace: defaultlabels:target-app: cloud-user
subsets:- addresses:- ip: 192.168.0.47- ip: 192.168.0.51 # can add more ip , support base load balance

我已经踩好坑了

  1. 首先, 我们要把 service 和 endpoints 两部分分开写, 所以Service 部分不能写spec.selector. 想想也对, 这个service 不是代理pods资源, 是不应该有selector的

  2. clusterIP 设成0, 实际试过不写这个配置, 会分配1个ip, 但是这个service 本身还是work的

  3. Service 里不需要写port 的 信息了, 灵活分发, 例如调用的是 8080 端口, 映射就是外部资源的相同端口

  4. 在endpoint 部分, 名字要跟service 的名字一样! 否则不work

  5. labels 不需要一样, 如例子

  6. 被代理的ip 可以写多个

部署yaml
[gateman@manjaro-x13 bq-api-service-proxy-external]$ kubectl apply -f headless-cloud-user.yaml
service/headless-cloud-user created
endpoints/headless-cloud-user created

查看svc:

[gateman@manjaro-x13 bq-api-service-proxy-external]$ kubectl get svc -o wide
NAME                  TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
headless-cloud-user   ClusterIP   None         <none>        <none>    56m   <none>
kubernetes            ClusterIP   10.96.0.1    <none>        443/TCP   78d   <none>

可以见到 这个service 仍然属于 ClusterIP , 但是CLUSTER- IP 那一列为吉, 就是没有分配虚拟ip, ports 信息也是吉

查看endpoinds:

[gateman@manjaro-x13 bq-api-service-proxy-external]$ kubectl get ep -o wide
NAME                  ENDPOINTS                   AGE
headless-cloud-user   192.168.0.47,192.168.0.51   57m
kubernetes            192.168.0.3:6443            78d

它代理了两个 外部ip, 但是没有端口信息, 实际上就是全部端口都可以代理

测试

当然最快速的测试方法还是在dns-test 容器里测试

可以见到, 多次调用这个service情况下, 返回的信息是随机来自于 不同的ip地址的实例的

而且当我关闭其中1个ip实例时,
多次调用下, 它都自动选择健康的实例, 牛!

/ # curl headless-cloud-user:8081/actuator/info
{"app":"Cloud User API","version":"1.0.1","hostname":"b1a26a0f6685","dbUrl":"jdbc:mysql://192.168.0.42:3306/demo_cloud_user?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true","des/ # curl headless-cloud-user:8081/actuator/info
{"app":"Cloud User API","version":"1.0.1","hostname":"e166316cddb1","dbUrl":"jdbc:mysql://192.168.0.42:3306/demo_cloud_user?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true","des/ # curl headless-cloud-user:8081/actuator/info
{"app":"Cloud User API","version":"1.0.1","hostname":"e166316cddb1","dbUrl":"jdbc:mysql://192.168.0.42:3306/demo_cloud_user?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true","des/ # curl headless-cloud-user:8081/actuator/info
{"app":"Cloud User API","version":"1.0.1","hostname":"e166316cddb1","dbUrl":"jdbc:mysql://192.168.0.42:3306/demo_cloud_user?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true","des/ # curl headless-cloud-user:8081/actuator/info
{"app":"Cloud User API","version":"1.0.1","hostname":"b1a26a0f6685","dbUrl":"jdbc:mysql://192.168.0.42:3306/demo_cloud_user?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true","des/ # curl headless-cloud-user:8081/actuator/info

一些见解

同过这个例子, 有一些看法

  1. 既然 headless 可以代理外部资源, 而headless 也属于ClusterIP, 所以认为ClusterIP 只能代理内部资源的说法是错误的

  2. headless 可以写多个ip地址, 也就有了基本load balance 功能, 所以认为headless service 无负载均衡的说法也是错的

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词