kube-proxy iptables 和 ipvs 模式的工作原理及示例

客户有个好几年前的k8s老环境,部署新的应用就出问题了,从部署的服务pod里访问k8s svc地址端口 172.16.0.1:443 不通,宿主机上访问都是通的,kube-proxy mode是 iptables 模式,endpoints检察都正常,svc 后端apiserver 6443 也都能正常访问,重建kube-proxy、kubernetes svc 后 pod 访问 svc 依然不通,最后定位到是客户环境问题,pod网络是自定义网络走了客户自己的网关,数据包被路由到网关并未进入本地处理流程,mark一下。


kube-proxy iptables 模式的工作原理:

kube-proxy iptables 和 ipvs 模式的工作原理及示例

kube-proxy是Kubernetes中的一个核心组件,负责维护节点上的网络规则,使得Pod之间的通信和从集群外部到服务的请求能够正确路由。在iptables模式下,kube-proxy并不直接处理流量,而是通过配置iptables规则来将流量导向正确的后端Pod。当一个Service被创建时,kube-proxy会为该Service配置iptables规则。这些规则的作用是将目标为Service的Cluster IP和端口的流量,重定向到后端Pod的IP和端口。负载均衡是通过iptables的随机概率算法实现的,每个后端Pod会被分配一定的权重,流量会按权重随机分发。

在 iptables 模式下,kube-proxy 通过动态管理 iptables 规则来实现流量转发。以下是具体的工作流程:

(1)监听 Kubernetes API Server

  • kube-proxy 会监听 Kubernetes API Server,实时获取 Service 和 Endpoint(Pod)的变化。

  • 当 Service 或 Pod 发生变化时(如创建、删除或更新),kube-proxy 会更新本地的 iptables 规则。

(2)创建 iptables 规则

kube-proxy 会根据 Service 和 Endpoint 的信息,在 nat 表中创建以下链和规则:

  • KUBE-SERVICES 链

    • 这是所有 Service 流量的入口链。

    • 当流量进入节点时,kube-proxy 会将流量导向 KUBE-SERVICES 链。

    • 在 KUBE-SERVICES 链中,会根据目标 IP(ClusterIP)和端口将流量转发到对应的 Service 链。

  • KUBE-SVC-<hash> 链

    • 每个 Service 都会有一个对应的 KUBE-SVC-<hash> 链,<hash> 是 Service 的唯一标识。

    • 这个链负责将流量负载均衡到后端的 Pod。

  • KUBE-SEP-<hash> 链

    • 每个 Pod(Endpoint)都会有一个对应的 KUBE-SEP-<hash> 链,<hash> 是 Pod 的唯一标识。

    • 这个链负责将流量转发到具体的 Pod IP 和端口。

(3)流量转发流程

以下是流量从 Service IP 到 Pod IP 的转发流程:

  1. 流量进入节点的 PREROUTING 链。

  2. PREROUTING 链将流量转发到 KUBE-SERVICES 链。

  3. 在 KUBE-SERVICES 链中,根据目标 IP 和端口匹配到对应的 KUBE-SVC-<hash> 链。

  4. 在 KUBE-SVC-<hash> 链中,根据负载均衡算法(如随机或轮询)将流量转发到某个 KUBE-SEP-<hash> 链。

  5. 在 KUBE-SEP-<hash> 链中,流量被 DNAT(目标地址转换)到具体的 Pod IP 和端口。

  6. 流量最终被转发到目标 Pod。


iptables 规则的示例

以下是一个简单的 iptables 规则示例,展示了 kube-proxy 如何将流量从 Service IP 转发到 Pod IP:

# PREROUTING 主要处理从外部引入的流量和来自 Pod 容器网络的引入流量,OUTPUT 主要处理流出到外部网络的流量和流出到 Pod 容器网络的流量。
因为发布的服务需要对外暴露服务,所以 Kubernetes 创建了一个自定义规则链 KUBE-SERVICE 来支持集群级别的服务发现,即 ClusterIP 和 LoadBalancer 类型,最后通过另外一条自定义规则链 KUBE-NODEPORTS 来对外暴露服务
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS

# 将目标为 ClusterIP:443 的流量转发到 KUBE-SVC-XXX 链
-A KUBE-SERVICES -d 172.16.0.1/32 -p tcp -m comment --comment "default/kubernets:https cluster IP" -m tcp --dport 443 -j KUBE-SVC-XXX

# 后端 Pod 的 DNAT 规则(概率负载均衡)
-A KUBE-SVC-XXX -m statistic --mode random --probability 0.333 -j KUBE-SEP-AAA
-A KUBE-SVC-XXX -m statistic --mode random --probability 0.500 -j KUBE-SEP-BBB
-A KUBE-SVC-XXX -j KUBE-SEP-CCC

# KUBE-SEP-AAA 链(Pod 1 链)
-A KUBE-SEP-AAA -s 10.244.1.11/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-AAA -p tcp -m tcp -j DNAT --to-destination 10.244.1.11:6443

# KUBE-SEP-BBB 链(Pod 2 链)
-A KUBE-SEP-BBB -s 10.244.1.12/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-BBB -p tcp -m tcp -j DNAT --to-destination 10.244.1.12:6443

# KUBE-SEP-CCC 链(Pod 3 链)
-A KUBE-SEP-CCC -s 10.244.1.13/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-CCC -p tcp -m tcp -j DNAT --to-destination 10.244.1.13:6443
  • KUBE-SVC-XXX 链将流量随机转发到三个 Pod 链(KUBE-SEP-AAA、KUBE-SEP-BBB 和 KUBE-SEP-CCC)。

  • KUBE-SEP-AAA、KUBE-SEP-BBB 和 KUBE-SEP-CCC 链分别将流量 DNAT 到具体的 Pod IP 和端口。

iptables 模式的优缺点

优点:

  • 简单可靠:iptables 是 Linux 内核的标准功能,兼容性较好。

  • 无需额外依赖:不需要安装额外的内核模块或工具。

缺点:

  • 性能问题:当 Service 和 Pod 数量较多时,iptables 规则会变得非常复杂,导致性能下降。

  • 规则更新延迟:iptables 规则的更新是线性的,当规则数量较多时,更新速度较慢。

  • 负载均衡能力有限:iptables 只支持简单的负载均衡算法(如随机或轮询)。


kube-proxy IPVS 模式的工作原理

kube-proxy iptables 和 ipvs 模式的工作原理及示例

在 Kubernetes 中,kube-proxy 的 IPVS 模式(IP Virtual Server)是一种基于 Linux 内核的高性能负载均衡机制,用于替代传统的 iptables 模式。IPVS 模式通过内核级负载均衡技术,显著提升了服务流量转发的效率和可扩展性,特别适合大规模集群场景。与 iptables 模式相比,IPVS 模式的优势在于:

  • 更低的延迟:基于哈希表的规则匹配,而非线性遍历规则链。

  • 更高的吞吐量:支持多种负载均衡算法(如轮询、加权轮询、最少连接等)。

  • 更好的扩展性:规则更新和查询效率更高,适合管理数千个 Service 和 Endpoint。

(1)监听 Kubernetes API Server

  • kube-proxy 持续监听 Kubernetes API Server,实时获取 Service、Endpoint 和 Node 的变化。

  • 当 Service 或 Pod 发生变化(如扩缩容、更新)时,kube-proxy 会动态调整 IPVS 规则。

(2)创建虚拟服务(Virtual Service)

IPVS 通过以下方式将 Kubernetes Service 映射到内核中的虚拟服务:

  • Service ClusterIP:为每个 Service 的 ClusterIP 和端口创建虚拟服务(Virtual IP,VIP)。

  • Service 类型:支持 ClusterIP、NodePort、LoadBalancer 和 ExternalIP 类型的 Service。

(3)绑定后端 Pod(Real Server)

每个虚拟服务(VIP)会绑定到多个后端 Pod(称为 Real Server,RS):

  • 后端 Pod 的 IP 和端口会被注册为虚拟服务的 Real Server。

  • IPVS 根据负载均衡算法(如 rr 轮询、lc 最少连接)将流量分发到后端 Pod。

(4)流量转发流程

以下是流量从 Service 到 Pod 的完整流程:

  1. 流量进入节点:无论是通过 ClusterIP、NodePort 还是外部 IP,流量首先到达节点。

  2. IPVS 拦截流量:内核的 IPVS 模块根据目标 IP 和端口匹配到虚拟服务(VIP)。

  3. 负载均衡决策:IPVS 根据预设的算法选择一个后端 Pod(Real Server)。

  4. DNAT(目标地址转换):将流量目标地址从 Service IP 转换为 Pod IP。

  5. 流量转发到 Pod:转换后的流量被发送到 Pod 所在的节点(可能经过 CNI 插件跨节点转发)。

  6. 返回流量处理:返回流量通过反向路径回到客户端,通常需要 SNAT 确保源地址正确。


IPVS 规则示例

通过 ipvsadm 命令可以查看 IPVS 规则:

# 创建虚拟服务
ipvsadm -A -t 172.16.0.1:443 -s rr

# 配置 IP 组绑定到虚拟服务 IP 上
ipvsadm -a -t 172.16.0.1:443 -r 10.244.1.11:6443 -m
ipvsadm -a -t 172.16.0.1:443 -r 10.244.1.12:6443 -m
ipvsadm -a -t 172.16.0.1:443 -r 10.244.1.13:6443 -m

# 查看所有虚拟服务和后端 Pod
ipvsadm -Ln

# 示例输出:
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.0.1:443 rr
  -> 10.244.1.11:6443             Masq    1      0          0
  -> 10.244.1.12:6443             Masq    1      0          0
  -> 10.244.1.13:6443             Masq    1      0          0
TCP  172.16.0.10:53 rr
  -> 10.244.1.2:53                Masq    1      0          0
  -> 10.244.1.3:53                Masq    1      0          0
  • 虚拟服务172.16.0.1:443 对应 Kubernetes 的 API Server Service。

  • 后端 Pod10.244.1.11:6443、10.244.1.12:6443 和 10.244.1.13:6443 是实际的 API Server Pod。

  • 调度算法rr 表示轮询(Round Robin)。


IPVS 负载均衡算法

IPVS 支持多种负载均衡算法,可通过 kube-proxy 的 --ipvs-scheduler 参数配置:

算法缩写全称描述
rrRound Robin轮询分发请求(默认算法)。
wrrWeighted Round Robin根据权重轮询。
lcLeast Connection将新请求分发给当前连接最少的 Pod。
shSource Hashing基于源 IP 的哈希分配,保证同一客户端始终访问同一 Pod。

IPVS 模式的优缺点

优点

  • 高性能:基于内核哈希表,规则匹配效率高,适合大规模集群。

  • 低延迟:避免线性遍历规则链,提升转发速度。

  • 灵活的负载均衡算法:支持多种调度策略。

  • 更少的规则膨胀:规则数量与 Service 数量成线性关系,而非指数关系。

缺点

  • 依赖内核模块:需确保 Linux 内核已加载 ip_vsip_vs_rr 等模块。

  • 功能局限性:某些高级功能(如 externalTrafficPolicy: Local)仍需依赖 iptables


IPVS 与 iptables 的协同

尽管 IPVS 模式主要依赖内核的 IPVS 模块,kube-proxy 仍依赖少量 iptables 规则完成辅助任务

  • Masquerading(SNAT):对某些流量进行源地址转换(如 NodePort 流量)。

  • 过滤特定流量:例如,丢弃无效的包或处理本地回环流量。

  • 兼容性保障:确保某些特殊场景(如 externalTrafficPolicy: Local)的流量正确处理。

1) ipvs 与iptables 协同示例:

  • iptables:负责流量捕获、SNAT 和辅助过滤。

  • ipvs:专注于高效负载均衡。

  • 协同优势:ipvs 提升性能,iptables 补充关键网络功能,共同实现灵活高效的 Service 流量管理。

a. 流量捕获

NodePort 服务:通过 iptables 规则捕获节点端口流量,转发到 ipvs 处理。

-A KUBE-NODEPORTS -p tcp --dport 30080 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp --dport 30080 -j KUBE-SVC-XXXXXX
    • KUBE-SVC-XXXXXX 链最终指向 ipvs 虚拟服务。

b. 源地址伪装(MASQUERADE)

当流量离开节点时,iptables 进行 SNAT(确保返回流量经原节点):

-A KUBE-POSTROUTING -m comment --comment "kube-proxy MASQUERADE" -j MASQUERAD

c. 过滤和兜底规则

  • 健康检查:kube-proxy 通过 iptables 开放健康检查端口(如 10256)。

  • 兜底策略:未命中 ipvs 规则的流量可能由 iptables 处理(如拒绝非法请求)。


d. 协作流程示例(NodePort 流量)

  1. 入口流量:外部请求到达节点的 NodePort 端口(如 30080)。

  2. iptables 拦截KUBE-NODEPORTS 链匹配端口,标记并跳转到 KUBE-SVC-XXXXXX

  3. ipvs 处理KUBE-SVC-XXXXXX 指向 ipvs 虚拟服务,由 ipvs 按调度算法分发到后端 Pod。

  4. 出站伪装:iptables 的 MASQUERADE 规则修改源 IP,确保响应正确返回。


2) 模式选择与配置

  • –proxy-mode 参数:当你配置为 --proxy-mode=ipvs,立即激活 IPVS NAT 转发模式,实现 POD 端口的流量负载。

  • –ipvs-scheduler 参数:修改负载均衡策略,默认为 rr——轮询调度。

  • –cleanup-ipvs 参数:启动 IPVS 前清除历史遗留的规则。

  • –ipvs-sync-period 和 –ipvs-min-sync-period 参数:配置定期同步规则的周期,例如 5s,必须大于 0。

  • –ipvs-exclude-cidrs 参数:过滤自建的 IPVS 规则,让你可以保留之前的负载均衡流量。

  • 依赖条件:ipvs 需内核模块支持(如 ip_vsip_vs_rr)。


3)  iptables 模式 与 ipvs 模式 的对比

以下是 iptables 模式 与 ipvs 模式 的对比表格,总结了它们在 Kubernetes 中管理网络流量的核心差异:

对比项iptables 模式ipvs 模式
工作方式基于链式 iptables 规则实现流量转发和负载均衡。基于内核级 IPVS 虚拟服务(L4)实现高效负载均衡。
性能规则链庞大时性能显著下降(时间复杂度 O(n))。高性能,时间复杂度 O(1),适合大规模集群。
负载均衡算法仅支持随机概率均衡(statistic mode random)。支持多种算法(如轮询 rr、加权最小连接 wlc、哈希 sh 等)。
规则管理每新增一个 Service/Endpoint 需添加多条 iptables 规则,规则复杂度高。直接管理虚拟服务和后端 Pod,规则更简洁。
适用场景小规模集群或对性能要求不高的场景。大规模集群、高并发或需要复杂负载均衡策略的场景。
资源消耗规则数量多时内存和 CPU 占用较高。资源占用低,规则与后端数量无关。
配置复杂度规则链复杂,调试困难(需跟踪多条链)。配置简单,调试直观(ipvsadm 命令查看虚拟服务)。
内核依赖依赖 iptables 和 conntrack 模块。依赖 ip_vsip_vs_rrip_vs_wlc 等 IPVS 内核模块。
SNAT 处理直接通过 iptables 的 MASQUERADE 规则实现。需依赖 iptables 的 MASQUERADE 规则辅助实现。
流量兜底处理通过 iptables 规则直接拒绝非法流量。依赖 iptables 补充兜底规则(如拒绝非法请求)。
健康检查支持通过 kube-proxy 维护 iptables 规则,间接支持。由 IPVS 直接管理后端健康状态(需结合 kube-proxy 的 Endpoint 监听)。

选择建议

  • 小规模集群/简单场景:优先使用 iptables(默认兼容性更好)。

  • 大规模/高性能场景:选择 ipvs(需内核支持)。

  • 特殊需求:如需高级负载均衡算法(如最小连接数),必须使用 ipvs


了解了k8s kube-proxy网络流量管理模式,接下来排查思路就很清晰了:

排查步骤

1、检查 Service、Endpoints、kube-proxy等服务是否正常

# 查看 Service 配置
kubectl describe svc kubernetes -n default
kubectl get svc kubernetes -n default -o yaml

# 查看 Endpoints 配置
kubectl describe endpoints kubernetes -n default
kubectl get endpoints kubernetes -n default -o yaml

# 检查 kube-proxy 日志
kubectl logs -n kube-system <kube-proxy-pod-name>

# 检查网络插件日志
kubectl logs -n kube-system <cni-pod-name>
journalctl -u kubelet | grep -i proxy

# 检查内核日志
dmesg | grep kube-proxy

# 重启 kubelet 和容器运行时
systemctl restart kubelet docker/containerd
  • 确认 Endpoints 指向正确的 apiserver IP 和端口(6443)

  • 确保 kubernetes Service 的端口映射正确(443→6443)

2、检查是否有防火墙、网络策略等规则限制

### 查看是否有网络策略测试影响

kubectl get networkpolicy --all --all-namespaces


### 检查流量是否被其他 iptables 表/链丢弃

# 查看 filter 表的 INPUT/FORWARD/OUTPUT 链
iptables-save -t filter | grep -E "DROP|REJECT"

# 查看是否有规则丢弃 172.16.0.1 的流量
iptables-save -t filter | grep 172.16.0.1

如果有 DROP/REJECT 规则,临时允许流量:

iptables -I INPUT -d 172.16.0.1 -p tcp --dport 443 -j ACCEPT


### 检查 NAT 规则是否正确跳转

# 确保 KUBE-SERVICES 正确跳转到 KUBE-SVC-...,并最终到 KUBE-SEP-...(API Server 的 Endpoint)。

# 查看 KUBE-SERVICES 链的跳转目标
iptables-save -t nat | grep "KUBE-SVC-.*TCP.*443"

# 查看最终的 KUBE-SEP-... 规则(应指向 API Server 的 IP:6443)
iptables-save -t nat | grep "KUBE-SEP-"


### 检查流量是否被 filter 表丢弃

# 查看 filter 表的 INPUT/FORWARD/OUTPUT 链是否有 DROP/REJECT 规则
iptables-save -t filter | grep -E "DROP|REJECT"

# 检查是否有针对 172.16.0.1:443 的拦截规则
iptables-save -t filter | grep 172.16.0.1

修复方法:临时允许流量(测试用):

iptables -I INPUT -d 172.16.0.1 -p tcp --dport 443 -j ACCEPT
iptables -I FORWARD -d 172.16.0.1 -p tcp --dport 443 -j ACCEPT

临时修复尝试:强制清理 iptables 规则

# 1. 备份当前 iptables 规则(防止误操作)
iptables-save > /tmp/iptables-backup.rules

# 2. 清理所有 kube-proxy 相关的规则
iptables-save | grep -v KUBE- | iptables-restore

# 3. 重启 kube-proxy
kubectl delete pod -n kube-system -l k8s-app=kube-proxy

3、检查路由是否正确,使用 tcpdump 抓包

### 检查路由是否正确

# 使用 traceroute 查看流量路径
traceroute -n -T -p 443 172.16.0.1
tracepath -p 443 172.16.0.1

# 测试访问
curl -vk https://172.16.0.1:443
telnet 172.16.0.1 443

# 检查路由表优先级
ip route show table all | grep 172.16.0.1

# 查看目标 IP 的路由
ip route get 172.16.0.1

# 期望输出示例(应走主网卡 eth0):
# 172.16.0.1 dev eth0 src 10.0.0.1 uid 0

异常情况:

如果显示 dev tun0 或其他虚拟网卡,可能是 VPN 或 CNI 插件干扰。
如果显示 via <网关>,需确保网关能正确转发 Service IP。


###  使用 tcpdump 抓包

# 在节点上抓取 172.16.0.1:443 流量
tcpdump -i bondxxx 172.16.0.1 and port 443 -nnvvv

# 如果无流量,说明数据包未到达节点(被路由或防火墙拦截)。
# 如果有流量但无响应,可能是 NAT 未生效。

4、跟踪 iptables 规则是否命中,检查 NAT 规则是否正确跳转

# 查看规则计数器(观察 pkts 是否增加)
iptables -t nat -L KUBE-SERVICES -n -v

如果 pkts 不增加,说明流量未命中规则,可能是:

流量被其他链(如 FORWARD)丢弃。

路由问题导致流量未进入 KUBE-SERVICES 链。

# 临时添加日志规则(观察流量路径)
iptables -t raw -I PREROUTING -d 172.16.0.1 -p tcp --dport 443 -j TRACE
iptables -t raw -I OUTPUT -d 172.16.0.1 -p tcp --dport 443 -j TRACE

# 查看内核日志
dmesg -T | grep TRACE

经过以上排查步骤,结果如下:

1、svc、ep、kube-proxy都正常,且无防火墙和网络测试限制

2、iptables NAT规则配置都正常,添加iptables日志规则无数据说明数据包未经过 NAT 表,pkts无数据说明也没有命中KUBE-SVC规则,通过以上分析基本可以定位到是路由问题数据包被路由到其他网卡或未进入本地处理流程。

3、pod 有到网关的路由规则,抓包返回 reset 包(问题定位)

kube-proxy iptables 和 ipvs 模式的工作原理及示例

kube-proxy iptables 和 ipvs 模式的工作原理及示例

原因分析

问题本质:Pod 访问 172.16.0.1 时,路由表错误地将流量导向网关 10.240.xxx.xxx,而正确的行为应该是:

宿主机处理:流量应留在宿主机,由 kube-proxy 的 iptables/IPVS 规则转发到 API Server(6443 端口)。

测试验证:

Pod 使用本机网络,设置  hostNetwork:true,访问 172.16.0.1:443 能通

# 进入一个启用宿主机网络测试 Pod
kubectl run -it --rm testpod --image=busybox --overrides='{"spec": {"hostNetwork": true}}' -- sh

# 验证 Pod 是否使用宿主机网络,预期输出:hostNetwork: true
kubectl get pod my-hostnetwork-pod -o yaml | grep hostNetwork

# 通过 YAML 文件创建(推荐),创建文件 hostnetwork-pod.yaml:
apiVersion: v1
kind: Pod
metadata:
  name: my-hostnetwork-pod
spec:
  hostNetwork: true  # 关键配置
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80  # 容器内端口(实际会绑定到宿主机)

# 应用配置
kubectl apply -f hostnetwork-pod.yaml

# 在 Pod 内测试
wget 172.16.0.1:443 -O - -T 5
telnet 172.16.0.1 443

注意事项

1、端口冲突风险

如果容器内的进程绑定到某个端口(如 80),该端口会直接在宿主机上暴露,可能与其他进程冲突。如果容器需要绑定宿主机特权端口(如 80),需提升权限:

spec:
  containers:
  - name: nginx
    securityContext:
      privileged: true  # 授予特权模式(谨慎使用)

2、DNS 解析行为

使用 hostNetwork: true 时,Pod 默认继承宿主机的 DNS 配置(/etc/resolv.conf),而非 Kubernetes 的 CoreDNS

若需使用集群内服务发现,需手动配置 DNS。

spec:
  dnsPolicy: "None"  # 覆盖默认 DNS 策略
  dnsConfig:
    nameservers:
      - 10.96.0.10  # 替换为集群 CoreDNS 的 ClusterIP
    searches:
      - default.svc.cluster.local
      - svc.cluster.local
      - cluster.local

3、安全风险

暴露宿主机网络栈可能带来安全隐患,建议仅用于特定场景(如网络监控工具、测试)。


参考:

anzhihe 安志合个人博客,版权所有 丨 如未注明,均为原创 丨 转载请注明转自:https://chegva.com/6343.html | ☆★★每天进步一点点,加油!★★☆ | 

您可能还感兴趣的文章!

发表评论

电子邮件地址不会被公开。 必填项已用*标注