kube-proxy运行机制分析
一、概念
Kubernetes 在创建服务时会为服务分配一个虚拟的IP地址,客户端通过访问这个虚拟的 IP地址来访问服务,而服务则负责将请求转发到后端的 Pod 上。这就是 个反向代理。但是,它和普通的反向代理有一些不同:首先它的IP地址是虚拟的,想从外面访问还需要一些技巧;其次是它的部署和启停是 Kubernetes 统一自动管理的。
真正将 Service 的作用落实的是背后的 kube-proxy 服务进程。
Kubernetes 集群的每个 Node 上都会运行一个 kube-proxy 服务进程,这个进程可以看作Service 的透明代理兼负载均衡器,其核心功能是将到某个 Service 的访问请求转发到后端的Pod 实例上。对每一个 TCP 类型的 Kubernetes Service, kube-proxy 都会在本地 Node 上建一个 SocketServer 来负责接收请求,然后均匀发送到后端某个 Pod 的端口上,这个过程默认采Round Robin 负载均衡算法。另外 Kubernetes 也提供通过修改 Service 的 service.spec.sessionAffinity 参数的值来实现会话保持特性的定向转发,如果设置的值为ClientIP ,则将来自同 ClientIP 的请求都转发到同 个后端 Pod 上。
此外, Service的Cluster IP的NodePort 等概念是 kube-proxy 服务通过 Iptables NAT 转换实现的, kube-proxy 在运行过程中动态创建与 Service 相关的 Iptables 规则,这些规则实现了Cluster IP 到NodePort 请求流量重定向到 kube-proxy 进程上对应服务的代理端口的功能。由Iptables 机制针对的是本地的 kube-proxy 端口,所以每个 Node 上都要运行 kube-proxy 组件,这样一来,在 Kubernetes 集群内部,我们可以在任意 Node 上发起对 Service 的访问请求。
由于 kube-proxy 的作用,在 Service 的调用过程中客户端无须关心后端有几个Pod ,中间过程的通信、负载均衡及故障恢复都是透明的
访问 Service 的请求,不论是用 Cluster IP + TargetPort 的方式,还是用节点机 IP+ NodePort 的方式,都被节点机的 iptables 规则重定向到 kube-proxy 监听 Service 服务代理端口。
kube-proxy 的负载均衡器只支持 Round Robin 算法
Round Robin 算法按照成员列表逐个选取成员,如果一轮循环完,便从头开始下一轮,如此循环往复。 kube-proxy 的负载均衡器在 Round Robin 基础上还支持 Session 保持。如果 Service 在定义中指定了 Session保持, kube-proxy 接收请求后从本地内存中查找是否存在来自该请求 IP affmityState对象,如果存在该对象,且 Session 有超时,则 kube-proxy 将请求转向该 affinityState 指向的后端 Pod ,如果本地存在没有来自该请求 affinityState 对象,则按照 Round Robin 算法为该请求挑选一个 Endpoint ,并创建 affmityState 对象,记录请求的 IP 指向的 ndpoint 后面的请求就会“粘连”到这个创建好的 affmityState 对象上,这就实现了客户端 IP 会话保持的功能。
二、kube-proxy实现细节
kube-proxy 通过查询和监听API Server中 Service的Endpoints 变化,为每个 Service 都建立了 个“服务代理对象”,井自动同步。服务代理对象是 kube-proxy 程序内部的一种数据结构,它包括一个用于监听此服务请求的 SocketServer, SocketServer 端口是随机选择的一个本地空闲端口。此外, kube-proxy 内部也创建了一个负载均衡器一一LoadBalancer, LoadBalancer 上保存了 Service 到对应的后端 Endpoint 的动态转发路由 ,而具体的路由选择则取决于 Round Robin 负载均衡算法及 Service的Session 会话保持( SessionAffinity )这两个特性。
针对发生变化的 Service 表, kube-proxy 会逐个处理
- 如果该 Service 没有设置集群 IP
ClusterIP,则不做任何处理,否则,获取该 Service的所有端口定义列表(spec.ports域)。 - 逐个读取服务端口定义列表中的端口信息 ,根据端口名称、 Service 名称和
Namespace判断本地是否已经存在对应的服务代理对象,如果不存在则新建:如果存在并且 Service 端口被修改过,则先删除iptables中和Service端口相关的规则, 关闭服务代理对象,然后走新建流程,即为该 Service 口分配服务代理对象并为该 Service 建相关的iptables规则 - 更新负载均衡器组件中对应 Service 转发地址列表, 对于新建 Service 确定转发时的会话保持策略。
- 对于己经删除Service 进行清理。
针对 Endpoint的变化 kube-proxy 会自动更新负载均衡 中对 Service 转发地址列表。
kube-proxy 针对 iptable 操作
kube-proxy 在启动时和监听到 Service的Endpoint 会在本 iptables的NAT中添加4条规则链
KUB-PORTALS-CONTAINER::从容器中通过Service Cluster IP端口号访 Service的请求。KUBE-PORTALS-HOST:从主机中 Service Cluster IP和端口号访 Service 的请求KUB-NODEPORT-CONTAINER:从容器中通过Service NodePort端口号访 Service的请求KUBE-NODEPORT-HOST:从主机中通 过Service NodePort端口口号访 Service 的请求。kube -proxy在Iptables中为 Service 创建Cluster IP + Service 端口到 kube-proxy所在主机 IP + Service 代理服务所监听的端口的转发规则 。转发规则的包匹配规则部分CRETIRIA :
1 | -m comment --comment $SERVICESTRING - p $PROTOCOL -m $PROTOCOL --dport $DESTPORT -d $DESTIP |
对于转发规则的跳转部分(-j),如果请求来自本地容器,且 Service 务监昕的是所有的接口(例如 IPv4 的地址为 0.0.0.0)
1 | -j REDIRECT --to-ports $proxyPort |
如果 Service 类型为 NodePort ,则 kube-proxy在iptables 中除了添加上面提及的规则,还会为每个 Service 创建由 NodePort 端口到 kube-proxy 所在主机 IP+ Service 代理服务所监昕的端口的转发规则。
1 | -m comment --comment SERVICESTRING -p $PROTOCOL -m PROTOCOL --dport $NODEPORT |
1 | #查看路由与规则 |





