k8s proxy 网络模型
iptables 模式

注意,所有的k8s 标记只分为两种,一种是需要转发的标记0x400,一种是需要丢弃的标记0x800。前者会最终在 POST 中被转发。
下面解释一下为什么会有需要丢弃的数据包。由于规则链的建立并不是原子性的,所以可能会出现一种情况,规则链建立一半时,已经有相关的数据包到达了——这是一个非常危险的情况,可能会导致一些未定义的行为。因此,在规则正在建立的过程中,需要将相关数据包标记为 0x800,并最终丢弃掉。也就是 0x800 是用于标识规则链是否完全建立的。
另外一种情况是按照用户的需求,对一些虚拟容器进行隔离操作。
iptables - clusterIP访问模式
这种访问模式一般是用于访问启动了多个实例的服务,并且需要进行负载均衡。客户端访问的链路可以表示为:
PREROUTING -> KUBE-SERVICE -> KUBE-SVC-SERV -> KUBE-SEP-POD
所有外部流量都会被 KUBE-SERVICE 链截获,并检查是否有流量是流向某一clusterIP的,并将流量传递给对应的 KUBE-SVC-SERV。KUBE-SVC-SERV 根据设置的负载均衡算法,将流量转发给对应的 KUBE-SEP-POD 链,并最终在该链中进行 DNAT 处理。
iptables - NodePort 访问模式
这种方式通常用来访问单独启动的服务实例。客户端的访问链路可以表示为:
PREROUTING -> KUBE-SERVICE -> KUBE-NODEPORTS -> KUBE-SVC-XXX -> KUBE-SEP-XXX
单独启动的服务实例会单独注册在 KUBE-SERVICE链中,当clusterIP匹配完成后,才会进行 NodePort 规则匹配。使用 nodePort 方式来访问一个容器,其转发链路要更长,因此性能要稍差。
ipvs 模式

ipvs 因为继承了 lvs 模块,所以其实是更加简单的。只需要在流量入口处进行流量区分和标记就可以。客户端进行访问的链路可以表示为:
PREROUTING -> KUBE-SERVICES -> KUBE-CLUSTER-IP -> INPUT -> KUBE-FIREWALL -> POSTROUTING
或者为:
PREROUTING –> KUBE-SERVICES –> KUBE-NODE-PORT –> INPUT –> KUBE-FIREWALL –> POSTROUTING
- KUBE-SERVICES 链负责劫持所有的流量,进行粗删选,根据主机所设置的网段号来初步判断流量目标是否是k8s 服务。
- KUBE-CLUSTER-IP 负责第二次筛选,将网段正确的流量匹配ipset集合,如果通过集合,则标记为0x2000,如果失败则标记为0x4000。
- 如果 KUBE-SERVICES 链没有通过筛选,则进入 KUBE-NODE-PORT 链中,判断是否是单独开启的服务实例。
- INPUT 与 KUBE-FIREWALL:判断是否有标记为 0x4000 的流量,如果有,直接丢弃。
- IPVS 与 POSTROUTING:将通过匹配的流量通过 nat 的方式转发到负载均衡算法计算后的地址。使用 nat 是因为可以很好地进行端口映射,这样会使得调度机制更加灵活,