关于Kubernetes中如何访问集群外服务的一些笔记

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 分享一些 k8s 中服务如何访问集群外服务的笔记博文内容涉及:如何访问集群外服务创建外部服务代理 SVC(IP+PORT情况)Endponts/EndpointSlice 实现 Demo外部服务为 单体/集群 的访问 Demo创建 ExternalName 类型 SVC(域名的情况)理解不足小伙伴帮忙指正

写在前面


  • 分享一些 k8s 中服务如何访问集群外服务的笔记
  • 博文内容涉及:

    • 如何访问集群外服务
    • 创建外部服务代理 SVC(IP+PORT情况)
    • Endponts/EndpointSlice 实现 Demo
    • 外部服务为 单体/集群 的访问 Demo
    • 创建 ExternalName 类型 SVC(域名的情况)
  • 理解不足小伙伴帮忙指正

是故不应取法,不应取非法。以是义故,如来常说:汝等比丘,知我说法,如筏喻者,法尚应舍何况非法。 ----------《金刚经》


如何访问集群外服务

在 K8s 中,考虑某些稳定性问题,希望把数据库部署到 物理机或者虚机上,或许系统正在一点点迁移到 K8s 平台,某些服务在非 k8s 集群部署,或者上游系统是别人的,和我们没有直接关系。那么我们如何实现 K8s 集群上的服务访问 这些外部服务。

外部服务是IP端口的方式

在 K8s 中,我们可以定义一个没有 lable SelectorService 来代替 非当前集群的服务。通过 IP 端口映射的方式把外部服务映射到内部集群中。

这样可以正常接入外部服务的同时,添加了一个类似外部服务的代理服务。之后如果外部服务发生 IP 端口变更,只需要修改映射关系即可,不需要修改应用相关的配置。同时对访问他的pod 隐藏了实际的IP端口,以后如果服务移入集群内,则不需要更改任何代码。

外部服务是域名的方式

当 外部服务提供的方式是域名的时候,我们可以创建一个 Service 类型为 ExternalName 的SVC,同样没有lable Selector, 类型为 ExternalName 的服务将外部服务域名映射到集群内部服务的 DNS 名称,而不是对应的 Pod 。

创建外部服务代理服务

适用于外部服务为 IP:Port的方式,定义一个没有 选择器的 Service ,对应这样的 Servicek8s 不会自动创建对应的 EndpointEndpointSlice ,其他的和正常的 Service 没有区别,所以我们需要提供 Service 对应的 endpoint 或者是 EndpointSlice 来对外部服务做映射。类似与通过 iptables 做了 DNAT 的映射,实现 IP 端口转发。

资源文件的定义

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$cat not-service.yaml
apiVersion: v1
kind: Serviceca
metadata:
  name: external-service
spec:
  ports:
    - protocol: TCP
      port: 30056
      targetPort: 3306

定义了一个普通的 Service ,没有选择器,在 Service 内部做了转发,暴露的端口为 30056 转发到端口 3306, 这里的 3306 为代理的外部服务的端口。

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$kubectl describe svc external-service
Name:              external-service
Namespace:         awx
Labels:            <none>
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.103.93.20
IPs:               10.103.93.20
Port:              <unset>  30056/TCP
TargetPort:        3306/TCP
Endpoints:         <none>
Session Affinity:  None
Events:            <none>

可以看到当前的 Service 类型为 ClusterIP, 对应的集群 IP 为 :10.103.93.20,Endpoints 为 None。

对于这样的 Service 系统不会自动创建 EndpointEndpointSlice,因此需要手动创建一个和该 Service 同名的Endpoint 或者带序号的 EndpointSlice 对象 ,用于指向实际的 后端访问地址

1.21 版本之前的只能通过创建 Endponits 的方式,创建 Endpoint 的配置文件内容如下:

Endponits 方式单体服务

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$cat external-service.yaml
kind: Endpoints
apiVersion: v1
metadata:
  name: external-service
subsets:
- addresses:
  - ip: 192.168.26.81
  ports:
  - port: 3306

这里定义 集群外的服务 IP 为 192.168.26.81,端口为 3306, 这个 endpoint 即表示集群外的服务,生产环境中,我们需要打通相关的网络。

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$kubectl apply  -f external-service.yaml
endpoints/external-service created
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$kubectl get endpoints external-service
NAME               ENDPOINTS            AGE
external-service   192.168.26.81:3306   57s

在集群外通过 python 模块发布一个 简单的 http 服务,暴露端口 3306,做简单测试。

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$coproc python -m SimpleHTTPServer 3306
[2] 109525
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$kubectl get svc external-service
NAME               TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)     AGE
external-service   ClusterIP   10.103.93.20   <none>        30056/TCP   26m

通过访问集群服务,实现对集群外部服务的访问

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$curl 10.103.93.20:30056 -s -w "%{http_code}\n" -o /dev/null
192.168.26.81 - - [10/Dec/2022 03:26:30] "GET / HTTP/1.1" 200 -
200

EndpointSlice 方式(集群服务)

对于 1.21 版本及之后的版本来讲,我们可以通过 EndpointSlice 来实现,资源文件的定义

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$cat external-service-1.yaml
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: external-service-1 # 按惯例将服务的名称用作 EndpointSlice 名称的前缀
  labels:
    # 你应设置 "kubernetes.io/service-name" 标签。
    # 设置其值以匹配服务的名称
    kubernetes.io/service-name: external-service
addressType: IPv4
ports:
  - name: '' # 留空,因为 port 9376 未被 IANA 分配为已注册端口
    appProtocol: http
    protocol: TCP
    port: 3306
endpoints:
  - addresses:
      - "192.168.26.82" # 此列表中的 IP 地址可以按任何顺序显示
  - addresses:
      - "192.168.26.81"

这里我们提供了两个 ip ,来模拟外部服务集群的情况。

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$kubectl apply  -f external-service-1.yaml
endpointslice.discovery.k8s.io/external-service-1 created
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$kubectl get endpointslices.discovery.k8s.io  external-service-1
NAME                 ADDRESSTYPE   PORTS   ENDPOINTS                     AGE
external-service-1   IPv4          3306    192.168.26.81,192.168.26.82   20s

在集群外 81,82 两台机器通过 python 模块发布一个 简单的 http 服务,暴露端口 3306,做简单测试。

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$coproc python -m SimpleHTTPServer 3306
[2] 9084
┌──[root@vms82.liruilongs.github.io]-[~]
└─$coproc python -m SimpleHTTPServer 3306

测试可以看到在81 和 82两个外部服务轮询访问,默认情况下 Serviec 的 负载均衡策略为,sessionAffinity: None ,即 RoundRobin 将客户端请求代理到合适的后端合适的 Pod 上

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$while true;do curl 10.103.93.20:30056 -s -w "%{http_code}\n" -o /dev/null ;sleep 2;done
192.168.26.81 - - [10/Dec/2022 03:56:52] "GET / HTTP/1.1" 200 -
200
200
200
192.168.26.81 - - [10/Dec/2022 03:56:58] "GET / HTTP/1.1" 200 -
200
200
192.168.26.81 - - [10/Dec/2022 03:57:02] "GET / HTTP/1.1" 200 -
200
192.168.26.81 - - [10/Dec/2022 03:57:04] "GET / HTTP/1.1" 200 -
200
200
192.168.26.81 - - [10/Dec/2022 03:57:08] "GET / HTTP/1.1" 200 -
200
192.168.26.81 - - [10/Dec/2022 03:57:10] "GET / HTTP/1.1" 200 -
200

这里我们修改一下,修改为会话保持 sessionAffinity: ClientIP

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$kubectl edit svc external-service
service/external-service edited
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$kubectl get svc external-service  -o json | jq .spec.sessionAffinity
"ClientIP"

可以看到当前 访问只到 81 上面

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$while true;do curl 10.103.93.20:30056 -s -w "%{http_code}\n" -o /dev/null ;sleep 2;done
192.168.26.81 - - [10/Dec/2022 04:00:56] "GET / HTTP/1.1" 200 -
200
192.168.26.81 - - [10/Dec/2022 04:00:58] "GET / HTTP/1.1" 200 -
200
192.168.26.81 - - [10/Dec/2022 04:01:00] "GET / HTTP/1.1" 200 -
200
192.168.26.81 - - [10/Dec/2022 04:01:02] "GET / HTTP/1.1" 200 -
200
192.168.26.81 - - [10/Dec/2022 04:01:04] "GET / HTTP/1.1" 200 -
200
192.168.26.81 - - [10/Dec/2022 04:01:06] "GET / HTTP/1.1" 200 -
200
192.168.26.81 - - [10/Dec/2022 04:01:08] "GET / HTTP/1.1" 200 -
200

DNS 解析测试,可以看到 对于没有选择器的服务来讲,同样可以通过 服务名对应的域名来解析到对应的 集群 IP 地址,这与 有选择器的相同。

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$kubectl run pod-test -it --rm --image=yauritux/busybox-curl  --image-pull-policy=IfNotPresent
If you don't see a command prompt, try pressing enter.
/home # nslookup external-service.awx.svc.cluster.local.
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      external-service.awx.svc.cluster.local.
Address 1: 10.103.93.20 external-service.awx.svc.cluster.local
/home # Session ended, resume using 'kubectl attach pod-test -c pod-test -i -t' command when the pod is running
pod "pod-test" deleted

域名的方式:ExternalName

这里假设 集群外的服务为 我的 个人主页 https://liruilongs.github.io/

创建一个 ExternalName 类型的 SVC,当然也可以设置端口,这里我们不需要。

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$cat external-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  type: ExternalName
  externalName: liruilongs.github.io

查看详细信息,CLUSTER-IP 为none

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$kubectl apply  -f external-service.yaml
service/external-service created
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$kubectl get svc
NAME               TYPE           CLUSTER-IP   EXTERNAL-IP            PORT(S)   AGE
external-service   ExternalName   <none>       liruilongs.github.io   <none>    5s
┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$kubectl describe svc external-service
Name:              external-service
Namespace:         liruilong-deploy-create
Labels:            <none>
Annotations:       <none>
Selector:          <none>
Type:              ExternalName
IP Families:       <none>
IP:
IPs:               <none>
External Name:     liruilongs.github.io
Session Affinity:  None
Events:            <none>

解析域名测试,可以发现,external-service 经过 k8s 的内部 DNS 记录为 liruilongs.github.io,解析获得的 ipv4和ipv6 完全相同。所以pod 可以通过域名连接到外部服务,而不是使用服务的实际 FQDN

┌──[root@vms81.liruilongs.github.io]-[~/ansible]
└─$kubectl run pod-test -it --rm --image=yauritux/busybox-curl  --image-pull-policy=IfNotPresent
If you don''t see a command prompt, try pressing enter.
/home # nslookup external-service
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      external-service
Address 1: 2606:50c0:8001::153
Address 2: 2606:50c0:8003::153
Address 3: 2606:50c0:8000::153
Address 4: 2606:50c0:8002::153
Address 5: 185.199.111.153 cdn-185-199-111-153.github.com
Address 6: 185.199.109.153 cdn-185-199-109-153.github.com
Address 7: 185.199.110.153 cdn-185-199-110-153.github.com
Address 8: 185.199.108.153 cdn-185-199-108-153.github.com
/home # nslookup liruilongs.github.io
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      liruilongs.github.io
Address 1: 2606:50c0:8003::153
Address 2: 2606:50c0:8001::153
Address 3: 2606:50c0:8000::153
Address 4: 2606:50c0:8002::153
Address 5: 185.199.111.153 cdn-185-199-111-153.github.com
Address 6: 185.199.110.153 cdn-185-199-110-153.github.com
Address 7: 185.199.108.153 cdn-185-199-108-153.github.com
Address 8: 185.199.109.153 cdn-185-199-109-153.github.com

ExternalName 服务仅在 DNS 级别实现,为该服务创建一个简单的 CNAME DNS 记录。因此,连接到服务的客户端将直接连接到外部服务,完全绕过服务代理。出于这个原因,这些类型的服务甚至没有获得集群 IP。所以对于域名的解析,实际上是依赖于 节点机器。

博文参考


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

https://stackoverflow.com/questions/74795408/clean-way-to-connect-to-services-running-on-the-same-host-as-the-kubernetes-clus

《Kubernetes 实战》

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
1月前
|
缓存 容灾 网络协议
ACK One多集群网关:实现高效容灾方案
ACK One多集群网关可以帮助您快速构建同城跨AZ多活容灾系统、混合云同城跨AZ多活容灾系统,以及异地容灾系统。
|
2月前
|
Kubernetes Ubuntu 网络安全
ubuntu使用kubeadm搭建k8s集群
通过以上步骤,您可以在 Ubuntu 系统上使用 kubeadm 成功搭建一个 Kubernetes 集群。本文详细介绍了从环境准备、安装 Kubernetes 组件、初始化集群到管理和使用集群的完整过程,希望对您有所帮助。在实际应用中,您可以根据具体需求调整配置,进一步优化集群性能和安全性。
148 12
|
2月前
|
Prometheus Kubernetes 监控
OpenAI故障复盘 - 阿里云容器服务与可观测产品如何保障大规模K8s集群稳定性
聚焦近日OpenAI的大规模K8s集群故障,介绍阿里云容器服务与可观测团队在大规模K8s场景下我们的建设与沉淀。以及分享对类似故障问题的应对方案:包括在K8s和Prometheus的高可用架构设计方面、事前事后的稳定性保障体系方面。
|
2月前
|
Kubernetes 网络协议 应用服务中间件
Kubernetes Ingress:灵活的集群外部网络访问的利器
《Kubernetes Ingress:集群外部访问的利器-打造灵活的集群网络》介绍了如何通过Ingress实现Kubernetes集群的外部访问。前提条件是已拥有Kubernetes集群并安装了kubectl工具。文章详细讲解了Ingress的基本组成(Ingress Controller和资源对象),选择合适的版本,以及具体的安装步骤,如下载配置文件、部署Nginx Ingress Controller等。此外,还提供了常见问题的解决方案,例如镜像下载失败的应对措施。最后,通过部署示例应用展示了Ingress的实际使用方法。
87 2
|
2月前
|
存储 Kubernetes 关系型数据库
阿里云ACK备份中心,K8s集群业务应用数据的一站式灾备方案
本文源自2024云栖大会苏雅诗的演讲,探讨了K8s集群业务为何需要灾备及其重要性。文中强调了集群与业务高可用配置对稳定性的重要性,并指出人为误操作等风险,建议实施周期性和特定情况下的灾备措施。针对容器化业务,提出了灾备的新特性与需求,包括工作负载为核心、云资源信息的备份,以及有状态应用的数据保护。介绍了ACK推出的备份中心解决方案,支持命名空间、标签、资源类型等维度的备份,并具备存储卷数据保护功能,能够满足GitOps流程企业的特定需求。此外,还详细描述了备份中心的使用流程、控制台展示、灾备难点及解决方案等内容,展示了备份中心如何有效应对K8s集群资源和存储卷数据的灾备挑战。
|
3月前
|
存储 Kubernetes Devops
Kubernetes集群管理和服务部署实战
Kubernetes集群管理和服务部署实战
102 0
|
3月前
|
Kubernetes 监控 Cloud Native
Kubernetes集群的高可用性与伸缩性实践
Kubernetes集群的高可用性与伸缩性实践
99 1
|
3月前
|
存储 Kubernetes 网络协议
k8s的无头服务
Headless Service 是一种特殊的 Kubernetes 服务,其 `spec:clusterIP` 设置为 `None`,不会分配 ClusterIP,通过 DNS 解析提供服务发现。与普通服务不同,Headless Service 不提供负载均衡功能,每个 Pod 都有唯一的 DNS 记录,直接映射到其 IP 地址,适用于有状态应用的场景,如与 StatefulSet 一起部署数据库。示例中通过创建 Nginx 的 StatefulSet 和 Headless Service,展示了如何直接访问单个 Pod 并进行内容修改。
90 3
|
4月前
|
JSON Kubernetes 容灾
ACK One应用分发上线:高效管理多集群应用
ACK One应用分发上线,主要介绍了新能力的使用场景
|
存储 Kubernetes API
在K8S集群中,如何正确选择工作节点资源大小? 2
在K8S集群中,如何正确选择工作节点资源大小?

热门文章

最新文章