• 【云原生】K8S--负载均衡详细介绍;什么是K8S的负载均衡?


    一、K8S云原生服务集群问题

    (一)负载均衡原理

    在之前的文章说过,每一个Pod都是独立的IP、HostName、存储,同时Pod是随时可以被动态创建和回收的,那么就有个问题,我们如何知道Pod的IP并进行访问的呢? 其实K8S是使用Service VIP技术的虚拟ip + kube-proxy来解决这个问题,其中service VIP用来转发请求,kube-proxy用来监控pod状态,并且会及时修改pod的ip。

    service是K8S的资源对象,service资源对象运行在每一个node节点上,每一个node节点都有一个service进程,service有自己的IP地址(虚拟IP),而service VIP相当于一个网关,所有的请求都要经过service VIP,通过service VIP进行转发,从而实现负载均衡。

    service VIP一旦被创建,是不会被修改的,除非删除service后重新创建service;同时由于service信息存储在高可用的etcd中,且service实例运行在多个node节点上,因此Service VIP不存在单点故障的问题;由于service VIP中使用的是虚拟IP,因此Service VIP只能在局域网内部进行访问,不能通过外网进行访问,如果想要进行外网访问,则需要借助物理网卡进行端口映射转发。

    在K8S中IP资源的分类如下:

    • Node IP:Node物理节点IP

    • Pod IP:物理机内部运行的一个虚拟容器pod的ip

    • cluster IP:集群IP,也是个虚拟IP,是K8S抽象出来的一个service的IP。此IP只能局域网内部访问,不能通过外网访问,如果要使用外网访问,就必须开辟nodeport类型的IP地址。如下图所示,外网访问物理IP,然后将访问请求映射到service VIP上,service VIP从etcd上获取endpoints中pod的IP,然后使用负载均衡策略选择一个pod进行调用

    在这里插入图片描述

    (二)Pod服务发现

    Pod服务发现借助kube-proxy实现,该组件实现了三件事情:监控pod;pod如果发生了变化,及时修改映射关系;修改映射关系的同时,修改路由规则,以便在负载均衡时可以选择到新的pod。

    在这里插入图片描述

    二、负载均衡方案(四层负载)

    K8S的负载均衡方案有三种:kube-proxy(userspace)、iptables(防火墙)、ipvs。

    1、kube-proxy

    使用kube-proxy的负载方案是使用kube-proxy来监控pod的状态,如果pod发生了变化,则需要kube-proxy去修改service和pod的映射关系(endpoints),同时修改路由规则,并且由kube-proxy转发请求,这种方式kube-proxy的压力比较大,性能可能会出现问题。
    在这里插入图片描述

    2、IPtables

    IPtables是K8S默认采用的负载策略,这种方式中,kube-proxy同样用来监控pod和修改映射关系以及修改路由规则,但是转发请求是采用轮询iptables路由规则的方式进行调用处理的。

    在这里插入图片描述
    这种模式kube-proxy主要做好watching Cluster API即可,路由和请求的转发都交给了iptables,但是kube-proxy在请求无响应时会换一个pod进行重试,而iptables则是一条条的路由规则,不会进行重试。

    在iptables中,默认的轮询策略是随机的轮询策略,但是也可以将其设置为轮询。

    (1)设置为随机策略

    # 随机:(Random balancing)
    iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -m statistic --mode random --probability 0.33  -j DNAT --to-destination 10.0.0.2:1234
    iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -m statistic --mode random --probability 0.5 -j DNAT --to-destination 10.0.0.3:1234
    iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017  -j DNAT --to-destination 10.0.0.4:1234
    
    • 1
    • 2
    • 3
    • 4

    在iptables命令中,命令的执行和顺序有关,在上述命令中,用–probability 设置了命中几率,第一条设置了纪律是0.33,也就是整个请求的0.33,第二条命中率为0.5,实际是剩余请求的0.5,也就是总请求的0.335,第三条是剩余的流量全部打到该ip上,也就是0.335,基本上就是随机分配了。

    (2)设置为轮询策略

    #every:每n个包匹配一次规则
    #packet:从第p个包开始
    iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -m statistic --mode nth --every 3 --packet 0 -j DNAT --to-destination 10.0.0.2:1234
    iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -m statistic --mode nth --every 2 --packet 0  -j DNAT --to-destination 10.0.0.3:1234
    iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -j DNAT --to-destination 10.0.0.4:1234
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3、IPVS

    ipvs (IP Virtual Server) 实现传输层负载均衡,通常称为第四层LAN交换,是Linux内核的一部分。

    ipvs与iptables的区别:

    • ipvs为大型集群提供了更好的可扩展性和性能

    • ipvs支持比iptables更复杂的负载均衡算法

    • ipvs支持服务器的健康检查和连接重试等。

    对于上述差异做个说明:

    在linux中iptables设计是用于防火墙的,对于比较少的规则,没有太多的性能影响,如果对于一个庞大的K8S集群,会有上千Service服务,Service服务会对应多个pod,每条都是一个iptables规则,那么对于集群来说,每个node上都有大量的规则,简直是噩梦。而IPVS则是使用hash tables来存储网络转发规则的,比iptables更有优势,而且ipvs主要工作在kerbespace,减少了上下文的切换。

    IPVS有轮询(rr)、最小连接数(lc)、目的地址hash(dh)、源地址hash(sh)、最短期望延迟(sed)、无须队列等待(nq)等负载均衡算法,在node上通过 “–ipvs-scheduler”参数,指定kube-proxy的启动算法。

    kube-proxy和IPVS合作的流程:

    (1)kube-proxy仍然是watching Cluster API,获取新建、删除Service或Endpoint pod指令,如果有新的Service建立,kube-proxy回调网络接口,构建IPVS规则。

    (2)kube-proxy会定期同步Service和Pod的转发规则,确保失效的转发可以被及时修复

    (3)有请求转发到后端的集群时,IPVS的负载均衡直接将其转发到对应的Pod上

    三、Ingres-nginx(七层负载均衡)

    (一)为什么要使用Ingres

    1、先介绍以下部署K8S服务时使用到的配置文件:

    创建配置文件(ingres.yaml),用来部署一个nginx的deployment和service

    # 创建一个service资源对象
    # kubectl expose deployment xxName –port=80 –target-port=80    k8s指令模式创建一个service
    # k8s部署yaml方式
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
      namespace: default
    spec:
      selector:
        app: nginx
      ports:
      - port: 80
        targetPort: 80
    ---
    
    # 部署deployment对象,k8s创建3个资源对象:Deployment,ReplicaSet,POD
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:1.16
            ports:
            - containerPort: 80
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    对上面的配置文件做个描述:
    在这里插入图片描述

    首先看Deployment:

    apiVersion标记版本,Kind标记类型,说明要创建一个Deployment,该deployment的名字叫nginx,空间为默认空间。

    spec下是rs和pod的配置,首先replicas是副本的数量,然后就是选择器的名称为nginx。

    template下是副本的配置,首先副本的标签是nginx,容器的名字是nginx,镜像为nginx1.16,这里可以配置为镜像仓库地址和对应的镜像,最后ports是容器开放的端口。

    这里说明几个比较重要的配置,就是选择器的名称和容器的标签一定要一致(绿色连接线),否则容器不会被副本控制器RS所控制。

    然后说一下Service:

    apiVersion和Kind都和Deployment一样,Kind的值表明了这是一个Service配置。

    然后就是这个service的名字,service标签选择器的名字,以及目标容器的端口。

    这里说几个比较重要的配置,和Deployment一样,选择器的名字要和容器的名字一致(绿色连接线),目标容器端口要和容器的端口保持一致(紫色连接线)

    执行配置文件,生成deployment和service:

    kubectl apply -f ingres.yaml
    
    • 1

    执行后查看deployment、service、rs、pod的情况(注意:这一步一般时间比较久,需要等一会)
    在这里插入图片描述
    从上面图片的输出中可以看到,nginx的type为ClusterIp,这种类型的service只能在集群内部访问,而不能在外部直接访问,那么就需要修改类型为NodePort,修改命令:

    kubectl edit svc nginx
    
    • 1

    在这里插入图片描述
     更改完毕之后,重新查看service,发现type已经变为NodePort,且port也变更了,前面的80是容器内的端口,后面的31758是对外开放的端口,也就是宿主机的端口。
    在这里插入图片描述
    此时,使用宿主机的ip + 31758访问,即可访问nginx

    在这里插入图片描述
    但是有个问题,就是如果每个服务都要对外开启一个端口,那么就需要开启很多的端口,这样即麻烦又有点浪费,因此就需要Ingres来解决这个问题,Ingres只需要一个NodePort就可以解决上述的问题。因为ingress相当于一个7层的负载均衡器,是k8s对反向代理的一个抽象。大概的工作原理也确实类似于Nginx,可以理解成在 Ingress 里建立一个个映射规则 , ingress Controller 通过监听 Ingress这个api对象里的配置规则并转化成 Nginx 的配置(kubernetes声明式API和控制循环) , 然后对外部提供服务。

    (二)Ingres-Nginx介绍

    Ingres是K8S对于nginx进行云原生模式的封装,使得nginx更适合云原生的结构,使用Ingres可以对Service进行负载均衡,因此Ingres工作在七层,属于七层负载均衡。

    Ingres通过http协议的方式实现Service的负载均衡:
    在这里插入图片描述
    对于K8S来说,Ingres就是一个资源控制器,用来控制资源的访问策略,

    (三)部署Ingres及使用同一个域名访问不同服务

    Ingres的配置文件如下所示:

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: nginx
      namespace: default
      labels:
        app: nginx
    spec:
      rules:
      - host: ingress.lcl.com
        http:
          paths:
          - backend:
              serviceName: nginx
              servicePort: 80
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在上面文件中,配置了Ingres的规则,那么对于使用同一个域名访问不同服务的配置,则是在paths下面增加多个path路径,让path指向不同的服务,并且在metadata中新增请求重写配置annotations,去除path的路径,保证访问到指定服务上的路径不带有该path,具体配置如下所示:

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: nginx
      namespace: default
      labels:
        app: nginx
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: / # 请求重写
    spec: 
      rules:
      - host: ingress.lcl.com
        http:
          paths:
            - path: /nginx   # 把path追加到域名后面 ingress.lcl.com/nginx   把/nignx当成服务请求的一部分
              backend:
                serviceName: nginx
                servicePort: 80
            - path: /tomcat
              backend:
                serviceName: tomcat
                servicePort: 8080
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    (四)不同域名访问不同服务

    不同域名访问不同服务主要是在rules下面配置不同的规则即可。

    # 使用多个域名,访问不同的服务
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: nginx
      namespace: default
      labels:
        app: nginx
    spec:
      rules:
      - host: ingress.lcl.com
        http:
          paths:
          - path: /
            backend:
             serviceName: nginx
             servicePort: 80
      - host: ingress.lcl.com
        http:
          paths:
          - path: /
            backend:
             serviceName: tomcat
             servicePort: 8080
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    (五)Ingres和https

    如果想将http请求升级为https,我们就需要制作证书

    # 生成私钥
    openssl genrsa -out lcl.key 2048
    # 自签发证书
    openssl req -new -x509 -key lcl.key -out lcl.crt -subj /C=CN/ST=Shanghai/L=Shanghai/O=DevOps/CN=ingres.lcl.com
    # 创建K8S使用的证书
    kubectl create secret tls lcl-secret --cert=lcl.crt --key=lcl.key
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    创建ingres,使用证书的Ingres

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: ingress-tomcat-tls
      namespace: default
      annotations:
        kubernetes.io/ingress.class: "nginx"
      labels:
        app: tomcat
    spec:
      tls:
      - hosts:
        - ingress.lcl.com
        secretName: lcl
      rules:
      - host: ingres.lcl.com
        http:
          paths:
            - backend:
                serviceName: nginx
                servicePort: 8080
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    查看secret资源

    kubectl describe secret lcl
    
    • 1

    修改原来的ingres配置文件

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: nginx
      namespace: default
      labels:
        app: nginx
    spec:
      tls:
      - hosts:
        - ingres.lcl.com
        secretName: lcl-secret
      rules:
      - host: ingress.lcl.com
        http:
          paths:
          - backend:
              serviceName: nginx
              servicePort: 80
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 相关阅读:
    [Python数据可视化] Plotly:交互式数据可视化的强大工具
    【Halcon算子】get_contour_attrib_xld和get_contour_global_attrib_xld
    Spark Optimizer 规则下的 BUG 排查与修复全记录
    入门后端开发得学什么?这份超详细的后端开发学习路线图值得推荐!
    什么是正向代理和反向代理
    数据增强:Simple Questions Generate Named Entity Recognition Datasets
    大管家前端线上笔试
    Linux2-系统自有服务防火墙与计划任务
    .net 6或5调用webservice自定义头。(金碟里的SessionId的传递)
    leetcode-简单
  • 原文地址:https://blog.csdn.net/weixin_39589455/article/details/125614300