k8s中iptables与ipvs详解——2023.05

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
EMR Serverless StarRocks,5000CU*H 48000GB*H
简介: k8s中iptables与ipvs详解——2023.05

背景介绍


从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 支持服务器健康检查和连接重试等功能

eea4978134734ab091946c7f0b044ccc.png


一、Iptables模式


在这种模式下,kube-proxy监视API Server中service和endpoint的变化情况。对于每个service,它都生成相应的iptables规则,这些规则捕获到service的clusterIP和port的流量,并将这些流量随机重定向到service后端Pod。对于每个endpoint对象,它生成选择后端Pod的iptables规则。


如果选择的第一个Pod没有响应,kube-proxy将检测到到第一个Pod的连接失败,并将自动重试另一个后端Pod。

08cd664e326e488e870bf5550fce12e8.png

缺点:

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使用更低的重定向流量。其同步规则的效率和网络吞吐量也更高。

58bc44b46ac6437db500451708f02252.png

ipvs依赖iptables进行包过滤、SNAT、masquared(伪装)。 使用 ipset 来存储需要 DROP 或 masquared 的流量的源或目标地址,以确保 iptables 规则的数量是恒定的,这样我们就不需要关心我们有多少服务了

如果没有加载并启用ipvs模块,或者没有配置ipvs相关配置,则会被降级成iptables模式。


三、内部原理理解


Iptables

以k8s中的nginx这个service举例,这是一个nodePort类型的service

1f56b680a43b43bfa91cf5e4a9ac1a32.png


用命令

iptables-save |grep nginx

可以看到这个service中的iptables规则

5f5150dbc5fb4e1e84843b9566a599eb.png

找到他对外暴露的端口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

70465248e0024aadac7620ae7cf5c8bf.png

主要是最后三条规则

-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

70ba4f030fd34c619d4237a5bbbe2519.png

主要是这条规则

-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

a61cb72830a84e10a4dc6fab6f795176.png

主要为这条规则

-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

e223e46d7175443f80176aa6257a6f9b.png

主要是这条规则

-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为网络模式

80ac159eaaf247ad91770e62941d0bbc.png

所以,如果要使用IPVS,我们首先需要将默认的iptables切换为IPVS

service切换IPVS

使用那种网络模式是有kube-proxy决定的,所以修改网络模式就是修改kube-proxy容器内容
kubeadm方式修改ipvs模式

第一步:

kubectl edit configmap kube-proxy -n kube-system

447a5aa2a41c4f0a9c7af3231cf11f38.png

第二步:找到mode字段,可以看到mode是空的,因为iptables是默认的网络模式,所以当mode为空时kube-proxy会选用iptables模式

d6bdce2a7a894fae8987a87fa31fca05.png

第三步:给mode赋值ipvs并保存退出

38943f05fa194d7e8b36750f1cde534f.png

3e08ffbfd38a4ab4bea93d7830d074fb.png

最后一步,删除节点原kube-proxy的pod,让k8s自己重建,则网络模式会被修改为ipvs

f5fb21bc508a4bbea186fde1ffdd9bea.png

feb0efc776a644c4ae038acbe1b27ae7.png

可以看到网络模式已经被修改为ipvs

66f33f11b6274a21b30d61d28546aa2c.png

二进制方式修改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

0d95e71f302f41009e4749a06a0469e2.png

区别

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

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
3月前
|
存储 Kubernetes 负载均衡
在K8S中,Kube-Proxy为什么使用ipvs,而不使用iptables?
在K8S中,Kube-Proxy为什么使用ipvs,而不使用iptables?
|
3月前
|
存储 Kubernetes 负载均衡
在K8S中,kube-proxy ipvs 和 iptables 有何异同?
在K8S中,kube-proxy ipvs 和 iptables 有何异同?
|
3月前
|
Kubernetes 负载均衡 API
在K8S中,kube-proxy ipvs 原理是什么?
在K8S中,kube-proxy ipvs 原理是什么?
|
3月前
|
Kubernetes 负载均衡 API
在K8S中,kube-proxy iptables 原理是什么?
在K8S中,kube-proxy iptables 原理是什么?
|
6月前
|
Kubernetes 容器
安装ipvsadm并且k8s开启IPVS模式
安装ipvsadm并且k8s开启IPVS模式
60 0
|
6月前
|
Kubernetes 负载均衡 Cloud Native
云原生|kubernetes|解决kube-proxy报错:Not using `--random-fully` in the MASQUERADE rule for iptables
云原生|kubernetes|解决kube-proxy报错:Not using `--random-fully` in the MASQUERADE rule for iptables
62 0
|
6月前
|
Kubernetes 算法 Cloud Native
云原生|kubernetes|集群网络优化之启用ipvs
云原生|kubernetes|集群网络优化之启用ipvs
307 0
|
Kubernetes 负载均衡 Cloud Native
云原生|kubernetes|解决kube-proxy报错:Not using `--random-fully` in the MASQUERADE rule for iptables
云原生|kubernetes|解决kube-proxy报错:Not using `--random-fully` in the MASQUERADE rule for iptables
607 0
|
Kubernetes Shell 开发者
K8S 集群部署_主机准备_配置主机 ipvs 功能 | 学习笔记
快速学习 K8S 集群部署_主机准备_配置主机 ipvs 功能
378 0
K8S 集群部署_主机准备_配置主机 ipvs 功能 | 学习笔记
|
弹性计算 Kubernetes 网络协议
k8s网络诊断之被丢弃的SYN--linux数据包的接收过程(k8s+flannel+ ipvs)
某客户反馈,ECS上自建nginx server 通过proxy_pass 反向代理 云上k8s集群 nodeport类型的svc,存在大量1s的延迟请求的问题,在nginx所在的ecs上,使用netstat可以看到syn_sent状态的connection,如下图所示,但是在pod所在的worker节点上是看不到syn_RECV状态的connection(nodeport上也无)
1288 0