k8s clusterip 方式service负载均衡实现三种方式及原理

k8s Service详解(概念、原理、流量分析、代码) - sucre_tan - 博客园

补充说明:

ClusterIP方式原理

kubernetes中kube-proxy的工作原理是什么 - 云计算 - 亿速云

Kubernetes中的负载均衡原理————以iptables模式为例 | CITAHub技术团队

kube-proxy & service

  • kube-proxy其实就是管理service的访问入口,包括集群内Pod到Service的访问和集群外访问service。

  • kube-proxy管理sevice的Endpoints,该service对外暴露一个Virtual IP,也成为Cluster IP, 集群内通过访问这个Cluster IP:Port就能访问到集群内对应的serivce下的Pod。

  • service是通过Selector选择的一组Pods的服务抽象,其实就是一个微服务,提供了服务的LB和反向代理的能力,而kube-proxy的主要作用就是负责service的实现。

  • service另外一个重要作用是,一个服务后端的Pods可能会随着生存灭亡而发生IP的改变,service的出现,给服务提供了一个固定的IP,而无视后端Endpoint的变化。

服务发现

k8s提供了两种方式进行服务发现:

  • 环境变量: 当你创建一个Pod的时候,kubelet会在该Pod中注入集群内所有Service的相关环境变量。需要注意的是,要想一个Pod中注入某个Service的环境变量,则必须Service要先比该Pod创建。这一点,几乎使得这种方式进行服务发现不可用。

    比如,一个ServiceName为redis-master的Service,对应的ClusterIP:Port为10.0.0.11:6379,则其对应的环境变量为:

REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11
  • DNS:这也是k8s官方强烈推荐的方式。可以通过cluster add-on的方式轻松的创建KubeDNS来对集群内的Service进行服务发现。更多关于KubeDNS的内容,请查看:Kubernetes DNS Service技术研究 - 爱码网

服务发布类型ServiceType

k8s原生的,一个Service的ServiceType决定了其发布服务的方式。

  • ClusterIP集群内发布服务,这是k8s默认的ServiceType。通过集群内的ClusterIP在内部发布服务,只能够在集群内部访问服务。

  • ExternalName用于集群内不同命名空间内的服务通过名称可直接访问,以及将在k8s集群外部的服务引入到k8s集群内通过服务名称访问场景。需要借助KubeDNS(version >= 1.7)的支持,就是用KubeDNS将该service和ExternalName做一个Map,KubeDNS返回一个CNAME记录。
    ExternalName的用途(业务场景),有两个:
    (1)将k8s集群内在某个namespace内的服务暴露到另外一个namespace内,实现两个不同的namespace之间的不同pod可以通过name的形式访问。假如集群内有两个服务服务a和b,a服务访问b服务。若两个服务都定义在同一个namespaceA下,则a可以通过b的名称http://b/访问b服务,k8s会将http://b/转为http://b.namespaceA.svc.cluster.local/ svc.cluster.local 是整个k8s集群的域),若将b定义在namespaceB访问,则A无法直接通过b的名称http://b/访问服务b,因为b的namespace不是namespaceA。若想仍然通过http://b访问,可以在namespaceA下定义一个type为ExternalName的服务b,其externalName属性的值为b.namespaceB.svc.cluster.local即可,相当于在namespaceA下为定义在namespaceB下的服务b建了一个链接,连接名为b。namespaceA下的ExternalName服务b定义如下:

    apiVersion: v1
    kind: Service
    metadata:
      name: b
      namespace: namespaceA
    spec:
      type: ExternalName
      externalName: b.namespaceB.svc.cluster.local

      (2)将k8s集群外的服务引入到k8s内部,供内部的pod访问,就像使用集群内的服务一样使用外部服务,利用ExternalName的Service访问的外部服务地址必须是域名,不支持IP地址。举例参见下方k8s集群内部与外部之间互联互通#通过ExternalName Service访问域名方式的外部服务

  • NodePort用来对集群外暴露k8s内部的Service。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建,同时,k8s会在集群内所有node上,为集群内的所有NodePort类型的服务暴露其NodePort,这样集群外部可以连接到集群内任何一个node的ip:nodePort即可以访问该服务。这种方式的缺点比较多:每个端口只能是一种服务;端口范围只能是 30000-32767,不推荐采用这种方式对集群外暴露服务NodePort 需要借助真实存在的ip,是一个公共的ip,任何人都可以访问,而ClusterIP可以理解成不对外开放,仅限于集群内的节点之间特定的一个范围。
  • LoadBalancer: 也是用来对集群外暴露k8s内部的Service。使用云提供商的负载局衡器,可以路由到 NodePort 服务和 ClusterIP 服务,这个需要结合具体的云厂商进行操作。所有通往指定的端口的流量都会被转发到对应的服务。它没有过滤条件,没有路由等。这意味着你几乎可以发送任何种类的流量到该服务,像 HTTP,TCP,UDP,Websocket,gRPC 或其它任意种类。这个方式的最大缺点是每一个用 LoadBalancer 暴露的服务都会有它自己的 IP 地址,每个用到的 LoadBalancer 都需要付费,这将是非常昂贵的。

kube-proxy负载均衡原理

k8s借助kube-proxy实现负载均衡。

kube-proxy实现了三种代理模式:

  • userspace代理模式:v1.0及之前版本的默认模式,来回在用户空间和内核空间切换,存在严重的性能问题,不推荐
  • iptables代理模式:从v1.1版本中开始增加了iptables mode,在v1.2版本中正式替代userspace模式成为默认模式。将k8s整个集群的service和endpoints路由都写到iptables中,当service数量较大时,同样存在严重的性能问题,且负载均衡能力比较简单,不推荐
  • IPVS代理模式:v1.9之后引入,通过维护ipvs规则和ipset两种高效的数据结构,使得iptables规则不再随着service数量增加而增加,这也是ipvs模式在大规模场景下比iptables模式性能更优越的原因,且支持丰富的负载均衡算法。推荐。

以上三种方式,都是利用客户端的OS的网络内核(iptables规则)拦截到ClusterIP:ClusterPort的请求,因此是客户端实现的负载均衡。

userspace 代理模式

userspace是在用户空间,通过kube-proxy来实现service的代理服务,其原理如下如图所示:

iptables代理模式

这种方式完全利用内核iptables来实现service的代理和LB。是v1.2及之后版本默认模式,其原理图如下所示:

说明:

  • k8s集群中所有node的iptables规则中均配置了整个k8s集群中所有的Service的ClusterIP:ClusterPort到对应的endpoint列表的路由规则。
  • iptables规则会拦截client端发起的到ClusertIP:ClusterPort的请求,实现了请求转发到某个具体的Endpoint,同时实现了负载均衡和会话保持功能。
  • iptables规则借助statistic模块实现负载均衡,以random方式均衡的分发流量,也即负载均衡模式为简单的轮询无法实现复杂的如最小链接分发方式,鉴于此,K8S 1.9后续版本调整了kube-proxy服务,其可通过ipvs实现Service负载均衡功能
  • iptables规则借助recent模块,实现会话保持功能。可以通过Service对象的sessionAffinity属性配置 session 亲和,目前可以有两种取值,一种是 None,也是默认值,表示没有,会直接轮询 Pod。一种是 ClientIP,表示根据客户端 IP 亲和,同一个客户端 IP,会被发送到同一个 Pod 上。
  • 我们提到了kube-proxy iptables模式在大规模场景下会生成众多的iptables规则,而这些iptables规则是链式顺序匹配的,这样会大大降低网络访问性能。

iptables最初也不是为了负载均衡而设计,而纯粹是为了防火墙而设计。为了解决iptables模式下的性能问题,kube-proxy引入了一个更适合负载均衡场景且有更高效数据结构(散列表)的模块——ipvs。

IPVS代理模式

https://www.jianshu.com/p/d10bf4086644?utm_campaign=maleskine...&utm_content=note&utm_medium=seo_notes

kube-proxy ipvs模式原理分析 - 墨天轮

说明:

  • 通过创建kube-ipvs0 dummy网卡并绑定service ip,使得从外部进来的流量在PREROUTING后的路由决策中发往INPUT,从而能到达ipvs模块。

  • ipvs模式下通过维护ipvs规则和ipset两种高效的数据结构,使得iptables规则不再随着service数量增加而增加,这也是ipvs模式在大规模场景下比iptables模式性能更优越的原因。

  • 外部访问service ip的链路为:PREROUTING->route->INPUT->ipvs(DNAT)->OUTPUT->route->POSTROUTING

  • 宿主机上访问service ip的链路为:OUTPUT->ipvs(DNAT)->OUTPUT->route->POSTROUTING

  • ipvs只做了DNAT,部分场景下仍需要iptables做SNAT。

k8s集群内部与外部之间互联互通

从k8s集群外部访问k8s

可通过NodePort、LoadBalancer和Ingeress方式,从k8s集群外部访问k8s内部的服务。

区别参见:K8S ClusterIP、 NodePort、LoadBalancer和Ingress 区别 - 王叫兽 - 博客园

将k8s集群外部的服务接入k8s集群内部

 参见:https://www.jianshu.com/p/758cfafcf80d 

有以下几种方式:

  • 利用ConfigMap+环境变量访问外部服务:ConfigMap配置外部服务的地址(ip或域名均可),在源端容器中定义环境变量,并从ConfigMap映射。这种方式的问题:需要编写额外的程序代码以从环境变量中读取外部服务地址,另外如果外部服务地址发生变化,需要重启所有正在运行的容器以获取更新后的服务地址,故不推荐这种方案
  • 通过ExternalName Service访问域名方式的外部服务。通过ExternalName Service定义k8s内部服务名到外部服务名的映射,即可在k8s内部访问外部服务,无需编写额外的程序代码读取环境变量,地址发生变更后,只需要ExternalName Service配置即可动态生效,不需要重启容器。这种方式的问题:外部服务名必须是域名,不支持IP地址。

    举例:以下配置可在集群内通过https://baidu-service/访问https://www.baidu.com/:
    apiVersion: v1
    kind: Service
    metadata:
      name: baidu-service
      namespace: namespaceA
    spec:
      type: ExternalName
      externalName: www.baidu.com
  • 通过无Pod选择器的Service+Endpoints访问外部服务。当外部服务的访问地址是ip地址时,无法通过ExternalName service访问外部服务。此时需要创建一个没有 Pod 选择器的Service和一个Endpoints,Endpoints对象通过subsets指向外部服务的ip和端口(若外部服务是一个集群,即有多个服务实例,均可以定义在subsets中,k8s会在所有服务地址之间进行流量的负载平衡)。

    例如一个外部游戏服务,其访问地址为http://192.168.3.175::8091/,想引入k8s集群内部,且希望通过http://games/访问(pod通过名称访问游戏服务,而非写死且可能会发生变更的ip地址),则对应的Headless Service和Endpoint定义如下:
     
    #Service定义,可以是Headless Service,也可以是普通的Service。
    #注意这里没有pod选择器,因此它不知道往哪里转发流量。
    #因此需手动创建一个将从此服务接收流量的 Endpoints 对象(见下方Endpoints定义)
    apiVersion: v1
    kind: Service
    metadata:
      name: games
    spec:
      #clusterIP: None表示headless service
      #clusterIP: None 
      type: ClusterIP
      ports:
      - port: 80
        targetPort: 8091
    
    
    #EndPoints定义,接收上方Service转发的流量(name要与Service的name相同)
    #并将流量转发到真正的外部服务192.168.3.175:8091上
    #若相同的外部服务有多个ip:port,则可以都定义在subsets中
    #k8s会在所有服务地址之间进行流量的负载平衡
    apiVersion: v1
    kind: Endpoints
    metadata:
      name: games
    subsets:
      - addresses:
          - ip: 192.168.3.175
        ports:
          - port: 8091
    

client Pod访问服务的处理过程如下:

  1. clientPod访问serviceName:servicePort
  2. 服务发现:k8s的cube-dns服务,将serviceName:servicePort解析为serviceIP:servicePort
  3. 请求被cube-proxy

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ClusterIP ServiceKubernetes 中一种 Service 类型,它会为后端 Pod 提供一个虚拟 IP 地址,使得在集群内部可以通过这个虚拟 IP 地址来访问后端 Pod,而不需要知道具体的 Pod IP 地址。ClusterIP Service 的优缺点如下: 优点: 1. 高可用性:ClusterIP Service 支持负载均衡,可以将请求均匀地分配给多个后端 Pod,从而提高应用的可用性。 2. 灵活性:ClusterIP Service 支持配置多种负载均衡算法和会话保持方式,可以根据实际需求进行灵活配置。 3. 安全性:ClusterIP Service 只在集群内部暴露虚拟 IP 地址,不会将后端 Pod 直接暴露给外部网络,从而提高了应用的安全性。 缺点: 1. 仅适用于集群内部访问:ClusterIP Service 只能在 Kubernetes 集群内部使用,无法通过外部网络直接访问。 2. 不支持动态扩容:ClusterIP Service 只能在创建时指定后端 Pod 的数量,无法动态地根据负载自动扩容。 3. 无法实现跨集群访问:ClusterIP Service 只能在同一集群内部进行负载均衡,无法实现跨集群访问。 ### 回答2: K8s中的ClusterIP Service是一种服务发现和负载均衡机制,它有以下优点: 1. 内部服务访问:ClusterIP Service允许在集群内部创建一个虚拟的固定IP地址,用于访问部署在集群内的服务。这个IP地址可以供其他Pod或Service使用,方便进行内部通信,无需暴露到集群外部。 2. 负载均衡:通过ClusterIP Service,可以将请求均匀地分发到后端的多个Pod上,实现负载均衡。这样可以提高服务的可用性、扩展性和性能。 3. 内部DNS解析:ClusterIP Service会自动为每个Service分配一个唯一的DNS名称,这样可以通过名称来访问Service,而无需直接使用Pod的IP地址。这样,当Pod的IP地址发生变化时,不会影响到服务的访问。 然而,ClusterIP Service也有一些缺点: 1. 无法供集群外部访问:ClusterIP Service只能在集群内部使用,无法通过集群外部的IP地址直接访问。如果需要集群外部访问,需要结合其他类型的Service,如NodePort或LoadBalancer。 2. 不能实现会话保持:ClusterIP Service默认使用基于IP的负载均衡算法,不保证请求会发送到同一个后端Pod上。这就导致无法实现会话保持,对于需要保持会话状态的应用可能存在问题。 3. 无法处理动态变化:当创建或删除Pod时,ClusterIP Service需要重新配置和更新。在大规模的集群中,频繁的Pod变化可能导致Service的配置更新变得复杂和有延迟。 总的来说,ClusterIP ServiceK8s集群中有诸多优点,如方便的内部服务发现和负载均衡,但也有一些限制,无法用于集群外部访问,不支持会话保持,以及对动态变化的响应较慢。 ### 回答3: Kubernetesk8s)是一个用于自动化管理容器化应用程序的开源平台,而ClusterIP Servicek8s中的一种服务类型。下面是ClusterIP Service的优缺点: 优点: 1. 内部访问:ClusterIP Service为内部应用程序提供了一个虚拟的集群IP地址,只对集群内可见。这允许应用程序在集群内部相互通信,同时保护应用程序免受来自外部的未经授权的访问。 2. 负载均衡ClusterIP Service可以在后端Pod之间进行负载均衡。它可以自动将流量分发到后端Pod实例,以提高应用程序的可用性和性能。 3. 简化网络配置:通过使用ClusterIP Service,应用程序可以通过单个虚拟IP地址访问多个后端Pod实例,而不需要知道每个Pod的具体IP地址。这简化了网络配置和管理的复杂性。 4. 无需暴露端口:ClusterIP Service只在集群内部使用,没有暴露到集群外部。这样可以确保应用程序仅对集群内的其他组件可见,而不受来自外部的潜在攻击。 缺点: 1. 无法从集群外部访问:ClusterIP Service只在集群内可用,无法从集群外部直接访问。如果需要将应用程序暴露给外部用户或设备,则需要使用其他类型的Service如NodePort或LoadBalancer。 2. 需要额外配置:ClusterIP Service需要在k8s集群中进行额外的配置。这包括创建Service对象、定义后端Pod等。相对于其他类型的ServiceClusterIP Service的设置和管理需要一些额外的步骤。 3. 网络层面问题:ClusterIP Service是在网络层面上实现的,因此可能会存在一些网络层面的问题。例如,可能会出现网络延迟或丢包等问题,尤其是在大规模部署时。 总的来说,ClusterIP Service提供了许多方便和安全的特性,但也有一些限制。开发人员需要根据应用程序的具体需求和部署环境来选择合适的Service类型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值