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=算法

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

原文地址:https://www.cnblogs.com/opesn/p/13124284.html