
如何在 kubernetes 中开启 ipvs 模式
作者 阳明
来源 | k8s技术圈(ID:kube100)
ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是我们常说的4层 LAN交换,作为 Linux 内核的一部分。 ipvs运行在主机上,在真实服务器集群前充当负载均衡器。 ipvs可以将基于 TCP和 UDP的服务请求转发到真实服务器上,并使真实服务器的服务在单个 IP 地址上显示为虚拟服务。
ipvs vs. iptables
我们知道 kube-proxy支持 iptables 和 ipvs 两种模式, 在 kubernetes v1.8 中引入了 ipvs 模式,在 v1.9 中处于 beta 阶段,在 v1.11 中已经正式可用了。iptables 模式在 v1.1 中就添加支持了,从 v1.2 版本开始 iptables 就是 kube-proxy 默认的操作模式,ipvs 和 iptables 都是基于 netfilter的,那么 ipvs 模式和 iptables 模式之间有哪些差异呢?
- ipvs 为大型集群提供了更好的可扩展性和性能
- ipvs 支持比 iptables 更复杂的复制均衡算法(最小负载、最少连接、加权等等)
- ipvs 支持服务器健康检查和连接重试等功能
ipvs 依赖 iptables
ipvs 会使用 iptables 进行包过滤、SNAT、masquared(伪装)。具体来说,ipvs 将使用 ipset来存储需要 DROP或 masquared的流量的源或目标地址,以确保 iptables 规则的数量是恒定的,这样我们就不需要关心我们有多少服务了
下表就是 ipvs 使用的 ipset 集合:
在以下情况下,ipvs 将依赖于 iptables:
1. kube-proxy 配置参数 --masquerade-all=true
如果 kube-proxy 配置了 --masquerade-all=true参数,则 ipvs 将伪装所有访问 Service 的 Cluster IP 的流量,此时的行为和 iptables 是一致的,由 ipvs 添加的 iptables 规则如下:
2. 在 kube-proxy 启动时指定集群 CIDR
如果 kube-proxy 配置了 --cluster-cidr=<cidr>参数,则 ipvs 会伪装所有访问 Service Cluster IP 的外部流量,其行为和 iptables 相同,假设 kube-proxy 提供的集群 CIDR 值为:10.244.16.0/24,那么 ipvs 添加的 iptables 规则应该如下所示:
3. Load Balancer 类型的 Service
对于 loadBalancer类型的服务,ipvs 将安装匹配 KUBE-LOAD-BALANCER 的 ipset 的 iptables 规则。特别当服务的 LoadBalancerSourceRanges 被指定或指定 externalTrafficPolicy=local 的时候,ipvs 将创建 ipset 集合 KUBE-LOAD-BALANCER-LOCAL/ KUBE-LOAD-BALANCER-FW/ KUBE-LOAD-BALANCER-SOURCE-CIDR,并添加相应的 iptables 规则,如下所示规则:
4. NodePort 类型的 Service
对于 NodePort 类型的服务,ipvs 将添加匹配 KUBE-NODE-PORT-TCP/KUBE-NODE-PORT-UDP的 ipset 的iptables 规则。当指定 externalTrafficPolicy=local时,ipvs 将创建 ipset 集 KUBE-NODE-PORT-LOCAL-TC/KUBE-NODE-PORT-LOCAL-UDP并安装相应的 iptables 规则,如下所示:(假设服务使用 TCP 类型 nodePort)
C
5. 指定 externalIPs 的 Service
对于指定了 externalIPs的 Service,ipvs 会安装匹配 KUBE-EXTERNAL-IP ipset 集的 iptables 规则,假设我们有指定了 externalIPs 的 Service,则 iptables 规则应该如下所示:
kube-proxy 使用 ipvs 模式
目前,本地化脚本、GCE 脚本和 kubeadm支持通过导入环境变量或者指定标志来切换 ipvs 代理模式
要求
确保 ipvs 需要的内核模块,需要下面几个模块:ipvs、ipvsrr、ipvswrr、ipvssh、nfconntrack_ipv4
已编译到节点内核中的,可以使用如下命令检查:
已经加载。
在使用 ipvs 模式之前,还应在节点上安装 ipset相关的软件包,如果不满足需求 kube-proxy 会回退到 iptables 的模式。
本地集群
在本地集群中 kube-proxy 默认会运行 iptables 的模式。 要使用 ipvs 模式,在启动集群之前需要导入 KUBE_PROXY_MODE=ipvs的环境变量:
GCE 集群
和本地集群一样,GCE 集群中的 kube-proxy 默认也是 iptables 模式,在启动集群之前同样需要导入环境变量 KUBE_PROXY_MODE=ipvs:
使用 kubeadm 搭建的集群
通过kubeadm部署的集群中 kube-proxy 同样默认是 iptables 模式。
如果你是通过配置文件来使用的 kubeadm,则可以在 kubeProxy属性下面添加 SupportIPVSProxyMode:true来启用 ipvs 模式:
k
然后执行初始化命令即可:
如果你使用的是 v1.8 版本的 kubernetes,你也可以在 kubeadm init命令中增加 --feature-gates=SupportIPVSProxyMode=true标志来来启用 ipvs 模式:
注意该参数在 v1.9 后已经弃用掉了
注意
如果成功启用了 ipvs 模式,你应该可以使用 ipvsadm之类的工具看到如下的一些 ipvs 代理规则:
或者在 kube-proxy 日志中可以看到如下的一些日志信息:
当没有这些 ipvs 代理规则或者出现了下面的这些日志信息的时候表明 kube-proxy 的 ipvs 模式启用失败了:
可以参考下面的调试方法进行错误信息排查
调试
检查 ipvs 代理规则
用户可以使用 ipvsadm工具检查 kube-proxy 是否维护正确的 ipvs 规则,比如,我们在集群中有以下一些服务:
我们可以得到如下的一些 ipvs 代理规则:
为什么 kube-proxy 无法启动 ipvs模式
可以使用下面的一些方法来帮助我们解决这些问题:
1. 启用 ipvs feature gate
对于 kubernetes v1.10 版本之后,feature gate SupportIPVSProxyMode已经被默认设置为 true了,但是如果你是 v1.10 之前的版本,你需要手动设置 --feature-gates=SupportIPVSProxyMode=true来启用该 feature。
2. 指定 proxy-mode=ipvs
检查 kube-proxy 的 model 是否被设置为了 ipvs。
3. 安装需要的内核模块和软件包
检查 ipvs 需要的内核模块是否已经被编译进内核模块中,以及需要的软件包(可以参考前面的环境要求部分)
