什么是 IPVS ?nginx
IPVS (IP Virtual Server)是在 Netfilter 上层构建的,并做为 Linux 内核的一部分,实现传输层负载均衡。算法
IPVS 集成在 LVS(Linux Virtual Server,Linux 虚拟服务器)中,它在主机上运行,并在物理服务器集群前做为负载均衡器。IPVS 能够将基于 TCP 和 UDP 服务的请求定向到真实服务器,并使真实服务器的服务在单个IP地址上显示为虚拟服务。 所以,IPVS 天然支持 Kubernetes 服务。服务器
为何为 Kubernetes 选择 IPVS ?网络
随着 Kubernetes 的使用增加,其资源的可扩展性变得愈来愈重要。特别是,服务的可扩展性对于运行大型工做负载的开发人员/公司采用 Kubernetes 相当重要。数据结构
Kube-proxy 是服务路由的构建块,它依赖于通过强化攻击的 iptables 来实现支持核心的服务类型,如 ClusterIP 和 NodePort。 可是,iptables 难以扩展到成千上万的服务,由于它纯粹是为防火墙而设计的,而且基于内核规则列表。负载均衡
尽管 Kubernetes 在版本v1.6中已经支持5000个节点,但使用 iptables 的 kube-proxy 其实是将集群扩展到5000个节点的瓶颈。 一个例子是,在5000节点集群中使用 NodePort 服务,若是咱们有2000个服务而且每一个服务有10个 pod,这将在每一个工做节点上至少产生20000个 iptable 记录,这可能使内核很是繁忙。oop
另外一方面,使用基于 IPVS 的集群内服务负载均衡能够为这种状况提供不少帮助。 IPVS 专门用于负载均衡,并使用更高效的数据结构(哈希表),容许几乎无限的规模扩张。spa
基于 IPVS 的 Kube-proxy设计
参数更改代理
参数: –proxy-mode 除了现有的用户空间和 iptables 模式,IPVS 模式经过–proxy-mode = ipvs 进行配置。 它隐式使用 IPVS NAT 模式进行服务端口映射。
参数: –ipvs-scheduler
添加了一个新的 kube-proxy 参数来指定 IPVS 负载均衡算法,参数为 –ipvs-scheduler。 若是未配置,则默认为 round-robin 算法(rr)。
未来,咱们能够实现特定于服务的调度程序(可能经过注释),该调度程序具备更高的优先级并覆盖该值。
参数: –cleanup-ipvs 相似于 –cleanup-iptables 参数,若是为 true,则清除在 IPVS 模式下建立的 IPVS 配置和 IPTables 规则。
参数: –ipvs-sync-period 刷新 IPVS 规则的最大间隔时间(例如’5s’,’1m’)。 必须大于0。
参数: –ipvs-min-sync-period 刷新 IPVS 规则的最小间隔时间间隔(例如’5s’,’1m’)。 必须大于0。
参数: –ipvs-exclude-cidrs 清除 IPVS 规则时 IPVS 代理不该触及的 CIDR 的逗号分隔列表,由于 IPVS 代理没法区分 kube-proxy 建立的 IPVS 规则和用户原始规则 IPVS 规则。 若是您在环境中使用 IPVS proxier 和您本身的 IPVS 规则,则应指定此参数,不然将清除原始规则。
设计注意事项
IPVS 服务网络拓扑
建立 ClusterIP 类型服务时,IPVS proxier 将执行如下三项操做:
这是一个例子:
# kubectl describe svc nginx-service Name: nginx-service ... Type: ClusterIP IP: 10.102.128.4 Port: http 3080/TCP Endpoints: 10.244.0.235:8080,10.244.1.237:8080 Session Affinity: None # ip addr ... 73: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN qlen 1000 link/ether 1a:ce:f5:5f:c1:4d brd ff:ff:ff:ff:ff:ff inet 10.102.128.4/32 scope global kube-ipvs0 valid_lft forever preferred_lft forever # ipvsadm -ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 10.102.128.4:3080 rr -> 10.244.0.235:8080 Masq 1 0 0 -> 10.244.1.237:8080 Masq 1 0 0
请注意,Kubernetes 服务和 IPVS 虚拟服务器之间的关系是“1:N”。 例如,考虑具备多个 IP 地址的 Kubernetes 服务。 外部 IP 类型服务有两个 IP 地址 - 集群IP和外部 IP。 而后,IPVS 代理将建立2个 IPVS 虚拟服务器 - 一个用于集群 IP,另外一个用于外部 IP。 Kubernetes 的 endpoint(每一个IP +端口对)与 IPVS 虚拟服务器之间的关系是“1:1”。
删除 Kubernetes 服务将触发删除相应的 IPVS 虚拟服务器,IPVS 物理服务器及其绑定到虚拟接口的 IP 地址。
端口映射
IPVS 中有三种代理模式:NAT(masq),IPIP 和 DR。 只有 NAT 模式支持端口映射。 Kube-proxy 利用 NAT 模式进行端口映射。 如下示例显示 IPVS 服务端口3080到Pod端口8080的映射。
TCP 10.102.128.4:3080 rr -> 10.244.0.235:8080 Masq 1 0 0 -> 10.244.1.237:8080 Masq 1 0
会话关系
IPVS 支持客户端 IP 会话关联(持久链接)。 当服务指定会话关系时,IPVS 代理将在 IPVS 虚拟服务器中设置超时值(默认为180分钟= 10800秒)。 例如:
# kubectl describe svc nginx-service Name: nginx-service ... IP: 10.102.128.4 Port: http 3080/TCP Session Affinity: ClientIP # ipvsadm -ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 10.102.128.4:3080 rr persistent 10800
IPVS 代理中的 Iptables 和 Ipset
IPVS 用于负载均衡,它没法处理 kube-proxy 中的其余问题,例如 包过滤,数据包欺骗,SNAT 等
IPVS proxier 在上述场景中利用 iptables。 具体来讲,ipvs proxier 将在如下4种状况下依赖于 iptables:
可是,咱们不想建立太多的 iptables 规则。 因此咱们采用 ipset 来减小 iptables 规则。 如下是 IPVS proxier 维护的 ipset 集表:
设置名称 成员 用法
KUBE-CLUSTER-IP 全部服务 IP + 端口 masquerade-all=true 或 clusterCIDR 指定的状况下进行假装 KUBE-LOOP-BACK 全部服务 IP +端口+ IP 解决数据包欺骗问题
KUBE-EXTERNAL-IP 服务外部 IP +端口 将数据包假装成外部 IP
KUBE-LOAD-BALANCER 负载均衡器入口 IP +端口 将数据包假装成 Load Balancer 类型的服务
KUBE-LOAD-BALANCER-LOCAL 负载均衡器入口 IP +端口 以及 externalTrafficPolicy=local 接受数据包到 Load Balancer externalTrafficPolicy=local KUBE-LOAD-BALANCER-FW 负载均衡器入口 IP +端口 以及 loadBalancerSourceRanges 使用指定的 loadBalancerSourceRanges 丢弃 Load Balancer类型Service的数据包 KUBE-LOAD-BALANCER-SOURCE-CIDR 负载均衡器入口 IP +端口 + 源 CIDR 接受 Load Balancer 类型 Service 的数据包,并指定loadBalancerSourceRanges KUBE-NODE-PORT-TCP NodePort 类型服务 TCP 将数据包假装成 NodePort(TCP)
KUBE-NODE-PORT-LOCAL-TCP NodePort 类型服务 TCP 端口,带有 externalTrafficPolicy=local 接受数据包到 NodePort 服务 使用 externalTrafficPolicy=local KUBE-NODE-PORT-UDP NodePort 类型服务 UDP 端口 将数据包假装成 NodePort(UDP)
KUBE-NODE-PORT-LOCAL-UDP NodePort 类型服务 UDP 端口 使用 externalTrafficPolicy=local 接受数据包到NodePort服务 使用 externalTrafficPolicy=local
一般,对于 IPVS proxier,不管咱们有多少 Service/ Pod,iptables 规则的数量都是静态的。
在 IPVS 模式下运行 kube-proxy
目前,本地脚本,GCE 脚本和 kubeadm 支持经过导出环境变量(KUBE_PROXY_MODE=ipvs)或指定标志(–proxy-mode=ipvs)来切换 IPVS 代理模式。 在运行IPVS 代理以前,请确保已安装 IPVS 所需的内核模块。
ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh nf_conntrack_ipv4
最后,对于 Kubernetes v1.10,“SupportIPVSProxyMode” 默认设置为 “true”。 对于 Kubernetes v1.11 ,该选项已彻底删除。 可是,您须要在v1.10以前为Kubernetes 明确启用 –feature-gates = SupportIPVSProxyMode = true。