k8s集群网络(4)-service之iptable cluster ip实现原理

上一篇文章中我们结合实际例子来查看了docker宿主环境中的容器网络,在这里我们主要介绍集群内的负载均衡。对于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集群网络中node port的实现方式。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值