首先调整kubeproxy 的模式为iptables

kubectl edit configmap kube-proxy -n kube-system
修改

kind: KubeProxyConfiguration
metricsBindAddress: 127.0.0.1:10249
mode: "ipvs"                          ##### 修改这一行留空则为iptables
nodePortAddresses: null

然后杀掉kubeproxy的pod ,让deployment 自动拉起来新配置pod

输出kubeproxy的pod 日志,看是否采用了iptables
kubectl logs kube-proxy-xxx -n kube-system

已经修改模式为iptables了。

目前集群已有svc

NAMESPACE              NAME                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                   AGE
default                go-web-service              NodePort    10.96.97.253    <none>        3009:30009/TCP            20d
kube-system            kube-dns                    ClusterIP   10.96.0.10      <none>        53/UDP,53/TCP,9153/TCP    72d

观察启动go-web-service这条的iptables 脉络

[root@ebs-76642 ~]# iptables -t nat -L KUBE-SERVICES |egrep 'go-web-service'
target     prot opt source               destination
KUBE-MARK-MASQ  tcp  -- !ebs-76642/16         ebs-76642            /* default/go-web-service:http cluster IP */ tcp dpt:pxc-ntfy
KUBE-SVC-KG4IN6CR36NHNLPD  tcp  --  anywhere             ebs-76642            /* default/go-web-service:http cluster IP */ tcp dpt:pxc-ntfy

[root@ebs-76642 ~]# iptables -t nat -L KUBE-SVC-KG4IN6CR36NHNLPD
Chain KUBE-SVC-KG4IN6CR36NHNLPD (2 references)
target     prot opt source               destination
KUBE-SEP-TKPLZBGAW27QFDLO  all  --  anywhere             anywhere             statistic mode random probability 0.50000000000
KUBE-SEP-LEFZ7V5H5GEG5L4O  all  --  anywhere             anywhere

[root@ebs-76642 ~]# iptables -t nat -L KUBE-SEP-TKPLZBGAW27QFDLO
Chain KUBE-SEP-TKPLZBGAW27QFDLO (1 references)
target     prot opt source               destination
KUBE-MARK-MASQ  all  --  172.16.1.43          anywhere
DNAT       tcp  --  anywhere             anywhere             tcp to:172.16.1.43:3009

[root@ebs-76642 ~]# k get pods -A -o wide|grep '172.16.1.43'
default                go-web-app-68797989b8-2vctz                 1/1     Running   3          20d   172.16.1.43      ebs-82413   <none>           <none>

观察kube-dns这条iptables 脉络,这里暴露了三个ports(dns-tcp,dns,metrics)

[root@ebs-76642 ~]# iptables -t nat -L KUBE-SERVICES |egrep 'kube-dns'
KUBE-MARK-MASQ  tcp  -- !ebs-76642/16         ebs-76642            /* kube-system/kube-dns:dns-tcp cluster IP */ tcp dpt:domain
KUBE-SVC-ERIFXISQEP7F7OF4  tcp  --  anywhere             ebs-76642            /* kube-system/kube-dns:dns-tcp cluster IP */ tcp dpt:domain
KUBE-MARK-MASQ  udp  -- !ebs-76642/16         ebs-76642            /* kube-system/kube-dns:dns cluster IP */ udp dpt:domain
KUBE-SVC-TCOU7JCQXEZGVUNU  udp  --  anywhere             ebs-76642            /* kube-system/kube-dns:dns cluster IP */ udp dpt:domain
KUBE-MARK-MASQ  tcp  -- !ebs-76642/16         ebs-76642            /* kube-system/kube-dns:metrics cluster IP */ tcp dpt:9153
KUBE-SVC-JD5MR3NA4I4DYORP  tcp  --  anywhere             ebs-76642            /* kube-system/kube-dns:metrics cluster IP */ tcp dpt:9153

- 先看ports name为dns-tcp 这个的
[root@ebs-76642 ~]# iptables -t nat -L KUBE-SVC-ERIFXISQEP7F7OF4
Chain KUBE-SVC-ERIFXISQEP7F7OF4 (1 references)
target     prot opt source               destination
KUBE-SEP-7LK5TTMYU3GPSJJW  all  --  anywhere             anywhere             statistic mode random probability 0.50000000000
KUBE-SEP-3NE7D5ZQGKE4MF2Z  all  --  anywhere             anywhere

- 对应dns-tcp后端的两个pods
[root@ebs-76642 ~]# iptables -t nat -L KUBE-SEP-7LK5TTMYU3GPSJJW
Chain KUBE-SEP-7LK5TTMYU3GPSJJW (1 references)
target     prot opt source               destination
KUBE-MARK-MASQ  all  --  172.16.0.15          anywhere
DNAT       tcp  --  anywhere             anywhere             tcp to:172.16.0.15:53
[root@ebs-76642 ~]# iptables -t nat -L KUBE-SEP-3NE7D5ZQGKE4MF2Z
Chain KUBE-SEP-3NE7D5ZQGKE4MF2Z (1 references)
target     prot opt source               destination
KUBE-MARK-MASQ  all  --  172.16.1.44          anywhere
DNAT       tcp  --  anywhere             anywhere             tcp to:172.16.1.44:53

k8s配置iptables参数 k8s service iptables_k8s配置iptables参数

k8s配置iptables参数 k8s service iptables_负载均衡_02

对于iptable方式的service:

流量从pod network namespace(cluster ip类型的service)或者外部(node port类型的service)进入到host netwok namespace之中。

在host netwok namespace的PREROUTING chain中会经过一系列target,KUBE-SERVICES(cluster ip类型的service),KUBE-NODEPORTS (node port类型的service),KUBE-SVC-XXX,KUBE-SEP-XXX。

在这些target里根据iptable内核随机模块random来实现匹配endpoint target,实现负载均衡。

在endpoint target(KUBE-SEP-XXX)里实现了DNAT,也就是将目标地址cluster ip转化为实际的pod的ip。

数据包经过以上修改根据host network namespace的路由表做下一跳路由选择。

对于ipvs方式的service:

流量从pod network namespace(cluster ip类型的service)或者外部(node port类型的service)进入到host netwok namespace之中。

对于clutser ip类型的service,在host netwok namespace的PREROUTING chain中经过匹配ipset KUBE-CLUSTER-IP做mask标记操作。

对于node port类型的service,在PREROUTING chain中经过匹配ipset KUBE-NODE-PORT-TCP做mask标记操作。

对于clutser ip类型的service,由于host network namespace中有创建网络设备kube-ipvs0,并且绑定所有cluster ip,这样从pod发出的数据包目标ip为cluster ip,有kube-ipvs0网络设备对应,数据进入INPUT chain中。

对于node port类型的service,由于数据包的目标ip是host的ip地址,所以也进入了host network namespace的INPUT chain中。

利用linux内核模块ipvs,数据在INPUT chain中被ipvs的规则修改(可由ipvsadm查看规则),完成负载均衡和DNAT,然后将数据直接送入POSTROUTING chain。

数据在POSTROUTING chain中,经过KUBE-POSTROUTING target,根据之前的mark操作完成MASQUERADE SNAT。

数据包经过以上修改根据host network namespace的路由表做下一跳路由选择。

对于iptable和ipvs方式的service:

两者都是采用linux内核模块完成负载均衡和endpoint的映射,所有操作都在内核空间完成,没有在应用程序的用户空间。

iptable方式依赖于linux netfilter/iptable内核模块。

ipvs方式依赖linux netfilter/iptable模块,ipset模块,ipvs模块。

iptable方式中,host宿主中ipatble的entry数目会随着service和对应endpoints的数目增多而增多。举个例子,比如有10个cluster ip类型的service,每个service有6个endpoints。那么在KUBE-SERVICES target中至少有10个entries(KUBE-SVC-XXX)与10个service对应,每个KUBE-SVC-XXX target中会有6个KUBE-SEP-XXX与6个endpoints来对应,每个KUBE-SEP-XXX会有2个enrties来分别做mark masq和DNAT,这样算起来至少有1062=120个entries在iptable中。试想如果application中service和endpoints数目巨大,iptable entries也是非常庞大的,在一定情况下有可能带来性能上的问题。

ipvs方式中host宿主中iptable的entry数目是固定的,因为iptable做匹配的时候会利用ipset(KUBE-CLUSTER-IP或者KUBE-NODE-PORT-TCP)来匹配,service的数目决定了ipset的大小,并不会影响iptable的大小。这样就解决了iptable模式下,entries随着service和endpoints的增多而增多的问题。

对于负载均衡,iptable方式采用random模块来完成负载均衡,ipvs方式支持多种负载均衡,例如round-robin,least connection,source hash等(可参考http://www.linuxvirtualserver.org/),并且由kubelet启动参数--ipvs-scheduler控制。

对于目标地址的映射,iptable方式采用linux原生的DNAT,ipvs方式则利用ipvs模块完成。

ipvs方式会在host netwok namespace中创建网络设备kube-ipvs0,并且绑定了所有的cluster ip,这样保证了cluster-ip类型的service数据进入INPUT chain,从而让ipvs来完成负载均衡和目标地址的映射。

iptable方式不会在host netwok namespace中创建额外的网络设备。

iptable方式数据在host network namespace的chain中的路径是:PREROUTING-->FORWARDING-->POSTROUTING

在PREROUTING chain中完成负载均衡,mark masq和目标地址映射。

ipvs方式数据在host network namespace的chain中的路径是:

PREROUTING-->INPUT-->POSTROUTING

在PREROUTING chain中完成mark masq SNAT,在INPUT chain利用ipvs完成负载均衡和目标地址映射。

iptable和ipvs方式在完成负载均衡和目标地址映射后都会根据host network namespace的路由表做下一跳路由选择。

关于iptable和ipvs方式的选择并没有固定答案,要根据项目的需求和实际情况而定。

iptables nat表中的详细过程

[root@docker3 ~]#  iptables -nL -t nat -v
Chain PREROUTING (policy ACCEPT 2 packets, 1152 bytes)
pkts bytes target     prot opt in     out     source               destination        
10837 3999K KUBE-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
====》1. 进入的请求,首先匹配PREROUTING 链里的该规则,并进入KUBE-SERVICES链
  238 27286 DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
 
Chain INPUT (policy ACCEPT 2 packets, 1152 bytes)
pkts bytes target     prot opt in     out     source               destination        
 
Chain OUTPUT (policy ACCEPT 8 packets, 480 bytes)
pkts bytes target     prot opt in     out     source               destination        
61563 3722K KUBE-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    0     0 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL
 
Chain POSTROUTING (policy ACCEPT 8 packets, 480 bytes)
pkts bytes target     prot opt in     out     source               destination        
61840 3742K KUBE-POSTROUTING  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */
====》6. 需要路由到另一个主机的连接经由POSTROUTING该规则,进入KUBE-POSTROUTING 链
   62  4323 MASQUERADE  all  --  *      !docker0  10.2.39.0/24         0.0.0.0/0          
    0     0 MASQUERADE  all  --  *      !docker0  10.1.33.0/24         0.0.0.0/0          
 
Chain DOCKER (2 references)
pkts bytes target     prot opt in     out     source               destination        
    0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0          
 
Chain KUBE-MARK-DROP (0 references)
pkts bytes target     prot opt in     out     source               destination        
    0     0 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            MARK or 0x8000
 
Chain KUBE-MARK-MASQ (6 references)
pkts bytes target     prot opt in     out     source               destination        
    2   128 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            MARK or 0x4000
 
Chain KUBE-NODEPORTS (1 references)
pkts bytes target     prot opt in     out     source               destination        
    2   128 KUBE-MARK-MASQ  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/k8s-nginx: */ tcp dpt:30780
    2   128 KUBE-SVC-2RMP45C4XWDG5BGC  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/k8s-nginx: */ tcp dpt:30780
    ====》3.请求命中上述两个规则,一个进行进入KUBE-MARK-MASQ 链进行标记,一个进入KUBE-SVC-2RMP45C4XWDG5BGC链
 
Chain KUBE-POSTROUTING (1 references)
pkts bytes target     prot opt in     out     source               destination        
    1    64 MASQUERADE  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000
    ====》7. 执行源地址转换(在flannel网络这里转换的地址是flannel.1即flannel在ifconfig里输出接口的地址),发往另一个node
 
Chain KUBE-SEP-D5T62RWZFFOCR77Q (1 references)
pkts bytes target     prot opt in     out     source               destination        
    0     0 KUBE-MARK-MASQ  all  --  *      *       10.2.39.3            0.0.0.0/0            /* default/k8s-nginx: */
    1    64 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/k8s-nginx: */ tcp to:10.2.39.3:80
    ====》5-2. DNAT到本机,交给INPUT
 
Chain KUBE-SEP-IK3IYR4STYKRJP77 (1 references)
pkts bytes target     prot opt in     out     source               destination        
    0     0 KUBE-MARK-MASQ  all  --  *      *       10.2.39.2            0.0.0.0/0            /* kube-system/kube-dns:dns-tcp */
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns-tcp */ tcp to:10.2.39.2:53
 
Chain KUBE-SEP-WV6S37CDULKCYEVE (1 references)
pkts bytes target     prot opt in     out     source               destination        
    0     0 KUBE-MARK-MASQ  all  --  *      *       10.2.39.2            0.0.0.0/0            /* kube-system/kube-dns:dns */
    0     0 DNAT       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */ udp to:10.2.39.2:53
 
Chain KUBE-SEP-X7YOSBI66WAQ7F6X (2 references)
pkts bytes target     prot opt in     out     source               destination        
    0     0 KUBE-MARK-MASQ  all  --  *      *       172.16.199.17        0.0.0.0/0            /* default/kubernetes:https */
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/kubernetes:https */ recent: SET name: KUBE-SEP-X7YOSBI66WAQ7F6X side: source mask: 255.255.255.255 tcp to:172.16.199.17:6443
 
Chain KUBE-SEP-YXWG4KEJCDIRMCO5 (1 references)
pkts bytes target     prot opt in     out     source               destination        
    0     0 KUBE-MARK-MASQ  all  --  *      *       10.2.4.2             0.0.0.0/0            /* default/k8s-nginx: */
    1    64 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/k8s-nginx: */ tcp to:10.2.4.2:80
    ====》5-1. DNAT到另一个node,随后执行postrouting
 
Chain KUBE-SERVICES (2 references)
pkts bytes target     prot opt in     out     source               destination        
    0     0 KUBE-SVC-2RMP45C4XWDG5BGC  tcp  --  *      *       0.0.0.0/0            169.169.148.143      /* default/k8s-nginx: cluster IP */ tcp dpt:80
    0     0 KUBE-SVC-NPX46M4PTMTKRN6Y  tcp  --  *      *       0.0.0.0/0            169.169.0.1          /* default/kubernetes:https cluster IP */ tcp dpt:443
    0     0 KUBE-SVC-TCOU7JCQXEZGVUNU  udp  --  *      *       0.0.0.0/0            169.169.0.53         /* kube-system/kube-dns:dns cluster IP */ udp dpt:53
    0     0 KUBE-SVC-ERIFXISQEP7F7OF4  tcp  --  *      *       0.0.0.0/0            169.169.0.53         /* kube-system/kube-dns:dns-tcp cluster IP */ tcp dpt:53
    2   128 KUBE-NODEPORTS  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL
    ====》2.连接随后并该规则匹配,进入KUBE-NODEPORTS 链
 
Chain KUBE-SVC-2RMP45C4XWDG5BGC (2 references)
pkts bytes target     prot opt in     out     source               destination        
    1    64 KUBE-SEP-D5T62RWZFFOCR77Q  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/k8s-nginx: */ statistic mode random probability 0.50000000000
    1    64 KUBE-SEP-YXWG4KEJCDIRMCO5  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/k8s-nginx: */
====》4.请求被该链中两个规则匹配,这里只有两个规则,按照50% RR规则进行负载均衡分发,两个目标链都是进行DNAT,一个转到本node的pod IP上,一个转到另一台宿主机的pod上,因为该service下只有两个pod

Chain KUBE-SVC-ERIFXISQEP7F7OF4 (1 references)
pkts bytes target     prot opt in     out     source               destination        
    0     0 KUBE-SEP-IK3IYR4STYKRJP77  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns-tcp */
 
Chain KUBE-SVC-NPX46M4PTMTKRN6Y (1 references)
pkts bytes target     prot opt in     out     source               destination        
    0     0 KUBE-SEP-X7YOSBI66WAQ7F6X  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/kubernetes:https */ recent: CHECK seconds: 10800 reap name: KUBE-SEP-X7YOSBI66WAQ7F6X side: source mask: 255.255.255.255
    0     0 KUBE-SEP-X7YOSBI66WAQ7F6X  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/kubernetes:https */
 
Chain KUBE-SVC-TCOU7JCQXEZGVUNU (1 references)
pkts bytes target     prot opt in     out     source               destination        
    0     0 KUBE-SEP-WV6S37CDULKCYEVE  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */