🗒️k8s kube-proxy的模式
2023-5-10
| 2023-5-17
0  |  0 分钟
type
status
date
slug
summary
tags
category
icon
password

写在前面

本文基于以下假设:
  • 了解iptables的四表五链
  • 熟悉CNI插件的实现方式,如overlay,本文流量分析基于flannel的overlay模式
iptables的四表五链是非常枯燥的,大致图解如下,more
notion image
虽然有很多博主分享原理,一步步查iptables的链来验证流量流向。无奈图示缺少,或者图示步骤不能解答某些疑惑。故此文主要是通过图解来比较异同,图示是根据多篇文章和自己的理解而来,可能存在谬误。而且很奇怪的一点,基本上可以查到的流量流向分析都是基于本机的iptables或者ipvs,几乎无人分析流量到目的服务器后的流向,即使有,准确性也存疑。
强烈推荐先看下面的文章,作者对ipvs的原理有很深的讲解

几个说明/结论

  • iptables有5条系统预定义的链,也可以自定义规则链(kube开头的链),但自定义链不能自动触发,因此一个数据包过来都是从系统预定义的链开始匹配的。
  • 无论iptables还是ipvs模式,k8s只使用了两个表:nat表和filter表,除了常规的链或者hook钩子,k8s自定义了很多KUBE开头的链或者hook钩子
  • PREROUTING和OUTPUT是进和出的第一关口,即主机上的流量要么先进入PREROUTING,要么先进入OUTPUT。而这两个关口首条NAT规则都先将所有流量导入KUBE-SERVICE链中,这样就截获了所有的入流量和出流量,进而可以对 k8s 相关流量进行重定向处理。
  • iptables模式下,不要尝试ping svc的clusterIP,不会通,因为clusterIP只存在于iptables规则里,因为未关联任何(虚拟)网卡。而ipvs模式下,虚拟网卡kube-ipvs0(dummy类型)关联所有的clusterIP,故可以ping通clusterIP,不过ping通不一定代表网络正常。
  • 和应用层负载均衡如haproxy、nginx不一样的是,haproxy、nginx进程是运行在用户态,因此会创建socket,本地会监听端口,而ipvs的负载均衡是直接运行在内核态的,因此不会出现监听端口。
  • ipvs的实现方式有多种:nat转发、网关、IPIP。由于Kubernetes Service需要使用端口映射功能,因此kube-proxy必然只能使用ipvs的NAT模式。
  • 虽然iptables模式弥补了userspace模式的一些缺陷,但iptables模式本身也存在一些缺陷,主要是在存在大量service的场景下,大量的规则同时也会产生一些问题:iptables规则匹配延时,iptables规则更新延时,负载均衡性能问题,QPS抖动问题
  • 不管是iptables还是ipvs转发模式,Kubernetes中访问Service都会进行DNAT,将原本访问 ClusterIP:Port 的数据包 DNAT 成 Service 的某个 Endpoint (PodIP:Port),然后内核将连接信息插入 conntrack 表以记录连接,目的端回包的时候内核从 conntrack 表匹配连接并反向 NAT,这样原路返回形成一个完整的连接链路。

1. iptables模式

💡
iptables模式下,不走input链,走forward链。
创建一个 clusterIP 访问方式的 service 以及带有两个副本,从 pod 中访问 clusterIP 的 iptables 规则流向为:
PREROUTING --> KUBE-SERVICE --> KUBE-SVC-XXX --> KUBE-SEP-XXX
宿主机curl访问clusterIP的iptables规则流向为(存疑,仅供参考):
PREROUTING --> KUBE-SERVICES->KUBE-FIREWALL->route table->KUBE-POSTROUTING | PREROUTING --> KUBE-SERVICES->route table->KUBE-FORWARD->KUBE-POSTROUTING 本机 | 目的宿主机
目的宿主机流量流向的理解:overlay模式下,flannel.1+cni0是集群网桥,pod的IP是集群网桥的子网,路由策略非常直白,故流量到达目的宿主机的prerouting后,直接通过路由决策进入forward,最后到postrouting。
 
kube-proxy iptables模式最主要的链是:KUBE-SERVICES、KUBE-SVC-XXX、KUBE-SEP-XXX。其中:
  • KUBE-SERVICES链 :访问集群内service的数据包入口,它会根据匹配到的service IP:port跳转到KUBE-SVC-XXX链。
  • KUBE-SVC-XXX链 :对应service对象,基于random功能实现了流量的负载均衡。
  • KUBE-SEP-XXX链 :通过DNAT将service IP:port替换成后端pod IP:port,从而将流量转发到相应的pod。
💡
图示中k8s特有的钩子简化了,详见最后的参考链接。如POSTROUTING有一条无条件跳转到KUBE-POSTROUTING链的规则
notion image
notion image

2. ipvs模式

💡
ipvs模式下,不走forward链,走input链。
创建一个 clusterIP 访问方式的 service 以及带有两个副本,从 pod 中访问 clusterIP 的 iptables 规则流向为:
PREROUTING --> KUBE-SERVICES --> KUBE-CLUSTER-IP --> INPUT --> KUBE-FIREWALL --> POSTROUTING
宿主机curl访问clusterIP的iptables规则流向不能确定,理论上第一条经过output。不过由于KUBE-SERVICES也会接管output流量,这样的话,经过output的流量岂不是和经过prerouting的一样要经过input最后跳转到postrouting?
为什么走了input链?说明进入prerouting的数据包目的IP是本机。
Chain KUBE-SERVICES (2 references) target prot opt source destination KUBE-MARK-MASQ all -- !10.244.0.0/16 0.0.0.0/0 /* Kubernetes service cluster ip + port for masquerade purpose */ match-set KUBE-CLUSTER-IP dst,dst KUBE-NODE-PORT all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 match-set KUBE-CLUSTER-IP dst,dst
  • clusterIP模式:kube-ipvs0网卡(宿主机)绑定了所有的clusterIP,而KUBE-SERVICES链会把流量全部转到KUBE-CLUSTER-IP,故此时目的ip就是本机。
  • nodeport模式:目的ip就是本机
💡
图示中k8s特有的钩子简化了,详见最后的参考链接。如POSTROUTING有一条无条件跳转到KUBE-POSTROUTING链的规则
notion image
notion image
IPVS vs IPTABLES
  • iptables 判决是基于链的,它是一个复杂度为 O(n) 的线性算法。iptables 的一个好的替代方案是 IPVS——内核中的 L4 负载均衡器,它在底层使用 ipset(哈希实现),因此复杂度为 O(1)。;
  • iptables 只支持随机、轮询两种负载均衡算法而 ipvs 支持的多达 8 种;
  • ipvs 还支持 realserver 运行状况检查、连接重试、端口映射、会话保持等功能。

3. 参考

 
 
技术
  • k8s
  • 网络
  • kubectl获取deployment的request.cpuk8s pod间的网络实现
    目录