K8S集群优化之路由转发:使用IPVS替代iptables

一、IPVS

什么是IPVS?

IPVS (IP Virtual Server,IP虚拟服务器)是基于Netfilter的、作为linux内核的一部分实现传输层负载均衡的技术,通常称为第4层LAN交换。

IPVS集成在LVS(Linux Virtual Server)中,它在主机中运行,并在真实服务器集群前充当负载均衡器。IPVS可以将对TCP/UDP服务的请求转发给后端的真实服务器,并使真实服务器的服务在单个IP地址上显示为虚拟服务。因此IPVS天然支持Kubernetes Service。

为什么选择IPVS?

随着kubernetes使用量的增长,其资源的可扩展性变得越来越重要。特别是对于使用kubernetes运行大型工作负载的开发人员或者公司来说,service的可扩展性至关重要。

kube-proxy是为service构建路由规则的模块,之前依赖iptables来实现主要service类型的支持,比如(ClusterIP和NodePort)。但是iptables很难支持上万级的service,因为iptables纯粹是为防火墙而设计的,并且底层数据结构是内核规则的列表。

kubernetes早在1.6版本就已经有能力支持5000多节点,这样基于iptables的kube-proxy就成为集群扩容到5000节点的瓶颈。举例来说,如果在一个5000节点的集群,我们创建2000个service,并且每个service有10个pod,那么我们就会在每个节点上有至少20000条iptables规则,这会导致内核非常繁忙

基于IPVS的集群内负载均衡就可以完美的解决这个问题。IPVS是专门为负载均衡设计的,并且底层使用哈希表这种非常高效的数据结构,几乎可以允许无限扩容

IPVS vs. Iptables区别

IPVS模式在Kubernetes v1.8中引入,并在v1.9中进入了beta。 1.11中实现了GA(General Availability)。IPTABLES模式在v1.1中添加,并成为自v1.2以来的默认操作模式。 IPVS和IPTABLES都基于netfilter。

IPVS模式和IPTABLES模式之间的差异如下:
  • IPVS为大型集群提供了更好的可扩展性和性能。(规则的存储方式使用的数据结构更高效)
  • IPVS支持比iptables更复杂的负载平衡算法(最小负载,最少连接,位置,加权等)。
  • IPVS支持服务器健康检查和连接重试等。
总结:

IPVS模式与iptables同样基于Netfilter,但是采用的hash表,因此当service数量达到一定规模时,hash查表的速度优势就会显现出来,从而提高service的服务性能。

二、具体步骤

2.1、开启内核参数
cat >> /etc/sysctl.conf << EOF
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

sysctl -p
2.2、开启ipvs支持
在使用IPVS模式之前,还应在节点上安装ipset等软件包。

yum -y install ipvsadm  ipset

# 临时生效
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4

# 永久生效
cat > /etc/sysconfig/modules/ipvs.modules <<EOF
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
2.3、配置kube-proxy
# 添加下面两行
  --proxy-mode=ipvs  \
  --masquerade-all=true \

# 修改服务文件
vim /usr/lib/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
WorkingDirectory=/data/k8s/kube-proxy
ExecStart=/data/k8s/bin/kube-proxy \
  --bind-address=192.168.1.145 \
  --hostname-override=192.168.1.145 \
  --cluster-cidr=10.254.0.0/16 \
  --kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig \
  --logtostderr=true \
  --proxy-mode=ipvs  \
  --masquerade-all=true \
  --v=2
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
2.4、重启kube-proxy
systemctl daemon-reload
systemctl restart kube-proxy
systemctl status kube-proxy

三、测试

测试是否生效

[root@k8sNode01 docker]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.254.0.1:443 rr
  -> 192.168.1.142:6443           Masq    1      0          0         
  -> 192.168.1.143:6443           Masq    1      1          0         
  -> 192.168.1.144:6443           Masq    1      1          0         
TCP  10.254.27.38:80 rr
  -> 172.30.36.4:9090             Masq    1      0          0         
TCP  10.254.72.60:80 rr
  -> 172.30.90.4:8080             Masq    1      0          0         
TCP  10.254.72.247:80 rr
  -> 172.30.36.5:3000             Masq    1      0          0         
TCP  127.0.0.1:27841 rr
  -> 172.30.36.2:80               Masq    1      0          0         
  -> 172.30.90.2:80               Masq    1      0          0         
TCP  127.0.0.1:28453 rr
  -> 172.30.36.5:3000             Masq    1      0          0         
TCP  127.0.0.1:36018 rr
  -> 172.30.36.4:9090             Masq    1      0          0         
TCP  172.30.90.0:27841 rr
  -> 172.30.36.2:80               Masq    1      0          0         
  -> 172.30.90.2:80               Masq    1      0          0