保姆级教程:用`ipvsadm`和`iptables-save`命令,一步步拆解K8s Service的流量转发路径
深入拆解Kubernetes Service流量转发从命令行视角看ipvs与iptables的协同当你第一次在Kubernetes集群中创建一个Service时有没有好奇过这个虚拟IP背后究竟发生了什么为什么一个ClusterIP能够稳定地将流量路由到可能随时变化的Pod上今天我们就用ipvsadm和iptables-save这两把手术刀在真实的Minikube集群中解剖这个看似简单实则精妙的过程。1. 实验环境准备与基础概念在开始我们的探索之旅前让我们先搭建一个简单的实验环境。使用Minikube创建一个本地集群是最快捷的方式minikube start --driverdocker --network-plugincni --extra-configkube-proxy.modeipvs这个命令创建了一个使用ipvs模式的Kubernetes集群。为什么特别指定ipvs因为在生产环境中ipvs模式通常能提供更好的性能特别是当你有大量Service时。不过别担心我们也会探讨iptables模式的工作机制。几个核心概念需要明确ServiceKubernetes中的抽象为一组Pod提供稳定的访问入口EndpointService背后实际提供服务的Pod IP和端口集合kube-proxy运行在每个节点上的网络代理负责实现Service的虚拟IP机制让我们创建一个简单的Nginx Deployment和对应的ServiceapiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 type: ClusterIP应用这个配置后我们就有了一个完美的实验对象。现在让我们进入正题。2. 解剖iptables模式下的流量路径虽然我们创建集群时指定了ipvs模式但理解iptables模式仍然很重要因为ipvs模式实际上也依赖iptables完成部分功能。让我们先看看纯iptables模式下的转发机制。2.1 关键iptables链解析在iptables模式下kube-proxy会创建一系列自定义链来处理Service流量。这些链的名字通常以KUBE-SVC-和KUBE-SEP-开头。让我们看看它们的实际作用# 查看与我们的nginx-service相关的iptables规则 minikube ssh -- sudo iptables-save | grep -i nginx-service你会看到类似这样的输出具体哈希值会不同-A KUBE-SERVICES -d 10.96.0.1/32 -p tcp -m comment --comment default/nginx-service: cluster IP -m tcp --dport 80 -j KUBE-SVC-2CMXP7HKUVJN7L6M -A KUBE-SVC-2CMXP7HKUVJN7L6M -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-XYZZY123456 -A KUBE-SVC-2CMXP7HKUVJN7L6M -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-ABCDEF789012 -A KUBE-SVC-2CMXP7HKUVJN7L6M -j KUBE-SEP-987654ZYXWVU这些规则的含义第一条规则将所有目标为Service ClusterIP(10.96.0.1)且端口为80的流量跳转到KUBE-SVC-*链后续规则实现了简单的负载均衡使用概率将流量分配到不同的KUBE-SEP-*链每个对应一个Pod2.2 深入Endpoint链每个KUBE-SEP-*链对应一个具体的Pod端点。让我们看看其中一个minikube ssh -- sudo iptables-save | grep KUBE-SEP-XYZZY123456输出可能类似-A KUBE-SEP-XYZZY123456 -s 10.244.0.5/32 -j KUBE-MARK-MASQ -A KUBE-SEP-XYZZY123456 -p tcp -m tcp -j DNAT --to-destination 10.244.0.5:80关键点第一条规则为来自Pod自身的流量打上标记用于后续的SNAT第二条规则执行DNAT将目标地址改为Pod的实际IP和端口2.3 iptables模式的性能考量虽然iptables模式简单可靠但它有一个明显的缺点随着Service和Pod数量的增加iptables规则会呈指数级增长。这是因为规则数量 ≈ Service数量 × 每个Service的Endpoint数量 × 节点数量当集群规模较大时比如超过1000个Serviceiptables的线性查找性能会成为瓶颈。这就是为什么Kubernetes引入了ipvs模式。3. ipvs模式下的流量转发机制现在让我们回到ipvs模式看看它是如何解决iptables的规模问题的。3.1 ipvs基础组件ipvs模式下kube-proxy会创建一个名为kube-ipvs0的虚拟接口并为每个Service分配一个IP地址minikube ssh -- ip addr show kube-ipvs0输出类似4: kube-ipvs0: BROADCAST,NOARP mtu 1500 qdisc noop state DOWN group default inet 10.96.0.1/32 scope global kube-ipvs0 valid_lft forever preferred_lft forever inet 10.96.0.10/32 scope global kube-ipvs0 valid_lft forever preferred_lft forever每个Service IP都绑定在这个接口上尽管接口状态是DOWN但这不影响ipvs的功能。3.2 使用ipvsadm查看规则ipvs的核心功能可以通过ipvsadm命令查看minikube ssh -- sudo ipvsadm -ln输出示例IP Virtual Server version 1.2.1 (size4096) Prot LocalAddress:Port Scheduler Flags - RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 10.96.0.1:80 rr - 10.244.0.5:80 Masq 1 0 0 - 10.244.0.6:80 Masq 1 0 0 - 10.244.0.7:80 Masq 1 0 0关键信息rr表示使用轮询(round-robin)调度算法三个后端Pod被列为真实服务器(Real Server)Masq表示使用IP伪装(MASQUERADE)即SNAT3.3 ipvs如何与iptables协同工作虽然ipvs接管了主要的负载均衡工作但iptables仍然在以下方面发挥作用包过滤实现网络策略和基本防火墙功能SNAT处理为来自Pod的流量做源地址转换查看相关的iptables规则minikube ssh -- sudo iptables-save | grep -i KUBE-MARK-MASQ你会看到类似这样的规则-A KUBE-POSTROUTING -m comment --comment kubernetes service traffic requiring SNAT -m mark --mark 0x4000/0x4000 -j MASQUERADE这条规则为所有被打上0x4000标记的流量执行MASQUERADESNAT。4. 实战追踪一个请求的完整旅程现在让我们实际追踪一个请求从Service到Pod的完整路径。我们将使用tcpdump和kubectl的端口转发功能。4.1 在Pod中启动tcpdump选择一个Pod并在其中启动tcpdump# 获取Pod列表 kubectl get pods -o wide # 在其中一个Pod中启动tcpdump kubectl exec -it nginx-deployment-xxxx -- tcpdump -i eth0 port 804.2 从外部发起请求在另一个终端中使用kubectl port-forward将Service端口映射到本地kubectl port-forward service/nginx-service 8080:80然后在第三个终端中访问这个服务curl http://localhost:80804.3 分析流量路径观察tcpdump的输出你会看到类似这样的记录10.244.0.1.60312 10.244.0.5.80: Flags [S], seq 123456789, win 64860, options [mss 1412,sackOK,TS val 987654321 ecr 0,nop,wscale 7], length 0关键点源IP是10.244.0.1通常是节点的IP目标IP是Pod的实际IP这表明DNAT已经成功将Service IP转换为Pod IP5. 性能优化与模式选择建议在实际生产环境中选择iptables还是ipvs模式需要考虑多个因素考虑因素iptables模式ipvs模式小规模集群简单可靠兼容性好优势不明显大规模集群规则数量多性能下降明显规则数量对性能影响小网络策略与NetworkPolicy集成更好需要额外iptables规则配合负载均衡算法仅支持随机和轮询支持多种算法(rr,lc,sh,dh等)调试复杂度规则直观但数量多规则简洁但需要结合ipvsadm和iptables个人经验分享在管理一个约500节点的生产集群时我们从iptables切换到ipvs后kube-proxy的CPU使用率下降了约40%特别是在Service数量超过2000后差异更加明显。不过要注意ipvs模式需要内核支持某些云主机的定制内核可能需要额外配置。