背景介绍
从k8s的1.8版本开始,kube-proxy引入了IPVS模式,IPVS模式与iptables同样基于Netfilter,但是ipvs采用的hash表,iptables采用一条条的规则列表。iptables又是为了防火墙设计的,集群数量越多iptables规则就越多,而iptables规则是从上到下匹配,所以效率就越是低下。因此当service数量达到一定规模时,hash查表的速度优势就会显现出来,从而提高service的服务性能
每个节点的kube-proxy负责监听API server中service和endpoint的变化情况。将变化信息写入本地userspace、iptables、ipvs来实现service负载均衡,使用NAT将vip流量转至endpoint中。由于userspace模式因为可靠性和性能(频繁切换内核/用户空间)早已经淘汰,所有的客户端请求svc,先经过iptables,然后再经过kube-proxy到pod,所以性能很差。
ipvs和iptables都是基于netfilter的,两者差别如下:
ipvs 为大型集群提供了更好的可扩展性和性能
ipvs 支持比 iptables 更复杂的负载均衡算法(最小负载、最少连接、加权等等)
ipvs 支持服务器健康检查和连接重试等功能
一、Iptables模式
在这种模式下,kube-proxy监视API Server中service和endpoint的变化情况。对于每个service,它都生成相应的iptables规则,这些规则捕获到service的clusterIP和port的流量,并将这些流量随机重定向到service后端Pod。对于每个endpoint对象,它生成选择后端Pod的iptables规则。
如果选择的第一个Pod没有响应,kube-proxy将检测到到第一个Pod的连接失败,并将自动重试另一个后端Pod。
缺点:
iptables 因为它纯粹是为防火墙而设计的,并且基于内核规则列表,集群数量越多性能越差。
一个例子是,在5000节点集群中使用 NodePort 服务,如果我们有2000个服务并且每个服务有10个 pod,这将在每个工作节点上至少产生20000个 iptable 记录,这可能使内核非常繁忙。
二、IPVS模式(NAT模式)
在这种模式下,kube-proxy监听API Server中service和endpoint的变化情况,调用netlink接口创建相应的ipvs规则,并定期将ipvs规则与Kubernetes服 Services和Endpoints同步。保证IPVS状态。当访问Services时,IPVS将流量定向到后端pod之一。
IPVS代理模式基于netfilter hook函数,该函数类似于iptables模式,但使用hash表作为底层数据结构,在内核空间中工作。这意味着IPVS模式下的kube-proxy使用更低的重定向流量。其同步规则的效率和网络吞吐量也更高。
ipvs依赖iptables进行包过滤、SNAT、masquared(伪装)。 使用 ipset 来存储需要 DROP 或 masquared 的流量的源或目标地址,以确保 iptables 规则的数量是恒定的,这样我们就不需要关心我们有多少服务了
如果没有加载并启用ipvs模块,或者没有配置ipvs相关配置,则会被降级成iptables模式。
三、内部原理理解
Iptables
以k8s中的nginx这个service举例,这是一个nodePort类型的service
用命令
iptables-save |grep nginx
可以看到这个service中的iptables规则
找到他对外暴露的端口30601
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx" -m tcp --dport 30601 -j KUBE-SVC-2CMXP7HKUVJN7L6M
找到他CLUSTER-IP的这一条规则,即139的规则
-A KUBE-SERVICES -d 10.102.19.139/32 -p tcp -m comment --comment "default/nginx cluster IP" -m tcp --dport 80 -j KUBE-SVC-2CMXP7HKUVJN7L6M
由这条规则看出,如果访问的是10.102.19.139
的80端口。则会将访问转发到 KUBE-SVC-
2CMXP7HKUVJN7L6M
在搜索 KUBE-SVC-2CMXP7HKUVJN7L6M
的规则
iptables-save |grep KUBE-SVC-2CMXP7HKUVJN7L6M
主要是最后三条规则
-A KUBE-SVC-2CMXP7HKUVJN7L6M -m comment --comment "default/nginx" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-LNPQQIWGFNOA5PA2 -A KUBE-SVC-2CMXP7HKUVJN7L6M -m comment --comment "default/nginx" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-5YYPNSSTAPIDIORU -A KUBE-SVC-2CMXP7HKUVJN7L6M -m comment --comment "default/nginx" -j KUBE-SEP-245ABZALMPSVYEFI
继续查找第一条规则所转发的路径
iptables-save |grep KUBE-SEP-LNPQQIWGFNOA5PA2
主要是这条规则
-A KUBE-SEP-LNPQQIWGFNOA5PA2 -p tcp -m comment --comment "default/nginx" -m tcp -j DNAT --to-destination 10.244.169.147:80
查找第二条转发的路径
iptables-save |grep KUBE-SEP-5YYPNSSTAPIDIORU
主要为这条规则
-A KUBE-SEP-5YYPNSSTAPIDIORU -p tcp -m comment --comment "default/nginx" -m tcp -j DNAT --to-destination 10.244.36.124:80
查看第三条转发的规则
iptables-save |grep KUBE-SEP-245ABZALMPSVYEFI
主要是这条规则
-A KUBE-SEP-245ABZALMPSVYEFI -p tcp -m comment --comment "default/nginx" -m tcp -j DNAT --to-destination 10.244.36.125:80
所以,现在理清整个iptables的规则
第一步,流量的入口.请求进入他nodePort的30601端口或者service的ip加80端口
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx" -m tcp --dport 30601 -j KUBE-SVC-2CMXP7HKUVJN7L6M -A KUBE-SERVICES -d 10.102.19.139/32 -p tcp -m comment --comment "default/nginx cluster IP" -m tcp --dport 80 -j KUBE-SVC-2CMXP7HKUVJN7L6M
第二步:负载均衡,他是采用random和权重值的方式进行负载均衡,因为iptables是从上到下匹配的,但因为权重值的原因,例如此service有三个pod访问路径。他在访问第一条的时候概率为0.3333,访问第二条概率为0.5,第三条为1,而他又是由上向下按顺序匹配,使得访问三条规则的概率一样,这样实现负载均衡
-A KUBE-SVC-2CMXP7HKUVJN7L6M -m comment --comment "default/nginx" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-LNPQQIWGFNOA5PA2 -A KUBE-SVC-2CMXP7HKUVJN7L6M -m comment --comment "default/nginx" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-5YYPNSSTAPIDIORU -A KUBE-SVC-2CMXP7HKUVJN7L6M -m comment --comment "default/nginx" -j KUBE-SEP-245ABZALMPSVYEFI
第三步:将访问转发到实际的容器中
-A KUBE-SEP-LNPQQIWGFNOA5PA2 -p tcp -m comment --comment "default/nginx" -m tcp -j DNAT --to-destination 10.244.169.147:80 -A KUBE-SEP-5YYPNSSTAPIDIORU -p tcp -m comment --comment "default/nginx" -m tcp -j DNAT --to-destination 10.244.36.124:80 -A KUBE-SEP-245ABZALMPSVYEFI -p tcp -m comment --comment "default/nginx" -m tcp -j DNAT --to-destination 10.244.36.125:80
ipvs
我们查看kube-proxy的日志,能发现service默认是采用iptables为网络模式
所以,如果要使用IPVS,我们首先需要将默认的iptables切换为IPVS
service切换IPVS
使用那种网络模式是有kube-proxy决定的,所以修改网络模式就是修改kube-proxy容器内容
kubeadm方式修改ipvs模式
第一步:
kubectl edit configmap kube-proxy -n kube-system
第二步:找到mode字段,可以看到mode是空的,因为iptables是默认的网络模式,所以当mode为空时kube-proxy会选用iptables模式
第三步:给mode赋值ipvs并保存退出
最后一步,删除节点原kube-proxy的pod,让k8s自己重建,则网络模式会被修改为ipvs
可以看到网络模式已经被修改为ipvs
二进制方式修改ipvs模式
配置文件路径根据实际安装目录为准
# vi kube-proxy-config.yml mode: ipvs ipvs: scheduler: "rr“ # systemctl restart kube-proxy
ipvs规则
查看ipvs的规则
先安装ipvsadm
yum install ipvsadm -y
查看ipvs规则
ipvsadm -L -n
区别
Iptables VS IPVS
Iptables:
• 灵活,功能强大
• 规则遍历匹配和更新,呈线性时延
IPVS:
• 工作在内核态,有更好的性能
• 调度算法丰富:rr,wrr,lc,wlc,ip hash…
补充:CoreDNS
Service DNS名称
CoreDNS:是一个DNS服务器,Kubernetes默认采用,以Pod部署在集群中, CoreDNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析。
参考文章:
k8s-service底层之 Iptables与 IPVS:https://blog.csdn.net/huahua1999/article/details/124237065
K8S中iptables和ipvs区别:https://blog.csdn.net/qq_36807862/article/details/106068871