在每个Node上都会运行一个kube-proxy服务进程,这个进程可以看做service的透明代理和负载均衡器。其核心功能是将某个service的访问请求转发到后端的某个Pod上。对每一个TCP类型的service,kube-proxy都会在本地Node上建立一个socketserver来负责接收请求,然后均匀发送到后端某个Pod端口上。这个过程默认采用Round Robin负载均衡算法。

此外,service的cluster IP和Nodeport概念是proxy通过Iptables的NAT转换实现的。proxy在运行过程中动态创建于service相关的Iptables规则,这些规则实现了Cluster IP及NodePort的请求流量重定向到proxy进程上对应服务的代理端口的功能。

也就是说,访问service的请求,都会被节点机的Iptables规则重定向到kube-proxy监听service服务代理端口,那么proxy如何选择后端的pod呢?

目前proxy只支持round robin算法,该算法是轮询查询。

接下来深入分析proxy实现细节:

kube-proxy通过查询和监听API server中service和endpoint的变化。为每个service都建立了一个服务代理对象。并自动同步。服务代理对象是proxy程序内部的一种数据结构,它包括一个用于监听此服务请求的socketserver,socketserver的端口是随机选择的一个本地空闲端口。此外,kube-proxy内部也创建了一个负载均衡器-LoadBalancer,LoadBalancer上保存了service到对应的后端endpoint列表的动态转发路由表。而具体的路由选择则取决于Round Robin负载均衡算法及service的session会话保持这两个特性。

针对发生变化的service列表,proxy会逐个处理,下面是具体处理流程:

1.如果该service没有设置Cluster IP,则不做任何处理,否则获取该service的所有端口定义列表(spec.ports域)

2.逐个读取服务端口定义列表中的端口信息,根据端口名称,service名称和namespace判断本地是否已经存在对应的服务代理对象,如果不存在则新建,若存在并且service端口被修改过,则先删除Iptables中和该service端口相关的规则,关闭服务代理对象,然后走新建流程,也就是为该service端口分配服务代理对象并为创建相关的Iptables规则。

3.更新负载均衡器组件中对应service的转发地址列表,对于新建的service,确定转发时的会话保持策略。

4.对于已删除的service则进行清理。

proxy在启动时和坚挺到service或endpoint变化后,会在本机的Iptables的NAT表中添加4条规则链。

a,KUBE-PORTALS-CONTAINER:从容器中通过service Cluster IP和端口号访问service的请求。

b,KUBE-PORTALS-HOST:从主机通过service Cluster IP和端口号访问service的请求。

c,KUBE-NODEPORT-CONTAINER:从容器中通过service的NodePort端口号访问service的请求。

d,KUBE-NODEPORT-HOST:从主机通过service的NodePort端口号访问service的请求。

此外,kube-proxy在Iptables上为每个service创建由Cluster IP+service端口到kube-proxy所在主机IP+service代理服务所监听的端口的转发规则。


可以看到对“redis-master”service的6379端口的访问将被转发至物理机的42872端口。而42872端口就是proxy为这个service打开的随机本地端口。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐