k8s-service中iptable cluster ip实现原理
本篇文章为大家展示了k8s-service中iptable cluster ip实现原理,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
在这里我们主要介绍集群内的负载均衡。对于k8s集群中的服务是需要相互访问的,一般我们都会为之创建相应的service,对于集群内部的service类型我们一般设置成cluster ip。对于一个cluster ip后面会关联多个endpoints,也就是实际的pod。对于cluster ip的访问,也就是实现了对cluster ip关联的多个endpoints访问。关于cluster ip和endpoints的流量负载均衡,一般有iptable方式和ipvs方式,在以前文章里有所介绍。这里我们主要以实际例子来介绍iptable的实现方式。另外cluster ip是虚拟ip,言外之意就是这个ip没有和任何device绑定,所以当你对这个ip进行例如ping或者traceroute命令的时候是不会得到应答的。
查看部署的nginx application的service,我们可以看到:
这个service为cluster ip类型
cluster ip为10.254.226.173
这个cluster ip关联了2个endpoints:10.1.27.4:80和10.1.79.3:80
kubectl describe service service-nginx-app -n default
查看host network namespace iptable的nat表:
iptables -nvL -t nat
对于PREROUTING chain中,所有的流量都走到了KUBE-SERVICES这个target中。请注意PREROUTING chain是流量到达之后的第一个入口。试想我们在pod里运行命令curl http://10.254.226.173,根据以前文章里介绍的容器内部路由表,数据包应该是这样的流动:
在pod中,根据路由表发现cluster ip(10.254.226)走默认路由,选择了默认网关。
在pod中,默认网关的ip地址就是宿主netwok namespace的docker0的ip地址,并且默认网关为直连路由。
在pod中,根据路由表,使用eth0 device发送数据,根据以前文章,eth0本质是veth pair在pod network namespace的一端,另一端attach在宿主netwok namespace的docker0 bridge上。
根据以前文章介绍的veth pair,数据从pod network namespace的一端发出,进入到了attached到docker0 bridge上的另一端。
docker0 bridge收到数据之后,自然就来到了host network namesapce的PREROUTING chain。
查看KUBE-SERVICES target:
iptables -nvL -t nat | grep KUBE-SVC
在KUBE-SERVICES target中我们可以看到目标地址为cluster ip10.254.226.173的匹配target为KUBE-SVC-ETZVW7ENORYJBYB4。
查看KUBE-SVC-ETZVW7ENORYJBYB4 target:
iptables -nvL -t nat
在KUBE-SVC-ETZVW7ENORYJBYB4 target中我们可以看到:
有2个target,分别是KUBE-SEP-L6A5J2X5SCQGCA7Z和KUBE-SEP-U7JQ3R4SRIDMQ4UH
在KUBE-SEP-L6A5J2X5SCQGCA7Z中有statistic mode random probability 0.5
对于statistic mode random probability 0.5是利用了iptable内核随机模块,随机比率为0.5,也就是50%。
所以对于上面的意思是有一半的随机比率进入到KUBE-SEP-L6A5J2X5SCQGCA7Z target当中,那么自然另一个target的随机比率也是一半了。
由此可见,是通过随机模块来均匀的实现负载均衡的。
查看KUBE-SEP-L6A5J2X5SCQGCA7Z和UBE-SEP-L6A5J2X5SCQGCA7Z target:
iptables -nvL -t nat
在这2个target中我们可以看到:
分别做了MASQ操作,当然这个应该是出站engress流量(限定了source ip),不是我们的入站ingress流量。
做了DNAT操作,把原来的cluster ip给DANT转换成了pod的ip 10.1.27.4和10.1.79.3。把原来的port转换成了80 port
经过这个一系列iptable的target我们的原始请求10.254.226.173:80就变成了10.1.27.4:80或者10.1.79.3:80,而且两者转变的机率各是50%。
根据iptable,经过PREROUTING chain发现DNAT之后的10.1.27.4或者10.1.79.3不是本地的ip(肯定不是,因为这两个ip是pod的ip,当然不会在host的network namespace里)。所以就走到了Forwarding chain中,根据host network namespace的路由表来决定下一跳地址。
所以综合上面的例子,对于ipable方式的k8s集群内cluster-ip类型的service总结为:
流量从pod network namespace中走到host netwok namespace的docker0中。
在host netwok namespace的PREROUTING chain中会经过一系列target。
在这些target里根据iptable内核随机模块来实现匹配endpoint target,随机比率为均匀分配,实现均匀的负载均衡。
在endpoint target里实现了DNAT,也就是将目标地址cluster ip转化为实际的pod的ip。
cluster ip是虚拟ip,不会和任何device绑定。
负载均衡为内核实现,使用均匀负载均衡,不可以有自定义的负载均衡算法。
需要host开启路由转发功能(net.ipv4.ip_forward = 1)。
数据包在host netwok namespace中经过转换以及DNAT之后,由host network namespace的路由表来决定下一跳地址。
上述内容就是k8s-service中iptable cluster ip实现原理,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注行业资讯频道。