zoukankan      html  css  js  c++  java
  • Kubernetes:深入了解Service

    Kubernetes:深入了解Service

    说白了就是与外界连通,大概分为5个部分。
    ·Service定义。
    ·Pod与Service的关系
    ·Service类型。
    ·Service代理模式。
    ·DNS
    
    部署一个应用,例如写一个deployment,里面有一个字段replicas来指定副本数,一个应用会用很多的副本分布在各个节点上,如果某一个pod由于某种原因崩溃掉了,replicas会帮你再启一个pod,保证副本数量,新启的这个pod肯定是和原来一样的,重启之后容器的IP就发生变化了,但是要怎么动态感知容器IP呢?这就引入了Service的概念,Service可以动态感知全部Pod的IP,并且能提供对外访问入口。
    
    Service的设计目的主要是防止Pod失联,他能获取到所有Pod的IP,所以你不用管容器的IP是什么了,全部交给Service去做就可以了。可以定义Pod的访问策略,也提供了负载均衡的功能,帮你将请求转发到后端的一个pod中,可以支持三种模式,分别是ClusterIP、NodePort、LoadBalancer,Service的底层实现主要是由iptables和IPVS两种网络模式,这两种模式决定了怎么去转发流量。
    

    Service 定义

    [root@k8s01 yml]# nginx_service.yaml 
    apiVersion: v1  ## API 版本
    kind: Service   ## 绑定的资源对象为Service
    metadata:             ## Service源数据,指定service名称和工作空间
      name: nginx-service   ## Service名称
      namespace: default    ## Service工作空间
    spec:             
      clusterIP: 10.0.0.213   ## 默认使用cluster IP 
      ports:                ## port 来定义Service的入口和容器的入口
      - name: http            ##指定端口名称
        port: 80              ## Service 入口
        protocol: TCP         ## 使用协议
        targetPort: 80        ## pod端口,也就是容器端口
      selector:            ##标签选择器,通过标签来匹配要关联的Pod
        app: web            ##关联到标签为app:web 的pod
    

    用这个配置文件创建一个Service

    [root@k8s01 yml]# kubectl create -f nginx_service.yaml
    service/nginx-service created
    [root@k8s01 yml]# kubectl get service
    NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    kubernetes      ClusterIP   10.0.0.1     <none>        443/TCP   3d22h
    nginx-service   ClusterIP   10.0.0.213   <none>        80/TCP    2s
    [root@k8s01 yml]# 
    

    发现有一条默认的Service,他的作用是在集群内部访问apiserver的,通过kubernetes这个DNS名称。

    Service要想动态感知后端IP的变化,他会用到一个名为endpoints的控制器,也就是每个Service会对应一个endpoints控制器,endpoints来帮他关联后端的podService只是关联某一组Pod,动态感知的具体实现时交给endpoints控制器来完成的,下面看一下。

    [root@k8s01 yml]# kubectl create -f deployment.yaml 
    deployment.apps/nginx-deployment created
    [root@k8s01 yml]# kubectl get endpoints 
    NAME            ENDPOINTS                               AGE
    kubernetes      192.168.10.91:6443,192.168.10.94:6443   3d22h
    nginx-service   10.244.2.22:80                          16s
    
    

    第一行为apiserverIP及端口,默认就会创建这一条Service,第二行就是我们刚刚创建的那个。

    回到Service,看上文类型为ClusterIP,也是默认的Service类型,分配的IP是我们刚制定的213,如不指定会有一个随机的IP,那个deployment之前删掉了,现在加回来。

    [root@k8s01 yml]# kubectl get endpoints 
    NAME            ENDPOINTS                                      AGE
    kubernetes      192.168.10.91:6443,192.168.10.94:6443          3d22h
    nginx-service   10.244.0.35:80,10.244.1.56:80,10.244.2.23:80   5m53s
    [root@k8s01 yml]# 
    
    

    endpoints这里决定了将数据包转发到哪里,关联到这个Service是通过标签的,也就是上文的

      selector:            ##标签选择器,通过标签来匹配要关联的Pod
        app: web            ##关联到标签为app:web 的pod
    

    下面查一下具有web标签的pod,通过下面的命令。

    [root@k8s01 yml]# kubectl get pod -l app=web -o wide
    NAME                               READY   STATUS    RESTARTS   AGE     IP            NODE    NOMINATED NODE   READINESS GATES
    nginx-deployment-79cfcb457-hrzm5   1/1     Running   0          3m13s   10.244.2.23   k8s05   <none>           <none>
    nginx-deployment-79cfcb457-s2mhp   1/1     Running   0          3m13s   10.244.1.56   k8s03   <none>           <none>
    nginx-deployment-79cfcb457-zhvfh   1/1     Running   0          3m13s   10.244.0.35   k8s02   <none>           <none>
    [root@k8s01 yml]# 
    
    

    目前是有三个pod,可以看到容器IP和运行节点,容器IP和上面的对比一下,也就是说如果现在有个容器崩了,他帮你又拉起一个容器,新容器新的IP地址,由ENDPOINTS控制器帮你感知到新启动的容器IP和端口,并加入到相对应的Service中,这块对用户来说完全是透明的,查看这个Service的详细信息。

    [root@k8s01 yml]# kubectl describe services nginx-service 
    Name:              nginx-service
    Namespace:         default
    Labels:            <none>
    Annotations:       <none>
    Selector:          app=web
    Type:              ClusterIP
    IP:                10.0.0.213
    Port:              http  80/TCP
    TargetPort:        80/TCP
    Endpoints:         10.244.0.35:80,10.244.1.56:80,10.244.2.23:80
    Session Affinity:  None
    Events:            <none>
    [root@k8s01 yml]# 
    
    

    Pod与Service的关系

    上文提到过,说白了就是Service通过标签选择器来匹配一组Pod,通常来说这组Pod都是在deployment里面定义的,现在看一下之前创建的nginx-deployment标签那里是怎么写的,

    [root@k8s01 yml]# cat deployment.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      labels:
        app: web
    spec:
      selector:
        matchLabels:
          app: web
      replicas: 3
      template:
        metadata:
          labels:
            app: web
        spec:
          containers:
          - name: nginx
            image: nginx:latest
            ports:
            - containerPort: 80
    [root@k8s01 yml]# 
    
    

    可以看到写了标签的位置有三处,作用如下。

    #第一处这个标签可以定义多个,但是不要重复
      labels:
        app: web
        
    #此为控制器使用的标签匹配,
      selector:
        matchLabels:
          app: web
    
    #这个是Pod标签,如果控制器要匹配到这一组Pod,控制器标签和Pod标签要保证一致,才能匹配到,Service实现了Pod的负载均衡,提供的是四层负载均衡,也就是TCP/UDP级别的。
      template:
        metadata:
          labels:
            app: web
    

    Service 类型

    有三种类型,分别如下。
    
    ClusterIP	#默认类型,分配一个集群内部可以访问的虚拟IP(VIP),主要用于集群内部通讯
    
    NodePort	#在每个Node上分配一个端口作为外部访问入口。
    
    LoadBalancer	#工作在特定Cloud Provider上,如谷歌云,aws,OpenStack
    

    ClusterIP

    流量转发用的是iptables/IPVS去实现的,接收到请求后选一个Pod IP & Port将流量转发过去,访问流程大概就是请求先到iptables/IPVS→Service→PodService逻辑上将Pod绑定到一起,对于用户是无感知的,你只需要知道ServiceIP即可,这个主要是集群内部用的,下面的就是之前写的一个Cluster类型的Service

    [root@k8s01 yml]# cat nginx_service.yaml 
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-service
      namespace: default
    spec:             
      clusterIP: 10.0.0.213
      ports:
      - name: http
        port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app: web
    
    

    NodePort

    应用部署到K8S集群中,你面临的问题就是如何让用户访问到你部署的应用,这就会用到最常用的一种方式,NodePort就会在每一个node上暴露一个端口出去,作为访问的统一入口,基于上面的配置改一下。

    [root@k8s01 yml]# cat nginx_service.yaml 
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-service
      namespace: default
    spec:
      type: NodePort
      ports:
      - name: http
        port: 80
        protocol: TCP
        targetPort: 80
        nodePort: 30010
      selector:
        app: web
    [root@k8s01 yml]# kubectl get services 
    NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
    kubernetes      ClusterIP   10.0.0.1     <none>        443/TCP        3d23h
    nginx-service   NodePort    10.0.0.169   <none>        80:30010/TCP   25s
    [root@k8s01 yml]# 
    

    上面的Service就是将标签为nginxPod上的80端口发布到了Node节点的30010端口,Node节点的端口范围是在apiserver`中指定的,也就是这里。

    [root@k8s01 yml]# cat /opt/kubernetes/cfg/kube-apiserver.conf |grep service-node-port
    --service-node-port-range=30000-32767 
    [root@k8s01 yml]# 
    
    

    查看访问结果

    [root@k8s01 yml]# for i in 192.168.10.{92,93,95}:30010;do curl -I $i;done
    HTTP/1.1 200 OK
    Server: nginx/1.17.10
    Date: Fri, 29 May 2020 10:18:16 GMT
    Content-Type: text/html
    Content-Length: 612
    Last-Modified: Tue, 14 Apr 2020 14:19:26 GMT
    Connection: keep-alive
    ETag: "5e95c66e-264"
    Accept-Ranges: bytes
    
    HTTP/1.1 200 OK
    Server: nginx/1.17.10
    Date: Fri, 29 May 2020 10:18:16 GMT
    Content-Type: text/html
    Content-Length: 612
    Last-Modified: Tue, 14 Apr 2020 14:19:26 GMT
    Connection: keep-alive
    ETag: "5e95c66e-264"
    Accept-Ranges: bytes
    
    HTTP/1.1 200 OK
    Server: nginx/1.17.10
    Date: Fri, 29 May 2020 10:18:16 GMT
    Content-Type: text/html
    Content-Length: 612
    Last-Modified: Tue, 14 Apr 2020 14:19:26 GMT
    Connection: keep-alive
    ETag: "5e95c66e-264"
    Accept-Ranges: bytes
    
    

    没问题,这个就是以IPVS方式去做的负载均衡,全部节点能用ipvsadm看到规则,下面看一下,全部node节点安装ipvsadm,执行命令看一下。

    [root@k8s01 yml]# ansible nodes -m yum -a "name=ipvsadm state=installed"
    [root@k8s01 yml]# ansible nodes -m shell -a "ipvsadm -ln | grep 30010 -A 3"
    192.168.10.92 | CHANGED | rc=0 >>
    TCP  192.168.10.92:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    --
    TCP  10.244.0.0:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    --
    TCP  10.244.0.1:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    --
    TCP  127.0.0.1:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    TCP  172.17.0.1:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    192.168.10.93 | CHANGED | rc=0 >>
    TCP  192.168.10.93:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    --
    TCP  10.244.1.0:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    --
    TCP  10.244.1.1:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    --
    TCP  127.0.0.1:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    TCP  172.17.0.1:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    192.168.10.95 | CHANGED | rc=0 >>
    TCP  192.168.10.95:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    --
    TCP  10.244.2.0:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    --
    TCP  10.244.2.1:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    --
    TCP  127.0.0.1:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    TCP  172.17.0.1:30010 rr
      -> 10.244.0.42:80               Masq    1      0          0         
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.2.29:80               Masq    1      0          0         
    [root@k8s01 yml]# 
    
    

    没问题,代理模式一共是两种,一种是iptables,另一种就是现在用的ipvs

    现在有一个问题,暴露端口的范围只是30000-50000,所以实际应用的时候还会加一个代理,譬如一个nginx,使用代理服务器作为访问入口,upstream地址池随便写几个node-IP:port就行了,Pod少这样玩还可以,Pod多了够你受的,Ingress可以解决这个问题

    如果真的用NodePort+代理服务发布服务,NodePort的访问流程如下。

    用户请求→代理服务器→NodeIP:PortPodIP:Port

    LoadBalancer

    [root@k8s01 yml]# kubectl get services 
    NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
    kubernetes      ClusterIP   10.0.0.1     <none>        443/TCP        3d23h
    nginx-service   NodePort    10.0.0.169   <none>        80:30010/TCP   25s
    [root@k8s01 yml]# 
    

    80端口为Pod端口,30010端口是在Node节点暴露的端口,所以外部访问的端口为30010,我需要知道这个端口才能把代理和Service关联起来,上文我指定了这个端口,不指定的话就是随机的,但是使用公有云的LoadBalancer就不用了,他是自动帮你添加创建的Service及生成的端口和每个NodeIpLoadBalancerLoadBalancer提供特定云提供商底层LB接口,直接用去调用就好,他和NodePort的访问流程其实一样,就是他关联后端节点端口是自动的。

    service代理模式

    其实流量转发是由每个Node上部署的kube-proxy组件完成的,网络代理有两种模式,一种是iptables,另一种是IPVS,目前默认使用的都是iptables,现在IPVS属于是稳定版,在部署的时候采用的就是IPVS,看一下kube-proxy的配置文件。

    [root@k8s02 ~]# cat /opt/kubernetes/cfg/kube-proxy.conf 
    KUBE_PROXY_OPTS="--logtostderr=false 
    --v=2 
    --proxy-mode=ipvs 
    --masquerade-all=true 
    --log-dir=/opt/kubernetes/logs 
    --config=/opt/kubernetes/cfg/kube-proxy-config.yml"
    
    [root@k8s02 ~]# 
    
    

    iptables

    安装升级iptables

    [root@k8s02 tools]# yum -y install gcc make libnftnl-devel libmnl-devel autoconf automake libtool bison flex  libnetfilter_conntrack-devel libnetfilter_queue-devel libpcap-devel
    Loaded plugins: fastestmirror
    [root@k8s02 tools]# wget wget https://www.netfilter.org/projects/iptables/files/iptables-1.6.2.tar.bz2
    [root@k8s02 tools]# yum -y install conntrack
    tar xf iptables-1.6.2.tar.bz2 
    cd iptables-1.6.2/
    ./autogen.sh
    ./configure
    make -j4
    make install
    cd /usr/local/sbin
    cp iptables /sbin
    cp iptables-restore /sbin/
    cp iptables-save /sbin/
    

    iptables属于是一个内核级的防火墙,当你创建一个Service的时候,kube-proxy会帮你在所有Node上生成iptables规则,在Node节点可以通过iptables-save查看所有规则,规则的多少在于你Pod&Service的数量,目前用的是ipvs模式,现在将k8s02节点切换至iptables模式,默认用的就是iptables模式,所以把配置文件中的指定删掉就行了,也就是这几行。

    [root@k8s02 ~]# cat /opt/kubernetes/cfg/kube-proxy.conf | grep mode -A 1
    --proxy-mode=ipvs 
    --masquerade-all=true 
    [root@k8s03 opt]# cat /opt/kubernetes/cfg/kube-proxy-config.yml 
    mode: ipvs
    ipvs:
      scheduler: "rr"
    [root@k8s02 ~]# systemctl restart kubelet.service 
    [root@k8s02 ~]# systemctl restart kube-proxy.service
    

    看一下之前创建的Service

    [root@k8s01 yml]# kubectl get svc
    NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
    kubernetes      ClusterIP   10.0.0.1     <none>        443/TCP        6d1h
    nginx-service   NodePort    10.0.0.169   <none>        80:30010/TCP   2d2h
    [root@k8s01 yml]# 
    
    

    现在在一个Node-1节点上检索一下iptables规则,找带有 10.0.0.169 的规则。

    [root@k8s02 ~]# iptables-save | grep "10.0.0.169"
    -A KUBE-SERVICES -d 10.0.0.169/32 -p tcp -m comment --comment "default/nginx-service:http cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
    -A KUBE-SERVICES -d 10.0.0.169/32 -p tcp -m comment --comment "default/nginx-service:http cluster IP" -m tcp --dport 80 -j KUBE-SVC-6IM33IEVEEV7U3GP
    [root@k8s02 ~]# 
    

    可以看到有两条规则,主要是第二条,意思是有请求要访问10.0.0.169这个IP,目标端口是80的都会跳转到一个名为KUBE-SVC-6IM33IEVEEV7U3GP的链中,这就是在你创建Service的时候iptables模式会先创建这条规则,然后我们再看一下KUBE-SVC-6IM33IEVEEV7U3GP链都有啥子规则,主要是下面的这三条。

    [root@k8s02 ~]# iptables-save | grep "KUBE-SVC-6IM33IEVEEV7U3GP"
    -A KUBE-SVC-6IM33IEVEEV7U3GP -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-2TARFLZWM4OAEKXX
    -A KUBE-SVC-6IM33IEVEEV7U3GP -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-3OSEFXMGUVYQSZI7
    -A KUBE-SVC-6IM33IEVEEV7U3GP -j KUBE-SEP-6SCCYNK5UB2KUKJH
    [root@k8s02 ~]# 
    

    三个Pod会对应有三条链,这是一组规则的集合,这组规则就实现了怎么做负载均衡,你可以理解为规则有一个权重值,例如第一条--probability 0.33332999982,这表示有30%的几率会被匹配到这条规则上,iptables的规则匹配是从上到下的,第二条有50%的几率,如果上两条都没匹配到,那就走最后一条了,然后你又会发现这三条规则分别又关联了三条不一样的链,检索一下这三条链都写了什么。

    [root@k8s02 ~]# iptables-save |egrep  "KUBE-SEP-2TARFLZWM4OAEKXX|KUBE-SEP-3OSEFXMGUVYQSZI7|KUBE-SEP-6SCCYNK5UB2KUKJH"
    :KUBE-SEP-2TARFLZWM4OAEKXX - [0:0]
    :KUBE-SEP-3OSEFXMGUVYQSZI7 - [0:0]
    :KUBE-SEP-6SCCYNK5UB2KUKJH - [0:0]
    -A KUBE-SEP-2TARFLZWM4OAEKXX -s 10.244.0.2/32 -j KUBE-MARK-MASQ
    -A KUBE-SEP-2TARFLZWM4OAEKXX -p tcp -m tcp -j DNAT --to-destination 10.244.0.2:80
    -A KUBE-SEP-3OSEFXMGUVYQSZI7 -s 10.244.1.69/32 -j KUBE-MARK-MASQ
    -A KUBE-SEP-3OSEFXMGUVYQSZI7 -p tcp -m tcp -j DNAT --to-destination 10.244.1.69:80
    -A KUBE-SEP-6SCCYNK5UB2KUKJH -s 10.244.2.32/32 -j KUBE-MARK-MASQ
    -A KUBE-SEP-6SCCYNK5UB2KUKJH -p tcp -m tcp -j DNAT --to-destination 10.244.2.32:80
    -A KUBE-SVC-6IM33IEVEEV7U3GP -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-2TARFLZWM4OAEKXX
    -A KUBE-SVC-6IM33IEVEEV7U3GP -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-3OSEFXMGUVYQSZI7
    -A KUBE-SVC-6IM33IEVEEV7U3GP -j KUBE-SEP-6SCCYNK5UB2KUKJH
    [root@k8s02 ~]# 
    

    可以看到一个DNAT的操作,这个操作会将数据包转发到后面的IP:Port上,上面可以看到一共是三个,这三个正是Service代理的IP和端口,看一下ENDPOINTS控制器。

    [root@k8s01 ~]# kubectl get endpoints nginx-service 
    NAME            ENDPOINTS                                     AGE
    nginx-service   10.244.0.2:80,10.244.1.69:80,10.244.2.32:80   2d16h
    [root@k8s01 ~]# 
    

    大概就是这样,不难理解,每个endpoints都有相对应的iptables规则,这是由kube-proxy组件搞定的,出现变化也会刷新这些规则,这就是使用iptables做流量转发和负载均衡实现的方法,负载均衡就是用了iptables一个权重值的概念来实现轮训转发,流量转发使用了DNAT帮你转发到具体的Pod中,下面来看看IPVS是怎么工作的。

    IPVS

    再来了解一下IPVS模式是怎么工作的,在使用iptables的情况下,会发现有两个问题,第一个创建一个Serviceiptables就会创建很多规则,也会涉及到更新,例如我一个pod挂掉了重新启了一个,IP变了,iptables的规则就会刷新,这是一个非增量式的更新,规则越多,消耗越大。

    其二这些规则都是从上到下逐条匹配的,如果你Service&Pod越来越多,那自然的你iptables规则就越来越多,问题就是匹配会有延时,因为一个请求进来,iptables会从上到下进行匹配,规则越多匹配越慢,这两个问题很致命,在大规模的情况下不建议使用iptables模式,而是使用IPVS模式。

    相信很多人都用过LVS,其实LVS就是通过IPVS内核调度模块实现的负载均衡,LVS只支持四层负载均衡,如果你用过LVSIPVS你就很好理解了,一个内核级的调度模块。

    使用了IPVS模式之后,它也是由kube-proxy来维护的,当你创建一个Service,他会生成一个虚拟设备kube-ipvs0,看一下。

    [root@k8s03 ~]# ip addr| grep ipvs
    5: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN 
        inet 10.0.0.33/32 brd 10.0.0.33 scope global kube-ipvs0
        inet 10.0.0.1/32 brd 10.0.0.1 scope global kube-ipvs0
        inet 10.0.0.169/32 brd 10.0.0.169 scope global kube-ipvs0
        inet 10.0.0.2/32 brd 10.0.0.2 scope global kube-ipvs0
        inet 10.0.0.151/32 brd 10.0.0.151 scope global kube-ipvs0
    

    这个设备的IP绑定的正是所有ServiceIP,也就是CLUSTER-IP,都会被绑定到这里,可以看到之前nginx-service使用的203在这里,再看一下IPVS规则,也找nginx-service的。

    [root@k8s03 ~]# ipvsadm -ln | grep "10.0.0.169" -A 3
    TCP  10.0.0.169:80 rr
      -> 10.244.1.64:80               Masq    1      0          0         
      -> 10.244.1.66:80               Masq    1      0          0         
      -> 10.244.2.30:80               Masq    1      0          0         
    [root@k8s03 ~]# 
    
    

    这种规则啥子意思应该都能看懂吧,kube-proxy通过IPVS去刷新规则,IPVS会比iptables的性能好很多,因为IPVS是工作在内核态,而iptables是工作在用户态,IPVS维护成本也比较低,不像iptables那么麻烦。

    iptables与IPVS小结

    对比一下,iptables比较灵活,功能也很强大,但问题就是在于更新规则都是全量去更新的,规则越多,操作越慢,再就是规则匹配这块,从上到下匹配,规则越多,匹配越慢。

    IPVS是工作在内核态的,有更好的性能,而且调度算法也支持很多,iptables暂时只支持轮训,IPVS可以设置很多调度算法,默认rr(轮训),还可以使用wrr(加权轮询)&lc(最小连接)&wlc(加权最小连接)&ip hash,在实际生产环境中最好使用ipvs,具体制定使用什么算法可以在配置文件中指定,使用如下参数

    --ipvs-scheduler=算法
    

    一般不会去动他,默认的就够用了

  • 相关阅读:
    JS防抖和节流
    移动端屏幕适配
    vue、react对比
    HTTP缓存
    程序员必备技术网站
    W3C标准、表现与数据分离、web语义化
    VUE的响应式原理
    react更新渲染及渲染原理
    ubuntu下mysql的环境搭建及使用
    apktool反编译工具
  • 原文地址:https://www.cnblogs.com/opesn/p/13124284.html
Copyright © 2011-2022 走看看