k8s负载均衡方案简介

您所在的位置:网站首页 负载均衡都有哪些方法 k8s负载均衡方案简介

k8s负载均衡方案简介

2024-07-10 04:55| 来源: 网络整理| 查看: 265

1、kube-proxy简介

        kube-proxy负责为Service提供cluster内部的服务发现和负载均衡,它运行在每个Node计算节点上,负责Pod网络代理, 它会定时从etcd服务获取到service信息来做相应的策略,维护网络规则和四层负载均衡工作。在K8s集群中微服务的负载均衡是由Kube-proxy实现的,它是K8s集群内部的负载均衡器,也是一个分布式代理服务器,在K8s的每个节点上都有一个,这一设计体现了它的伸缩性优势,需要访问服务的节点越多,提供负载均衡能力的Kube-proxy就越多,高可用节点也随之增多。

        service是一组pod的服务抽象,相当于一组pod的负载均衡,负责将请求分发给对应的pod。service会为这个负载均衡提供一个IP,一般称为cluster IP。kube-proxy的作用主要是负责service的实现,具体来说,就是实现了内部从pod到service和外部的从node port向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的变化。 2、Service 简介

        Kubernetes Service定义了这样一种抽象: Service是一种可以访问 Pod逻辑分组的策略, Service通常是通过 Label Selector访问 Pod组。

        Service能够提供负载均衡的能力,但是在使用上有以下限制:只提供 4 层负载均衡能力,而没有 7 层功能,但有时我们可能需要更多的匹配规则来转发请求,这点上 4 层负载均衡是不支持的。

2.1、service的类型

2.1.1、ClusterIp(集群内部使用)

默认类型,自动分配一个仅Cluster内部可以访问的虚拟IP(VIP)。

2.1.2、NodePort(对外暴露应用)

        在ClusterIP基础上为Service在每台机器上绑定一个端口,这样就可以通过NodeIP:NodePort访问来访问该服务。 端口范围:30000~32767

2.1.3、LoadBalancer(对外暴露应用,适用于公有云)

        在NodePort的基础上,借助Cloud Provider创建一个外部负载均衡器,并将请求转发到NodePort。

2.1.4、ExternalName

        创建一个dns别名指到service name上,主要是防止service name发生变化,要配合dns插件使用。通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容。这只有 Kubernetes 1.7或更高版本的kube-dns才支持。

2.2、Service 工作流程

客户端访问节点时通过 iptables实现的

iptables规则是通过 kube-proxy写入的

apiserver通过监控 kube-proxy去进行对服务和端点的监控

kube-proxy通过 pod的标签( lables)去判断这个断点信息是否写入到 Endpoints里

 3、Endpoints简介

        endpoint是k8s集群中的一个资源对象,存储在etcd中,用来记录一个service对应的所有pod的访问地址。service配置selector,endpoint controller才会自动创建对应的endpoint对象;否则,不会生成endpoint对象。

3.1、工作流程

        一个 Service 由一组 backend Pod 组成。这些 Pod 通过 endpoints 暴露出来。 Service Selector 将持续评估,结果被 POST 到一个名称为 Service-hello 的 Endpoint 对象上。 当 Pod 终止后,它会自动从 Endpoint 中移除,新的能够匹配上 Service Selector 的 Pod 将自动地被添加到 Endpoint 中。 检查该 Endpoint,注意到 IP 地址与创建的 Pod 是相同的。现在,能够从集群中任意节点上使用 curl 命令请求 hello Service : 。

3.2、示例:service-hello.yaml

        【例如】k8s集群中创建一个名为hello的service,就会生成一个同名的endpoint对象,ENDPOINTS就是service关联的pod的ip地址和端口。

apiVersion: apps/v1 kind: Deployment metadata: name: hello spec: replicas: 3 selector: matchLabels: run: hello template: metadata: labels: run: hello spec: containers: - name: nginx image: nginx:latest --- apiVersion: v1 kind: Service metadata: name: service-hello labels: name: service-hello spec: type: NodePort # 这里代表是NodePort类型的,另外还有ingress,LoadBalancer ports: - port: 80 targetPort: 8080 protocol: TCP nodePort: 31111 # 所有的节点都会开放此端口30000--32767,此端口供外部调用。 selector: run: hello

3.2.1、查看验证

        Kube-proxy进程获取每个Service的Endpoints,实现Service的负载均衡功能。

[root@master ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello-688d6b8d4c-bzfj9 1/1 Running 0 21m 10.254.1.2 node01 hello-688d6b8d4c-nwgd6 1/1 Running 0 21m 10.254.2.2 node02 hello-688d6b8d4c-s5ff8 1/1 Running 0 21m 10.254.3.2 harbor [root@master ~]# kubectl get service service-hello -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service-hello NodePort 10.244.143.216 80:31111/TCP 18h run=hello [root@master ~]# kubectl describe service service-hello Name: service-hello Namespace: default Labels: Annotations: Selector: run=hello Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 10.244.143.216 IPs: 10.244.143.216 Port: 80/TCP TargetPort: 8080/TCP NodePort: 31111/TCP Endpoints: 10.254.1.6:8080,10.254.2.3:8080,10.254.3.3:8080 Session Affinity: None External Traffic Policy: Cluster Events: [root@master ~]# kubectl get endpoints service-hello NAME ENDPOINTS AGE service-hello 10.254.1.6:8080,10.254.2.3:8080,10.254.3.3:8080 18h

        Service的负载均衡转发规则:访问Service的请求,不论是Cluster IP+TargetPort的方式;还是用Node节点IP+NodePort的方式,都被Node节点的Iptables规则重定向到Kube-proxy监听Service服务代理端口。kube-proxy接收到Service的访问请求后,根据负载策略,转发到后端的Pod。

3、kubernetes中的port nodePort是外部访问k8s集群中service的端口,通过nodeIP: nodePort可以从外部访问到某个service。port是k8s集群内部访问service的端口,即通过clusterIP: port可以访问到某个service。targetPort是pod的端口,从port和nodePort来的流量经过kube-proxy流入到后端pod的targetPort上,最后进入容器。containerPort是pod内部容器的端口,targetPort映射到containerPort。 4、kubernetes服务发现

Kubernetes提供了两种方式进行服务发现, 即环境变量和DNS, 简单说明如下:

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

DNS:这是k8s官方强烈推荐的方式!!! 可以通过cluster add-on方式轻松的创建KubeDNS来对集群内的Service进行服务发现。

5、Service代理模式 5.1、userspace 代理模式

        这种模式,kube-proxy 会监视 Kubernetes 控制平面对 Service 对象和 Endpoints 对象的添加和移除操作。 对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。 任何连接到“代理端口”的请求,都会被代理到 Service 的后端 Pods 中的某个上面(如 Endpoints 所报告的一样)。 使用哪个后端 Pod,是 kube-proxy 基于 SessionAffinity 来确定的。

        最后,它配置 iptables 规则,捕获到达该 Service 的 clusterIP(是虚拟 IP) 和 Port 的请求,并重定向到代理端口,代理端口再代理请求到后端Pod。

        默认情况下,用户空间模式下的 kube-proxy 通过轮转算法选择后端。

5.2、iptables 代理模式

        这种模式,kube-proxy 会监视 Kubernetes 控制节点对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会配置 iptables 规则,从而捕获到达该 Service 的 clusterIP 和端口的请求,进而将请求重定向到 Service 的一组后端中的某个 Pod 上面。 对于每个 Endpoints 对象,它也会配置 iptables 规则,这个规则会选择一个后端组合。

        默认的策略是,kube-proxy 在 iptables 模式下随机选择一个后端。

        使用 iptables 处理流量具有较低的系统开销,因为流量由 Linux netfilter 处理, 而无需在用户空间和内核空间之间切换。 这种方法也可能更可靠。

        如果 kube-proxy 在 iptables 模式下运行,并且所选的第一个 Pod 没有响应, 则连接失败。 这与用户空间模式不同:在这种情况下,kube-proxy 将检测到与第一个 Pod 的连接已失败, 并会自动使用其他后端 Pod 重试。

        你可以使用 Pod 就绪探测器 验证后端 Pod 可以正常工作,以便 iptables 模式下的 kube-proxy 仅看到测试正常的后端。 这样做意味着你避免将流量通过 kube-proxy 发送到已知已失败的 Pod。

[root@master ~]# vim mysql-service.yaml apiVersion: v1 kind: Service metadata: labels: name: mysql role: service name: mysql-service spec: ports: - port: 3306 targetPort: 3306 nodePort: 30964 type: NodePort selector: mysql-service: "true" name: mysql [root@master ~]# kubectl apply -f mysql-service.yaml service/mysql-service created [root@master ~]# kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.244.0.1 443/TCP 29h mysql-service NodePort 10.244.140.208 3306:30964/TCP 19s service-hello NodePort 10.244.143.216 80:31111/TCP 20h 5.3、IPVS 代理模式

特性状态: Kubernetes v1.11 [stable]

        在 ipvs 模式下,kube-proxy 监视 Kubernetes 服务和端点,调用 netlink 接口相应地创建 IPVS 规则, 并定期将 IPVS 规则与 Kubernetes 服务和端点同步。 该控制循环可确保IPVS 状态与所需状态匹配。访问服务时,IPVS 将流量定向到后端Pod之一。

        IPVS代理模式基于类似于 iptables 模式的 netfilter 挂钩函数, 但是使用哈希表作为基础数据结构,并且在内核空间中工作。 这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。 与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。

IPVS 提供了更多选项来平衡后端 Pod 的流量。 这些是:

rr:轮替(Round-Robin)lc:最少链接(Least Connection),即打开链接数量最少者优先dh:目标地址哈希(Destination Hashing)sh:源地址哈希(Source Hashing)sed:最短预期延迟(Shortest Expected Delay)nq:从不排队(Never Queue)

5.3.1、kube-proxy配置 ipvs模式(所有节点)

1)加载ip_vs相关内核模块

[root@master ~]# modprobe -- ip_vs [root@master ~]# modprobe -- ip_vs_sh [root@master ~]# modprobe -- ip_vs_rr [root@master ~]# modprobe -- ip_vs_wrr [root@master ~]# modprobe -- nf_conntrack_ipv4 [root@master ~]# lsmod | grep ip_vs ip_vs_sh 12688 0 ip_vs_wrr 12697 0 ip_vs_rr 12600 0 ip_vs 141432 6 ip_vs_rr,ip_vs_sh,ip_vs_wrr nf_conntrack 133053 10 ip_vs,nf_nat,nf_nat_ipv4,nf_nat_ipv6,xt_conntrack,nf_nat_masquerade_ipv4,nf_nat_masquerade_ipv6,nf_conntrack_netlink,nf_conntrack_ipv4,nf_conntrack_ipv6 libcrc32c 12644 4 xfs,ip_vs,nf_nat,nf_conntrack

2)安装ipvsadm工具

[root@master ~]# yum -y install ipset ipvsadm

3)查看kube-proxy 

[root@master ~]# kubectl get pod -n kube-system | grep kube-proxy kube-proxy-2f9x9 1/1 Running 2 (18h ago) 29h kube-proxy-8xjdp 1/1 Running 2 (18h ago) 29h kube-proxy-f425c 1/1 Running 2 (18h ago) 29h kube-proxy-t4pq8 1/1 Running 2 (18h ago) 29h

3)编辑kube-proxy配置文件,mode修改成ipvs 

[root@master ~]# kubectl edit configmaps -n kube-system kube-proxy mode: "ipvs" [root@master ~]# kubectl get pod -n kube-system | grep kube-proxy |awk '{system("kubectl delete pod "$1" -n kube-system")}' pod "kube-proxy-2f9x9" deleted pod "kube-proxy-8xjdp" deleted pod "kube-proxy-f425c" deleted pod "kube-proxy-t4pq8" deleted [root@master ~]# kubectl get pod -n kube-system | grep kube-proxy # 再次查看 kube-proxy-5p5tb 1/1 Running 0 10s kube-proxy-c2vxk 1/1 Running 0 13s kube-proxy-z2hjm 1/1 Running 0 12s kube-proxy-zgjc7 1/1 Running 0 9s [root@master ~]# ipvsadm -Ln

 说明:要在 IPVS 模式下运行 kube-proxy,必须在启动 kube-proxy 之前使 IPVS 在节点上可用。当 kube-proxy 以 IPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。 如果未检测到 IPVS 内核模块,则 kube-proxy 将退回到以 iptables 代理模式运行。

6、服务状态

        从数据层面看状态,数据的状态往往受2个维度有关,一是与时间相关或者顺序相关的,不同的操作顺序可能导致同一个时间点上的数据状态大于1个,二是与数据的副本状态相关的。也就是数据的位置,数据落在多个副本上,可能出现多种数据状态的组合。

        从服务层面看,服务层面的状态取决于实例是单独维护数据还是共享数据,或者说是否存在多个数据闭环让数据的流向产生了多条路径。有状态的服务往往比较难进行水平拓展,在现在容器盛行的环境,把服务设计成无状态的更加高效,即便是有状态的服务,也要将状态内敛在系统的某个范围,比如分布式的存储,对于业务服务,我不需要关心数据在多个副本的状态,数据的状态由分布式存储这个服务本身解决。

差异维度有状态服务无状态服务服务本身服务本身依赖或者存在局部的状态数据,这些数据需要自身持久化或者可以通过其他节点恢复。服务不依赖自身的状态,实例的状态数据可以维护在内存中。节   点一个请求只能被某个节点(或者同等状态下的节点)处理。任何一个请求都可以被任意一个实例处理。数据状态存储状态数据,实例的拓展需要整个系统参与状态的迁移。不存储状态数据,实例可以水平拓展,通过负载均衡将请求分发到各个节点。系统中在一个封闭的系统中,存在多个数据闭环,需要考虑这些闭环的数据一致性问题。在一个封闭的系统中,只存在一个数据闭环。架构中通常存在于分布式架构中。通常存在于单体架构的集群中。相关资源

statefulSet,由于是有状态的服务,所以每个pod都有特定的名称和网络标识。比如pod名是由statefulSet名+有序的数字组成(0、1、2..)

ReplicaSet、ReplicationController、Deployment等,由于是无状态服务,所以这些控制器创建的pod序号都是随机值。并且在缩容的时候并不会明确缩容某一个pod,而是随机的,因为所有实例得到的返回值都是一样,所以缩容任何一个pod都可以。

相关服务有状态服务 可以说是 需要数据存储功能的服务、或者指多线程类型的服务,队列等。(mysql数据库、kafka、zookeeper等)多个实例可以共享相同的持久化数据。例如:nginx实例,tomcat实例等


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3