目录:

  1. ipvs vs iptables
  2. ipvs kube-proxy原理分析
    2.1.cluster-ip到pod访问
    2.2.node-ip到pod访问
  3. 总结

IPVS简介:

尽管 Kubernetes 在版本v1.6中已经支持5000个节点,但使用 iptables 的 kube-proxy 实
际上是将集群扩展到5000个节点的瓶颈。 在5000节点集群中使用 NodePort 服务,如
果有2000个服务并且每个服务有10个 pod,这将在每个工作节点上至少产生20000个
iptable 记录,这可能使内核非常繁忙。

ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是我们常说的4层LAN交换,作为
Linux 内核的一部分。ipvs运行在主机上,在真实服务器集群前充当负载均衡器。ipvs
可以将基于TCP和UDP的服务请求转发到真实服务器上,并使真实服务器的服务在单个
IP 地址上显示为虚拟服务。

1、ipvs vs iptables:

我们知道kube-proxy支持 iptables 和 ipvs 两种模式, 在kubernetes v1.8 中引入了 ipvs
模式,在 v1.9 中处于 beta 阶段,在 v1.11 中已经正式可用了。iptables 模式在 v1.1 中
就添加支持了,从 v1.2版本开始 iptables 就是 kube-proxy 默认的操作模式,ipvs 和
iptables 都是基于netfilter的。ipvs 会使用 iptables 进行包过滤、SNAT、masquared。
具体来说,ipvs 将使用ipset来存储需要DROP或masquared的流量的源或目标地址,
以确保 iptables 规则的数量是恒定的,这样我们就不需要关心我们有多少服务了。

启动ipvs的要求:

  • k8s版本 >= v1.11
  • 使用ipvs需要安装相应的工具来处理”yum install ipset ipvsadm -y“
  • 确保 ipvs已经加载内核模块, ip_vs、ip_vs_rr、ip_vs_wrr、ip_vs_sh、
    nf_conntrack_ipv4。如果这些内核模块不加载,当kube-proxy启动后,会退回到iptables模式。

2、ipvs kube-proxy原理分析:

先前基于iptables规则表的DNAT->SNAT方式来处理外部客户端到k8s集群pod内的流量
和集群内部流量(cluster-ip到pod ip),无需在宿主机上管理cluster-ip都由iptables来进行
管理。

使用IPVS后是需要对vs(虚拟服务也就是vip)进行管理,由于IPVS的DNAT钩子挂在
INPUT链上,因此必须要让内核识别 VIP(cluster-ip) 是本机的 IP。k8s 通过设置将
service cluster ip 绑定到虚拟网卡kube-ipvs0,其中下面的10.96.x.x都是VIP,也就
是cluster-ip。如下图:

ipvs-clsterip.png

ipvs 会使用 iptables 进行包过滤、SNAT、masquared(伪装)。具体来说,ipvs 将使用
ipset来存储需要DROP或masquared的流量的源或目标地址,以确保 iptables 规则的
数量是恒定的,这样我们就不需要关心我们有多少服务了。

2.1、cluster-ip到pod访问

这里访问cluster ip为10.96.0.10,k8s集群内部的dns服务

1)、入口流量匹配:
数据包是通过本地协议发出的,在宿主机本地通过访问cluster-ip到后端真是的pod那
么就要伪装所有访问 Service Cluster IP 的外部流量,k8s只能在OUTPUT这个链上
来做相应的规则:
$iptables -S -tnat | grep OUTPUT

ipvs-cls-out.png

匹配到倒数第二条就是将流量引入到KUBE-SERVICES规则中处理。如下图:2)、入口流量引流到全局链KUBE-SERVICES中:
ipset list KUBE-CLUSTER-IP
iptables -S -tnat | grep KUBE-SERVICES

ipvs-cls-out-2.png

第一步中上面的数据包流入到KUBE-SERVICES该规则中目的就是让源地址不是
10.244.0.0/16,目的地址match 到 KUBE-CLUSTER-IP 的数据包打上标签。

3)、入口流量标签化处理:
将上面KUBE-SERVICES链中的流量进行打标签处理:
$iptables -S -tnat | grep KUBE-MARK-MASQ

ipvs-cls-tag.png

4)、入口流量SNAT处理:
那么数据包在出去的时候一定是要经过POSTROUTING链进行SNAT即将所有来源外部
流量转换成该cluster ip的源地址。
$iptables -S -tnat | grep POSTROUTING

ipvs-cls-pro-1.png

然后通过内部的lvs进行流量转发到后端pod上。如下图:
$ipvsadm -Ln

ipvs-cls-out-3.png

2.2、node-ip到pod访问

这里创建一个service为NodePort的nginx应用对应为nodeip:port(192.168.100.100:30080),
clusterip:port(10.101.19.237:80)
$ip ad| grep ipvs

$kubectl get svc

ipvs-node-1.png

1)、入口流量匹配:
集群外部通过node ip 访问到后端pod服务,流量肯定是先在PREROUTING链中处理:
$iptables -S -tnat | grep PREROUTING

ipvs-node-2.png

匹配到倒数第二条就是,将流量引入到KUBE-SERVICES规则中处理。

2)、入口流量引流到全局链KUBE-SERVICES中:
$ipset list KUBE-CLUSTER-IP

$iptables -S -tnat | grep KUBE-SERVICES

ipvs-node-3.jpg

第一步中上面的数据包流入到KUBE-SERVICES该规则中目的就是让源地址不是10.244.0.0/16,目的地址match 到 KUBE-CLUSTER-IP 的数据包打上标签

3)、入口流量标签化处理:
$iptables -S -tnat | grep KUBE-MARK-MASQ

ipvs-node-4.png

4)、入口流量SNAT处理:
那么数据包在出去的时候一定是要经过POSTROUTING链进行SNAT即将所有来源外部流量转换成该cluster ip的源地址。
$iptables -S -tnat | grep POSTROUTING

ipvs-node-5.png

iptables中POSTROUTING链最先将流量引流到KUBE-POSTROUTING中做进一步的SNAT处理
$iptables -S -tnat | grep KUBE-POSTROUTING

ipvs-node-6.png

端口的转换
$iptables -S -tnat | grep KUBE-NODE-PORT

ipvs-node-7.png

上面的流程进行SNAT后即将所有来源外部流量转换成该cluster ip的源地址的对应得端
口。然后通过内部的lvs进行流量转发到后端pod上。


3、总结如下流程:

这种的LB方式和之前分析的swarm集群中LB类似都是用lvs来直接进行负载,这比起原先使用iptables来进行负载在性能上要好的多,同时也比较清晰友好。总之一句话流量都是要先经过iptables清理一遍然后交给4层的lvs进行负载。

lc.png

作者:Feel_狗焕
链接:https://www.jianshu.com/p/89f126b241db
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

发表评论

邮箱地址不会被公开。 必填项已用*标注