浅谈Kubernetes Service负载均衡实现机制

本文深入探讨Kubernetes中Service的概念及其与kube-proxy的协作机制,解析不同类型的Service(ClusterIP、NodePort、LoadBalancer、Ingress)适用场景,以及kube-proxy如何基于Iptables和IPVS实现Service的高效负载均衡。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

奇技指南

Kubernetes Serivce是一组具有相同label Pod集合的抽象(可以简单的理解为集群内的LB),集群内外的各个服务可以通过Service进行互相通信。但是Service的类型有多种,每种类型的Service适合怎样的场景以及kube-proxy是如何实现Service负载均衡的将是本文讨论的重点。

本文来自360云计算

1

Service和kube-proxy在kubernetes集群中的工作原理

在介绍Service和kube-proxy之前,先绍下它们在Kubernetes集群中所起到的作用。

640?wx_fmt=png

让我们分析下上面这张图:

1. 运行在每个Node节点的kube-proxy会实时的watch Services和 Endpoints对象。

当用户在kubernetes集群中创建了含有label的Service之后,同时会在集群中创建出一个同名的Endpoints对象,用于存储该Service下的Pod IP. 它们的关系如下图所示:

640?wx_fmt=png

2.每个运行在Node节点的kube-proxy感知到Services和Endpoints的变化之后,会在各自的Node节点设置相关的iptables或IPVS规则,用于之后用户通过Service的ClusterIP去访问该Service下的服务。

3.当kube-proxy把需要的规则设置完成之后,用户便可以在集群内的Node或客户端Pod上通过ClusterIP经过iptables或IPVS设置的规则进行路由和转发,最终将客户端请求发送到真实的后端Pod。

对于kube-proxy如何设置Iptables和IPVS策略后续会讲。接下来先介绍下每种不同类型的Service的使用场景。

2

Service 类型

当前Kubernetes Service支持如下几种类型,并在介绍类型的同时便可以了解每种类型的Service的具体使用场景。

ClusterIP

ClusterIP类型的Service是Kubernetes集群默认的Service, 它只能用于集群内部通信。不能用于外部通信。

ClusterIP Service类型的结构如下图所示:

640?wx_fmt=png

NodePort

如果你想要在集群外访问集群内部的服务,你可以使用这种类型的Service。NodePort类型的Service会在集群内部的所有Node节点打开一个指定的端口。之后所有的流量直接发送到这个端口之后,就会转发的Service去对真实的服务进行访问。

NodePort Service类型的结构如下图所示:

640?wx_fmt=png

LoadBalancer

LoadBalancer类型的Service通常和云厂商的LB结合一起使用,用于将集群内部的服务暴露到外网,云厂商的LoadBalancer会给用户分配一个IP,之后通过该IP的流量会转发到你的Service.

LoadBalancer Service类型的结构如下图所示:

640?wx_fmt=png

Ingress

Ingress 其实不是Service的一个类型,但是它可以作用于多个Service,作为集群内部服务的入口。

Ingress 的结构如下图所示:

640?wx_fmt=png

3

Service 服务发现

Service当前支持两种类型的服务发现机制,一种是通过环境变量,另一种是通过DNS。在这两种方案中,建议使用后者。

环境变量

当一个Pod创建完成之后,kubelet会在该Pod中注册该集群已经创建的所有Service相关的环境变量,但是需要注意的是,Service创建之前的所有的POD是不会注册该Service的环境变量的,所以在平时使用时,建议通过DNS的方式进行Service之间的服务发现。

DNS

可以在集群中部署CoreDNS服务(旧版本的kubernetes集群使用的是kubeDNS), 来达到集群内部的Pod通过DNS的方式进行集群内部各个服务之间的通讯。

当前kubernetes集群默认使用CoreDNS作为默认的DNS服务,主要原因是CoreDNS是基于Plugin的方式进行扩展的简单,灵活。并且不完全被Kubernetes所捆绑。

4

Service 负载均衡

在本文的最初已经介绍了service和kube-proxy在集群中是如何配合来达到服务的负载均衡。kube-proxy在其中起到了关键性的作用,kube-proxy作为一个控制器,作为k8s和Linux kernel Netfilter交互的一个枢纽。监听kubernetes集群Services和Endpoints对象的变化,并根据kube-proxy不同的模式(iptables or ipvs), 对内核设置不同的规则,来实现路由转发。接下来分别介绍下kube-proxy基于Iptables和IPVS两种模式实现Service负载均衡的工作机制。

Iptables 实现负载均衡

Iptables是一个用户态程序,通过配置Netfilter规则来构建Linux内核防火墙。Netfilter是Linux内核的网络包管理框架,提供了一整套的hook函数的管理机制,使得诸如数据包过滤,网络地址转换(NAT)和基于协议类型的连接跟踪成为了可能,Netfilter在内核中的位置如下图所示。

640?wx_fmt=png

接下来介绍kube-proxy是如何利用Iptables做负载均衡的。数据包在Iptables中的匹配流程如下图所示:

640?wx_fmt=png

在Iptables模式下,kube-proxy通过在目标node节点上的Iptables中的NAT表的PREROUTIN和POSTROUTING链中创建一系列的自定义链(这些自定义链主要是”KUBE-SERVICE”链, “KUBE-POSTROUTING”链,每个服务对应的”KUBE-SVC-XXXXXX”链和”KUBE-SEP-XXXX”链),然后通过这些自定义链对流经到该Node的数据包做DNAT和SNAT操作从而实现路由,负载均衡和地址转化,如下图所示:

640?wx_fmt=jpeg

kube-proxy中,客户端的请求数据包在Iptables规则中具体的匹配过程为:

1.PREROUTING链或者OUTPUT链(集群内的Pod通过clusterIP访问Service时经过OUTPUT链, 而当集群外主机通过NodePort方式访问Service时,通过PREROUTING链,两个链都会跳转到KUBE-SERVICE链)

640?wx_fmt=png

640?wx_fmt=png

2.KUBE-SERVICES链(每一个Service所暴露的每一个端口在KUBE-SERVICES链中都会对应一条相应的规则,当Service的数量达到一定规模时,KUBE-SERVICES链中的规则的数据将会非常的大,而Iptables在进行查找匹配时是线性查找,这将耗费很长时间,时间复杂度O(n))

640?wx_fmt=png

3.KUBE-SVC-XXXXX链 (在KUBE-SVC-XXXXX链中(后面那串 hash 值由 Service 的虚 IP 生成),会以一定的概率匹配下面的某一条规则执行,通过statistic模块为每个后端设置权重,已实现负载均衡的目的,每个KUBE-SEP-XXXXX链代表Service后面的一个具体的Pod(后面那串 hash 值由后端 Pod 实际 IP 生成),这样便实现了负载均衡的目的)

640?wx_fmt=png

4.KUBE-SEP-XXXX链 (通过DNAT,将数据包的目的IP修改为服务端的Pod IP)

640?wx_fmt=png

5.POSTROUTING链

640?wx_fmt=png

6.KUBE_POSTROUTING链 (对标记的数据包做SNAT)

640?wx_fmt=png

通过上面的这个设置便实现了基于Iptables实现了负载均衡。但是Iptbles做负载均衡存在一些问题:

  • 规则线性匹配时延:

  • 规则更新时延:

  • 可扩展性:

  • 可用性: 服务扩容/缩容时, Iptables规则的刷新会导致连接断开,服务不可用。

为了解决Iptables当前存在的这些问题,华为开源团队的同学为社区贡献了IPVS模式,接下来介绍下IPVS是如何实现负载均衡的。

IPVS 实现负载均衡

IPVS是LVS项目的一部分,是一款运行在Linux kernel当中的4层负载均衡器,性能异常优秀。使用调优后的内核,可以轻松处理每秒10万次以上的转发请求。

IPVS具有以下特点:

  • 传输层Load Balancer, LVS负载均衡器的实现。

  • 与Iptables同样基于Netfilter, 但是使用的是hash表。

  • 支持TCP, UDP, SCTP协议,支持IPV4, IPV6。

  • 支持多种负载均衡策略:

    • rr: round-robin

    • lc: least connection

    • dh: destination hashing

    • sh: source hashing

    • sed: shortest expected delay

    • nq: never queue

  • 支持会话保持

LVS的工作原理如下图所示:

640?wx_fmt=png

1.当客户端的请求到达负载均衡器的内核空间时,首先会达到PREROUTING链。

LVS主要由三种工作模式, 分别是NAT DR, Tunnel模式,而在kube-proxy中,IPVS工作在NAT模式,所以下面主要对NAT模式进行介绍:

还是分析上面的那张图:

1. 客户端将请求发往前端的负载均衡器,请求报文源地址是CIP(客户端IP), 目的地址是VIP(负载均衡器前端地址)

2. 负载均衡器收到报文之后,发现请求的是在规则里面存在的地址,那么它将请求的报文的目的地址改为后端服务器的RIP地址,并将报文根据响应的负责均衡策略发送出去。

3. 报文发送到Real Server后,由于报文的目的地址是自己,所有会响应请求,并将响应的报文返回给LVS。

4. 然后LVS将此报文的源地址修改本机的IP地址并发送给客户端。

介绍完基本的工作原理之后,下面我们看看如何在kube-proxy中使用IPVS模式进行负载均衡。

首先需要在启动kube-proxy的参数中指定如下参数:

--proxy-mode=ipvs //将kube-proxy的模式设置为IPVS	
--ipvs-scheduler=rr //设置ipvs的负载均衡算法,默认是rr	
--ipvs-min-sync-period=5s // 刷新IPVS规则的最小时间间隔	
--ipvs-sync-period=30s // 刷新IPVS规则的最大时间间隔

设置完这些参数之后,重启启动kube-proxy服务即可。当创建ClusterIP类型的Service时,IPVS模式的kube-proxy会做下面几件事儿:

  • 创建虚拟网卡,默认是kube-ipvs0

  • 绑定service IP地址到虚拟网卡kube-ipvs0

640?wx_fmt=png

  • 为每一个Service IP地址创建IPVS虚拟服务器

640?wx_fmt=png

同时IPVS还支持会话保持功能,通过在创建Srevice对象时,指定service.spec.sessionAffinity参数为ClusterIP默认是None 和 指定service.spec.sessionAffinityConfig.clientIP.timeoutSeconds参数为需要的时间,默认是10800s。

下面是一个创建Service,指定会话保持的一个具体的例子:

kind: Service	
apiVersion: v1	
metadata:	
  name: nginx-service	
spec:	
  type: ClusterIP	
  selector:	
    app: nginx	
  sessionAffinity: ClientIP	
  sessionAffinityConfig:	
    clientIP:	
      timeoutSeconds: 50	
  ports:	
  -name: http	
   protocol: TCP	
   port: 80	
   targetPort: 80

之后通过ipvsadm -L即可查看会话保持功能是否设置成功。这样kube-proxy便可以通过IPVS的模式实现负载均衡。

640?wx_fmt=png

5

总结

kube-proxy在使用iptables和ipvs实现对Service的负载均衡,但是通过iptables的实现方式,由于Iptables本身的特性,新增规则,更新规则是非增量式的,需要先iptables-save然后在内存中更新规则,在内核中修改规则,在iptables-restore,并且Iptables在进行规则查找匹配时是线性查找,这将耗费很长时间,时间复杂度O(n)。而使用IPVS的实现方式,其连接过程的时间复杂度是O(1)。基本就是说连接的效率与集群Service的数量是无关的。因此随着集群内部Service的不断增加,IPVS的性能优势就体现出来了。

相关文章

  • https://zhuanlan.zhihu.com/p/37230013

  • https://zhuanlan.zhihu.com/p/39909011

  • https://www.projectcalico.org/comparing-kube-proxy-modes-iptables-or-ipvs/

  • https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0

  • https://wiki.archlinux.org/index.php/Iptables_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)

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

  • http://blog.chinaunix.net/uid-23069658-id-3160506.html

  • https://tonydeng.github.io/sdn-handbook/linux/loadbalance.html

  • https://www.josedomingo.org/pledin/2018/11/recursos-de-kubernetes-services/

界世的你当不

只做你的肩膀

640?wx_fmt=jpeg

640?wx_fmt=jpeg

 360官方技术公众号 

技术干货|一手资讯|精彩活动

空·

你“在看”我吗?

640?wx_fmt=png

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值