k8s 中的 service 如何找到绑定的 Pod 以及如何实现 Pod 负载均衡( 三 )


可以看到该模式下 iptables 来做用户态的入口,kube-proxy 只是持续监听 Service 以及 Endpoints 对象的变化,iptables 通过设置的转发策略,直接将对 VIP 的请求转发给后端 Pod,iptables 使用 DNAT 来完成转发,其采用了随机数实现负载均衡 。
如果 kube-proxy 在 iptables 模式下运行,并且所选的第一个 Pod 没有响应,则连接失败 。这与用户空间模式不同:在这种情况下,kube-proxy 将检测到与第一个 Pod 的连接已失败,并会自动使用其他后端 Pod 重试 。
该模式相比 userspace 模式,克服了请求在用户态-内核态反复传递的问题,性能上有所提升,但使用 iptables NAT 来完成转发,存在不可忽视的性能损耗,iptables 模式最主要的问题是在 service 数量大的时候会产生太多的 iptables 规则,使用非增量式更新会引入一定的时延,大规模情况下有明显的性能问题 。
ipvs当集群的规模比较大时,iptables 规则刷新就会很慢,难以支撑大规模的集群 。因为 iptables 的底层实现是链表,对路由规则的增删查改都需要遍历一次链表 。
在 kubernetes v1.2 之后 ipvs 成为kube-proxy的默认代理模式 。ipvs 正是解决这一问题的,ipvs 是 LVS 的负载均衡模块,与 iptables 比较像的是,ipvs 的实现虽然也基于 netfilter 的钩子函数,但是它却使用哈希表作为底层的数据结构并且工作在内核态,也就是说 ipvs 在重定向流量和同步代理规则有着更好的性能,几乎允许无限的规模扩张 。

k8s 中的 service 如何找到绑定的 Pod 以及如何实现 Pod 负载均衡

文章插图
ipvs 支持三种负载均衡模式:
1、DR模式(Direct Routing);
2、NAT 模式(Network Address Translation);
3、Tunneling(也称 ipip 模式) 。
三种模式中只有 NAT 支持端口映射,所以 ipvs 使用 NAT 模式 。linux 内核原生的 ipvs 只支持 DNAT,当在数据包过滤,SNAT 和支持 NodePort 类型的服务这几个场景中ipvs 还是会使用 iptables 。
ipvs 也支持更多的负载均衡算法:
  • rr:round-robin/轮询;
  • lc:least connection/最少连接;
  • dh:destination hashing/目标哈希;
  • sh:source hashing/源哈希;
  • sed:shortest expected delay/预计延迟时间最短;
  • nq:never queue/从不排队
kernelspacekernelspace 模式是 windows 上的代理模式,这里不展开讨论了
服务发现service 的 endpoints 解决了容器发现问题,但是不提前知道 service 的 Cluster IP,就无法知道 service 服务了 。Kubernetes 支持两种基本的服务发现模式 —— 环境变量和 DNS 。
环境变量当一个 pod 创建完成之后,kubelet 会在该 pod 中注册该集群已经创建的所有 service 相关的环境变量,但是需要注意的是,在 service 创建之前的所有 pod 是不会注册该环境变量的,所以在平时使用时,建议通过 DNS 的方式进行 service 之间的服务发现 。
举个例子,一个名称为 redis-primary 的 Service 暴露了 TCP 端口 6379,同时给它分配了 Cluster IP 地址 10.0.0.11,这个 Service 生成了如下环境变量:
REDIS_PRIMARY_SERVICE_HOST=10.0.0.11REDIS_PRIMARY_SERVICE_PORT=6379REDIS_PRIMARY_PORT=tcp://10.0.0.11:6379REDIS_PRIMARY_PORT_6379_TCP=tcp://10.0.0.11:6379REDIS_PRIMARY_PORT_6379_TCP_PROTO=tcpREDIS_PRIMARY_PORT_6379_TCP_PORT=6379REDIS_PRIMARY_PORT_6379_TCP_ADDR=10.0.0.11DNS可以在集群中部署 CoreDNS 服务(旧版本的 kubernetes 群使用的是 kubeDNS),来达到集群内部的 pod 通过DNS 的方式进行集群内部各个服务之间的通讯 。
当前 kubernetes 集群默认使用 CoreDNS 作为默认的 DNS 服务,主要原因是 CoreDNS 是基于 Plugin 的方式进行扩展的,简单,灵活,并且不完全被Kubernetes所捆绑 。

经验总结扩展阅读