前言
不知道一直在玩k8的朋友有没有发现一个问题,开启了
ipvs
之后,
service
开启
NodePort
之后,在宿主机压根找不到该监听端口,本篇文章将带着大家解开这层面纱。
iptable回顾
四表五链的处理顺序是先作用链,再作用表!!!
四表五链的处理顺序是先作用链,再作用表!!!
四表五链的处理顺序是先作用链,再作用表!!!
链的访问顺序是:
- 数据包到达网卡时,首先经过
链,进行预路由处理。PREROUTING
- 然后,在经过
链后,根据路由规则确定目标地址和接口,选择目标主机或者进行转发。PREROUTING
- 如果数据包是发往本地主机的,那么接下来会经过INPUT链,进行输入数据包的处理。
- 如果数据包是转发的,那么接下来会经过
链,进行数据包的转发处理。FORWARD
- 如果数据包是由本地主机发出的,那么接下来会经过
链,进行输出数据包的处理。OUTPUT
- 最后,数据包离开网卡之前,会经过
链,进行后路由处理。POSTROUTING
每条链上有什么表呢?
- PREROUTING链:
- raw表:用于处理连接跟踪之前的数据包,可以修改数据包的源地址。
- mangle表:用于处理数据包的特殊修改,如修改TTL(生存时间)字段、标记数据包等。
- INPUT链:
- mangle表:用于处理数据包的特殊修改。
- nat表:用于网络地址转换,通常用于
(目标地址转换)和DNAT
(源地址转换)。MASQUERADE
- FORWARD链:
- mangle表:用于处理数据包的特殊修改。
- filter表:用于过滤数据包,决定是否允许数据包通过路由转发。
- OUTPUT链:
- raw表:用于处理连接跟踪之前的数据包,可以修改数据包的源地址。
- mangle表:用于处理数据包的特殊修改。
- nat表:用于网络地址转换,通常用于
(源地址转换)。SNAT
- POSTROUTING链:
- mangle表:用于处理数据包的特殊修改。
- nat表:用于网络地址转换,通常用于
(源地址转换)和SNAT
(源地址转换)。MASQUERADE
这些表的作用是在五个主要的链上进行数据包处理和转换。根据规则的配置,
iptables
可以对数据包进行源地址转换、目标地址转换、标记、过滤等操作,从而实现网络流量的控制和管理。每个链上可以同时使用多个表,可以根据需求组合不同的规则来实现复杂的网络处理逻辑。
kube-proxy定义的链条
除了
iptable
本身的四表五链之外,
kube-proxy
也自定义了一系列链条,这里我们只基于
NodePort
并且开启
ipvs
的
kube-proxy
进行讨论
[root@openeuler-controlplane-jtzv-0 ~]# iptables -nL -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
cali-PREROUTING all -- 0.0.0.0/0 0.0.0.0/0 /* cali:6gwbT8clXdHdC1b1 */
KUBE-SERVICES all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */
CNI-HOSTPORT-DNAT all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
......
Chain KUBE-SERVICES (2 references)
target prot opt source destination
KUBE-MARK-MASQ all -- !10.233.64.0/18 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
......
Chain KUBE-NODE-PORT (1 references)
target prot opt source destination
KUBE-MARK-MASQ tcp -- 0.0.0.0/0 0.0.0.0/0 /* Kubernetes nodeport TCP port for masquerade purpose */ match-set KUBE-NODE-PORT-TCP dst
.....
在这里我们可以看到一条链 PREROUTING ➡️ KUBE-SERVICES ➡️ KUBE-NODE-PORT
KUBE-NODE-PORT
链条的内容解析如下
- 链名称:
。KUBE-NODE-PORT
- 目标:
,表示如果规则匹配成功,则执行名为KUBE-MARK-MASQ
的目标规则。KUBE-MARK-MASQ
- 协议:
,表示该规则仅处理 TCP 协议的流量。tcp
- 源地址 (
):source
,表示任何源地址都会被匹配。0.0.0.0/0
- 目标地址 (
):destination
,表示任何目标地址都会被匹配。0.0.0.0/0
- 注释 (
):对该规则的简要说明,用于标识该规则的用途。/* Kubernetes nodeport TCP port for masquerade purpose */
该规则使用了
match-set
来匹配集合
KUBE-NODE-PORT-TCP
中的目标端口(NodePort)。当外部请求到达 NodePort 时,该规则会将流量标记为
KUBE-MARK-MASQ
,以便进行后续的
MASQUERADE
处理。
在 Kubernetes 中,是一个
KUBE-MARK-MASQ
链的标记,它用于标记要进行源地址转换(
iptables
)的数据包。
MASQUERADE
是一种
MASQUERADE
Network Address Translation (NAT)
技术,它允许修改数据包的源 IP 地址,以便返回的数据包能够正确返回给发起请求的客户端。
具体来说,当请求从 Kubernetes 集群中的
(服务暴露在宿主机上的端口)到达时,
NodePort
链的规则会匹配该请求,并将其标记为
KUBE-NODE-PORT
。然后,
KUBE-MARK-MASQ
链的规则将对这些标记的数据包进行
KUBE-MARK-MASQ
MASQUERADE
处理,将它们的源 IP 地址替换为宿主机的 IP 地址,以确保响应的数据包能够正确返回到请求的客户端。
这个过程确保了外部请求能够正确路由到
集群中的
Kubernetes
和
Service
,并在返回时正确返回给请求的客户端。这是实现
Pod
的
Kubernetes Service
类型所必需的一部分。
NodePort
既然使用了
march-set
,我们不妨先看看
ipset
[root@openeuler-controlplane-jtzv-0 ~]# ipset list |grep KUBE-NODE-PORT-TCP -A 12
Name: KUBE-NODE-PORT-TCP
Type: bitmap:port
Revision: 3
Header: range 0-65535
Size in memory: 8296
References: 1
Number of entries: 4
Members:
30000
30090
31037
31428
可以看到我们的目标
NodePort(31037)
工作在
ipvs
链(内核空间)利用
input
(用户空间)定义的转发规则对数据包进行校验,或者说此时
ipvsadm
链不再生效了,
INPUT
会拦截进入本机的数据包,并根据负载均衡的规则将其转发给后端的真实服务器(
IPVS
)处理
Real Server
我们可以通过
ipvsadm -S -n
映射内容,到这一步基本就已经知道原因了,可以看到你的
NodeIP:NodePort
映射到
PodIP
,往下分析无非就是走完这个链条,本篇文章就不再展开赘述了。