• 【云原生 | 从零开始学Kubernetes】二十、Service代理kube-proxy组件详解


    该篇文章已经被专栏《从零开始学k8s》收录
    上一篇文章:Kubernetes核心技术Service实战 点击跳转

    在这里插入图片描述

    kube-proxy 组件介绍

    Kubernetes service 只是把应用对外提供服务的方式做了抽象,真正的应用跑在 Pod 中的 container 里,我们的请求转到 kubernetes nodes 对应的 nodePort 上,那么 nodePort 上的请求是如何进一步转到提供后台服务的 Pod 的呢? 就是通过 kube-proxy 实现的

    kube-proxy 部署在 k8s 的每一个 Node 节点上,是 Kubernetes 的核心组件,我们创建一个 service 的时候,kube-proxy 会在 iptables 中追加一些规则,为我们实现路由与负载均衡的功能。在 k8s1.8 之前,kube-proxy 默认使用的是 iptables 模式,通过各个 node 节点上的 iptables 规则来实现 service 的负载均衡,但是随着 service 数量的增大,iptables 模式由于线性查找匹配、全量更新等特点,其性能 会显著下降。从 k8s 的 1.8 版本开始,kube-proxy 引入了 IPVS 模式,IPVS 模式与 iptables 同样基于 Netfilter,但是采用的 hash 表,因此当 service 数量达到一定规模时,hash 查表的速度优势就会显现出来,从而提高 service 的服务性能。

    kubectl get pods -n kube-system -o wide
    
    • 1

    service 是一组 pod 的服务抽象,相当于一组 pod 的 LB,负责将请求分发给对应的 pod。service 会为这个 LB 提供一个 IP,一般称为 cluster IP。kube-proxy 的作用主要是负责 service 的实现,具体来说,就是实现了内部从 pod 到 service 和外部的从 node port 向 service 的访问。

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

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

    kube-proxy 三种工作模式

    1、Userspace 方式:

    在这里插入图片描述

    Client Pod 要访问 Server Pod 时,它先将请求发给内核空间中的 service iptables 规则,由它再将请求转给监听在指定套接字上的 kube-proxy 的端口,kube-proxy 处理完请求,并分发请求到指定Server Pod 后,再将请求转发给内核空间中的 service ip,由 service iptables 将请求转给各个节点中 的 Server Pod。

    这个模式有很大的问题,客户端请求先进入内核空间的,又进去用户空间访问 kube-proxy,由 kube-proxy 封装完成后再进去内核空间的 iptables,再根据 iptables 的规则分发给各节点的用户空间的 pod。由于其需要来回在用户空间和内核空间交互通信,因此效率很差。在 Kubernetes 1.1 版本之前,userspace 是默认的代理模型。

    2、iptables 方式:

    在这里插入图片描述

    客户端 IP 请求时,直接请求本地内核 service ip,根据 iptables 的规则直接将请求转发到到各 pod 上,因为使用 iptable NAT 来完成转发,也存在不可忽视的性能损耗。另外,如果集群中存上万的 Service/Endpoint,那么 Node 上的 iptables rules 将会非常庞大,性能还会再打折 iptables 代理模式由 Kubernetes 1.1 版本引入,自 1.2 版本开始成为默认类型。

    3、ipvs 方式:

    在这里插入图片描述

    Kubernetes 自 1.9-alpha 版本引入了 ipvs 代理模式,自 1.11 版本开始成为默认设置。客户端请求时到达内核空间时,根据 ipvs 的规则直接分发到各 pod 上。kube-proxy 会监视 Kubernetes Service 对象和 Endpoints,调用 netlink 接口以相应地创建 ipvs 规则并定期与 Kubernetes Service 对象和 Endpoints 对象同步 ipvs 规则,以确保 ipvs 状态与期望一致。访问服务时,流量将被重定向到其中一个后端 Pod。与 iptables 类似,ipvs 基于 netfilter 的 hook 功能,但使用哈希表作为底层数据结构并在内核空间中工作。这意味着 ipvs 可以更快地重定向流量,并且在同步代理规则时具有更好的性能。此外,ipvs 为负载均衡算法提供了更多选项,例如:

    rr:轮询调度  
    
    lc:最小连接数  
    
    dh:目标哈希  
    
    sh:源哈希  
    
    sed:最短期望延迟  
    
    nq:不排队调度 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    如果某个服务后端 pod 发生变化,标签选择器适应的 pod 又多一个,适应的信息会立即反映到 apiserver 上,而 kube-proxy 一定可以 watch 到 etc 中的信息变化,而将它立即转为 ipvs 或者 iptables 中的规则,这一切都是动态和实时的,删除一个 pod 也是同样的原理。

    在这里插入图片描述

    以上不论哪种,kube-proxy 都通过 watch 的方式监控着 apiserver 写入 etcd 中关于 Pod 的最新状态信息,它一旦检查到一个 Pod 资源被删除了或新建了,它将立即将这些变化反应在 iptables 或 ipvs 规则中,以便 iptables 和 ipvs 在调度 Clinet Pod 请求到 Server Pod时不会出现 Server Pod 不存在的情况。自 k8s1.11 以后,service 默认使用 ipvs 规则,若 ipvs 没有被激活,则降级使用 iptables 规则.

    kube-proxy 生成的 iptables 规则分析

    1、service 的 type 类型是 ClusterIp,iptables 规则分析

    在 k8s 创建的 service,虽然有 ip 地址,但是 service 的 ip 是虚拟的,不存在物理机上的,是在 iptables 或者 ipvs 规则里的。

    [root@k8smaster service]# kubectl apply -f pod_test.yaml 
    [root@k8smaster service]# kubectl apply -f service_test.yaml 
    [root@k8smaster node]# kubectl get svc -l run=my-nginx
    NAME       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
    my-nginx   ClusterIP   10.105.254.244   <none>        80/TCP    15s
    [root@k8smaster node]# kubectl get pods -l run=my-nginx -o wide
    NAME                        READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE  
    my-nginx-5898cf8d98-5trvw   1/1     Running   0          40s   10.244.1.5   k8snode2   <none>          
    my-nginx-5898cf8d98-phfqr   1/1     Running   0          40s   10.244.1.4   k8snode2   <none>          
    [root@k8smaster node]# iptables -t nat -L | grep 10.105.254.244
    KUBE-MARK-MASQ  tcp  -- !10.244.0.0/16        10.105.254.244       /* default/my-nginx: cluster IP */ tcp dpt:http
    KUBE-SVC-BEPXDJBUHFCSYIC3  tcp  --  anywhere             10.105.254.244       /* default/my-nginx: cluster IP */ tcp dpt:http
    
    [root@k8smaster node]# iptables -t nat -L | grep KUBE-SVC-BEPXDJBUHFCSYIC3
    KUBE-SVC-BEPXDJBUHFCSYIC3  tcp  --  anywhere             10.105.254.244       /* default/my-nginx: cluster IP */ tcp dpt:http			#把service关联的pod做了转发
    Chain KUBE-SVC-BEPXDJBUHFCSYIC3 (1 references)		
    
    [root@k8smaster node]# iptables -t nat -L | grep 10.244.1.5
    KUBE-MARK-MASQ  all  --  10.244.1.5           anywhere             /* default/my-nginx: */
    DNAT       tcp  --  anywhere             anywhere             /* default/my-nginx: */ tcp to:10.244.1.5:80
    #DNAT转发 kubesvc接收请求,在过滤podip的时候有个mark也会标记ip,然后做了一个dnat转发到10.244.1.5:80这个pod上
    
    #通过上面可以看到之前创建的 service,会通过 kube-proxy 在 iptables 中生成一个规则,来实现流量路由,有一系列目标为 KUBE-SVC-xxx 链的规则,每条规则都会匹配某个目标 ip 与端口。也就是说访问某个 serivce的ip和端口请求会由 KUBE-SVC-xxx 链来通过DNAT转发到对应的podip和端口上。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2、service 的 type 类型是 nodePort,iptables 规则分析

    [root@k8smaster node]# kubectl apply -f pod_nodeport.yaml 
    deployment.apps/my-nginx-nodeport created
    [root@k8smaster node]# kubectl apply -f service_nodeport.yaml 
    service/my-nginx-nodeport created
    
    [root@k8smaster node]# kubectl get pods -l run=my-nginx-nodeport -o wide
    NAME                                 READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED
    my-nginx-nodeport-5fccbb754b-m4csx   1/1     Running   0          34s   10.244.1.7   k8snode2   <none>      
    my-nginx-nodeport-5fccbb754b-rg48l   1/1     Running   0          34s   10.244.1.6   k8snode2   <none>
    [root@k8smaster node]# kubectl get svc -l run=my-nginx-nodeport 
    NAME                TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
    my-nginx-nodeport   NodePort   10.105.58.82   <none>        80:30380/TCP   39s
     
    [root@k8smaster node]# iptables -t nat -S | grep 30380 
    -A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp --dport 30380 -j KUBE-MARK-MASQ
    -A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp --dport 30380 -j KUBE-SVC-6JXEEPSEELXY3JZG
    #一个是mark链一个是svc 在访问物理机ip和端口,访问会先经过这两个链
    
    [root@k8smaster node]# iptables -t nat -S | grep KUBE-SVC-6JXEEPSEELXY3JZG
    -N KUBE-SVC-6JXEEPSEELXY3JZG
    -A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp --dport 30380 -j KUBE-SVC-6JXEEPSEELXY3JZG
    -A KUBE-SERVICES -d 10.105.58.82/32 -p tcp -m comment --comment "default/my-nginx-nodeport: cluster IP" -m tcp --dport 80 -j KUBE-SVC-6JXEEPSEELXY3JZG
    -A KUBE-SVC-6JXEEPSEELXY3JZG -m comment --comment "default/my-nginx-nodeport:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-36FBCF7ZW3VDH33Q
    -A KUBE-SVC-6JXEEPSEELXY3JZG -m comment --comment "default/my-nginx-nodeport:" -j KUBE-SEP-K2MGI3AJIGBK3IJ5
    #会通过iptables的probability机制有0.50的概率进入KUBE-SEP-36FBCF7ZW3VDH33Q这个链,剩下50%还是最后那个GBK3IJ5这个链
    
    [root@k8smaster node]# iptables -t nat -S | grep KUBE-SEP-36FBCF7ZW3VDH33
    -N KUBE-SEP-36FBCF7ZW3VDH33Q
    -A KUBE-SEP-36FBCF7ZW3VDH33Q -s 10.244.1.6/32 -m comment --comment "default/my-nginx-nodeport:" -j KUBE-MARK-MASQ
    -A KUBE-SEP-36FBCF7ZW3VDH33Q -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp -j DNAT --to-destination 10.244.1.6:80
    -A KUBE-SVC-6JXEEPSEELXY3JZG -m comment --comment "default/my-nginx-nodeport:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-36FBCF7ZW3VDH33Q
    
    #-A KUBE-SEP-36FBCF7ZW3VDH33Q -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp -j DNAT --to-destination 10.244.1.6:80 是做了一个dnat把请求给10.244.1.6这个pod的80端口了 下面可以看到ip是相同的
    [root@k8smaster node]# kubectl get pods -l run=my-nginx-nodeport -o wide
    NAME                                 READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED
    my-nginx-nodeport-5fccbb754b-m4csx   1/1     Running   0          8m24s   10.244.1.7   k8snode2   <none>    
    my-nginx-nodeport-5fccbb754b-rg48l   1/1     Running   0          8m24s   10.244.1.6   k8snode2   <none>    
    
     
    [root@k8smaster node]# iptables -t nat -S | grep KUBE-SEP-K2MGI3AJIGBK3IJ5
    -N KUBE-SEP-K2MGI3AJIGBK3IJ5
    -A KUBE-SEP-K2MGI3AJIGBK3IJ5 -s 10.244.1.7/32 -m comment --comment "default/my-nginx-nodeport:" -j KUBE-MARK-MASQ
    -A KUBE-SEP-K2MGI3AJIGBK3IJ5 -p tcp -m comment --comment "default/my-nginx-nodeport:" -m tcp -j DNAT --to-destination 10.244.1.7:80
    -A KUBE-SVC-6JXEEPSEELXY3JZG -m comment --comment "default/my-nginx-nodeport:" -j KUBE-SEP-K2MGI3AJIGBK3IJ5
    #也是一个dnat,把请求分给另外一个pod,通过这两个链50%的概率来转发到两个pod上
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    写在最后

    创作不易,如果觉得内容对你有帮助,麻烦给个三连关注支持一下我!如果有错误,请在评论区指出,我会及时更改!
    目前正在更新的系列:从零开始学k8s
    感谢各位的观看,文章掺杂个人理解,如有错误请联系我指出~
    在这里插入图片描述

  • 相关阅读:
    客户服务质量提升的三种思路
    微信小程序开发实战6_2 获取用户信息
    农村创业最新项目有哪些?适合青年农民创业!
    2022C语言知识点大全【详细、必备】
    项目构建工具maven
    计算机网络复习-第六章应用层
    Centos7安装Redis6.2.7-sentinel高可用步骤
    统计信号处理基础 习题解答10-15
    微服务 Spring Cloud 7,Nacos配置中心的Pull原理,附源码
    docker部署JAVA项目
  • 原文地址:https://blog.csdn.net/qq_45400861/article/details/126850632