• 8.kubeproxy组件详解


    1.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的服务性能。

    service是一组pod的服务抽象,相当于一组pod的LB,负责将请求分发给对应的pod。service会为这个LB提供一个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。

    2.kube-proxy三种工作模式

    • Userspace方式:
      image
      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是默认的代理模型。

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

    • ipvs方式:
      image
      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:不排队调度

      如果某个服务后端pod发生变化,标签选择器适应的pod又多一个,适应的信息会立即反映到apiserver上,而kube-proxy一定可以watch到etc中的信息变化,而将它立即转为ipvs或者iptables中的规则,这一切都是动态和实时的,删除一个pod也是同样的原理。如图:
      image
      注:
      以上不论哪种,kube-proxy都通过watch的方式监控着apiserver写入etcd中关于Pod的最新状态信息,它一旦检查到一个Pod资源被删除了或新建了,它将立即将这些变化,反应再iptables 或 ipvs规则中,以便iptables和ipvs在调度Clinet Pod请求到Server Pod时,不会出现Server Pod不存在的情况。自k8s1.11以后,service默认使用ipvs规则,若ipvs没有被激活,则降级使用iptables规则.

    3.service的type类型是ClusterIp,iptables规则分析

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

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-nginx
    spec:
      selector:
        matchLabels:
          run: my-nginx
      replicas: 2
      template:
        metadata:
          labels:
            run: my-nginx
        spec:
          containers:
          - name: my-nginx
            image: nginx
            imagePullPolicy: IfNotPresent
            ports:
            - containerPort: 80  #pod中的容器需要暴露的端口
    

    service_test.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: my-nginx
      labels:
        run: my-service
    spec:
      type: ClusterIP
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        run: my-nginx
    
    [root@master1]# kubectl apply -f pod_test.yaml
    [root@master1]# kubectl apply -f service_test.yaml
    
    [root@master1 service]# kubectl get svc -l run=my-service
    NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
    my-nginx   ClusterIP   10.98.63.235   <none>        80/TCP    75s
    
    
    [root@master1 service]# kubectl get pods -l run=my-nginx -o wide
    NAME                        READY   STATUS    RESTARTS   AGE   IP
    my-nginx-69f769d56f-6fn7b   1/1     Running   0          13m   10.244.121.22
    my-nginx-69f769d56f-xzj5l   1/1     Running   0          13m   10.244.121.21
    
    [root@master1 service]# iptables -t nat -L | grep 10.98.63.235
    KUBE-MARK-MASQ  tcp  -- !10.244.0.0/16        10.98.63.235         /* default/my-nginx cluster IP */ tcp dpt:http
    KUBE-SVC-L65ENXXZWWSAPRCR  tcp  --  anywhere             10.98.63.235         /* default/my-nginx cluster IP */ tcp dpt:http
    
    [root@master1 service]# iptables -t nat -L | grep KUBE-SVC-L65ENXXZWWSAPRCR
    KUBE-SVC-L65ENXXZWWSAPRCR  tcp  --  anywhere             10.98.63.235         /* default/my-nginx cluster IP */ tcp dpt:http
    Chain KUBE-SVC-L65ENXXZWWSAPRCR (1 references)
    
    [root@master1 service]# iptables -t nat -L | grep 10.244.121.22
    KUBE-MARK-MASQ  all  --  10.244.121.22        anywhere             /* default/my-nginx */
    DNAT       tcp  --  anywhere             anywhere             /* default/my-nginx */ tcp to:10.244.121.22:80
    
    [root@master1 service]# iptables -t nat -L | grep 10.244.121.21
    KUBE-MARK-MASQ  all  --  10.244.121.21        anywhere             /* default/my-nginx */
    DNAT       tcp  --  anywhere             anywhere             /* default/my-nginx */ tcp to:10.244.121.21:80
    

    通过上面可以看到之前创建的service,会通过kube-proxy在iptables中生成一个规则,来实现流量路由,有一系列目标为 KUBE-SVC-xxx 链的规则,每条规则都会匹配某个目标 ip 与端口。也就是说访问某个 ip:port 的请求会由 KUBE-SVC-xxx 链来处理。这个目标 IP 其实就是service ip。

    4.service的type类型是nodePort,iptables规则分析

    pod_nodeport.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-nginx-nodeport
    spec:
      selector:
        matchLabels:
          run: my-nginx-nodeport
      replicas: 2
      template:
        metadata:
          labels:
            run: my-nginx-nodeport
        spec:
          containers:
          - name: my-nginx-nodeport-container
            image: nginx
            imagePullPolicy: IfNotPresent
            ports:
            - containerPort: 80
    

    service_nodeport.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: my-nginx-nodeport
      labels:
        run: my-nginx-nodeport
    spec:
      type: NodePort
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
        nodePort: 30380
      selector:
        run: my-nginx-nodeport
    
    [root@master1]# kubectl apply -f pod_nodeport.yaml 
    [root@master1]# kubectl apply -f service_nodeport.yaml 
    
    [root@master1 service]# kubectl get pods -l  run=my-nginx-nodeport
    NAME                                 READY   STATUS    RESTARTS   AGE
    my-nginx-nodeport-649c945f85-l2hj6   1/1     Running   0          21m
    my-nginx-nodeport-649c945f85-zr47r   1/1     Running   0          21m
    
    [root@master1 service]# kubectl get svc -l run=my-nginx-nodeport
    NAME                TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
    my-nginx-nodeport   NodePort   10.104.251.190   <none>        80:30380/TCP   22m
    
    [root@master1 service]# 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-J5QV2XWG4FEBPH3Q
    
    [root@master1 service]# iptables -t nat -S | grep KUBE-SVC-J5QV2XWG4FEBPH3Q
    -N KUBE-SVC-J5QV2XWG4FEBPH3Q
    -A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-nginx-nodeport" -m tcp --dport 30380 -j KUBE-SVC-J5QV2XWG4FEBPH3Q
    -A KUBE-SERVICES -d 10.104.251.190/32 -p tcp -m comment --comment "default/my-nginx-nodeport cluster IP" -m tcp --dport 80 -j KUBE-SVC-J5QV2XWG4FEBPH3Q
    -A KUBE-SVC-J5QV2XWG4FEBPH3Q -m comment --comment "default/my-nginx-nodeport" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-XRUO23GXY67LXLQN
    -A KUBE-SVC-J5QV2XWG4FEBPH3Q -m comment --comment "default/my-nginx-nodeport" -j KUBE-SEP-IIBDPNPJZXXASELC
    
    [root@master1 service]# iptables -t nat -S | grep KUBE-SEP-XRUO23GXY67LXLQN
    -N KUBE-SEP-XRUO23GXY67LXLQN
    -A KUBE-SEP-XRUO23GXY67LXLQN -s 10.244.102.90/32 -m comment --comment "default/my-nginx-nodeport" -j KUBE-MARK-MASQ
    -A KUBE-SEP-XRUO23GXY67LXLQN -p tcp -m comment --comment "default/my-nginx-nodeport" -m tcp -j DNAT --to-destination 10.244.102.90:80
    -A KUBE-SVC-J5QV2XWG4FEBPH3Q -m comment --comment "default/my-nginx-nodeport" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-XRUO23GXY67LXLQN
    
    [root@master1 service]# iptables -t nat -S | grep KUBE-SEP-IIBDPNPJZXXASELC
    -N KUBE-SEP-IIBDPNPJZXXASELC
    -A KUBE-SEP-IIBDPNPJZXXASELC -s 10.244.121.23/32 -m comment --comment "default/my-nginx-nodeport" -j KUBE-MARK-MASQ
    -A KUBE-SEP-IIBDPNPJZXXASELC -p tcp -m comment --comment "default/my-nginx-nodeport" -m tcp -j DNAT --to-destination 10.244.121.23:80
    -A KUBE-SVC-J5QV2XWG4FEBPH3Q -m comment --comment "default/my-nginx-nodeport" -j KUBE-SEP-IIBDPNPJZXXASELC
    
  • 相关阅读:
    QT学习1
    时域和频域
    win10 + VS2017 + MNN 编译使用
    深度学习笔记(二十二)Structure-Preserving Neural Style Transfer
    miRNA分析
    mRNA分析
    代谢组学分析
    实证分析
    React---新扩展RenderProps和ErrorBoundary
    React---新扩展Context和组件优化
  • 原文地址:https://www.cnblogs.com/forlive/p/15961994.html
Copyright © 2020-2023  润新知