说明:本文由 Codex 根据作者提供的主题、素材与公开资料辅助生成,属于 AI 生成/整理内容,非作者原创。请读者自行甄别并交叉验证。
先说结论#
PREROUTING、FORWARD、POSTROUTING 是 Linux netfilter/iptables 处理数据包时常见的链。
可以先这样记:
PREROUTING:刚进机器,路由决策之前;
FORWARD:不是发给本机,而是要从本机转发出去;
POSTROUTING:即将离开机器,路由决策之后。一条转发流量大致会经过:
网卡收到包
↓
PREROUTING
↓
路由决策
↓
FORWARD
↓
POSTROUTING
↓
网卡发出包这三个链常用于理解:
- Linux 网关。
- NAT。
- Docker 端口映射。
- Kubernetes kube-proxy iptables 模式。
- Pod 跨节点访问。
- Service ClusterIP 转发。
表和链#
iptables 里有两个容易混淆的概念:
table:按用途分类的规则集合;
chain:数据包在某个时机经过的规则列表。常见 table:
| table | 作用 |
|---|---|
filter | 过滤流量,决定 ACCEPT / DROP |
nat | 地址转换,做 DNAT / SNAT / MASQUERADE |
mangle | 修改包标记、TTL 等更细节属性 |
raw | 连接跟踪前的特殊处理 |
security | SELinux 等安全标记相关处理 |
常见 chain:
| chain | 大致时机 |
|---|---|
PREROUTING | 包进入后,路由判断前 |
INPUT | 目标是本机进程 |
FORWARD | 目标不是本机,要转发 |
OUTPUT | 本机进程发出的包 |
POSTROUTING | 包离开前 |
不是每张 table 都有所有 chain。
例如:
filter表常见INPUT、FORWARD、OUTPUT。nat表常见PREROUTING、INPUT、OUTPUT、POSTROUTING。mangle表覆盖更多链。
三类路径#
理解 iptables 链,先把包分成三类。
访问本机#
例如外部访问本机 22 端口:
外部机器
↓
本机网卡
↓
PREROUTING
↓
路由判断:目标是本机
↓
INPUT
↓
sshd这类流量重点看:
PREROUTING:是否做 DNAT。INPUT:是否允许进入本机进程。
本机发出#
例如本机执行 curl https://example.com:
本机进程
↓
OUTPUT
↓
路由判断
↓
POSTROUTING
↓
网卡发出这类流量重点看:
OUTPUT:本机出站规则。POSTROUTING:是否做 SNAT/MASQUERADE。
本机转发#
例如 Linux 主机作为网关,或 Kubernetes Node 转发 Pod 流量:
源机器 / Pod
↓
进入本机网卡
↓
PREROUTING
↓
路由判断:目标不是本机
↓
FORWARD
↓
POSTROUTING
↓
发往下一跳这类流量重点看:
PREROUTING:目标地址是否被改写。FORWARD:内核是否允许转发。POSTROUTING:源地址是否被改写。
PREROUTING#
PREROUTING 的位置很早。
包刚进入机器,还没有做最终路由决策时,就会经过它。
典型用途是 DNAT:
把目标地址 / 目标端口改掉。例如把访问本机公网 80 端口的流量转到内网某台机器:
iptables -t nat -A PREROUTING \
-p tcp --dport 80 \
-j DNAT --to-destination 10.0.0.10:8080含义是:
如果进入本机的 TCP 包目标端口是 80;
在路由决策前,把目标改成 10.0.0.10:8080。为什么要在路由前改?
因为目标地址变了以后,内核才能根据新的目标地址重新决定这个包应该走哪条路。
在 Kubernetes 里,Service ClusterIP 的 DNAT 也常发生在类似路径上:包访问虚拟 IP,规则把目标改成某个后端 Pod IP。
FORWARD#
FORWARD 处理的是“经过本机转发”的包。
判断标准是:
这个包不是发给本机进程;
也不是本机进程发出的;
而是从一个网络接口进入,再从另一个接口出去。例如:
Pod A -> Node -> Pod B
客户端 -> Linux 网关 -> 外部网络
容器 -> 宿主机 -> 外部网络这类流量会经过 FORWARD。
filter 表中的 FORWARD 常用于决定能不能转发:
iptables -A FORWARD -s 10.244.0.0/16 -j ACCEPT
iptables -A FORWARD -j DROP如果 Linux 没开启转发,即使 iptables 放行也不能正常转发。
检查:
sysctl net.ipv4.ip_forward临时开启:
sysctl -w net.ipv4.ip_forward=1持久化通常写入 /etc/sysctl.conf 或 /etc/sysctl.d/*.conf。
POSTROUTING#
POSTROUTING 的位置很晚。
路由已经决定,包即将离开机器时,会经过它。
典型用途是 SNAT 或 MASQUERADE:
把源地址改掉。例如让内网机器通过网关访问外网:
iptables -t nat -A POSTROUTING \
-s 10.0.0.0/24 \
-o eth0 \
-j MASQUERADE含义是:
来自 10.0.0.0/24 的流量;
如果从 eth0 出去;
离开前把源地址伪装成 eth0 的地址。为什么要在路由后改?
因为内核已经知道这个包要从哪个出口出去,这时才能根据出口地址做合适的源地址转换。
在 Kubernetes 里,Pod 访问集群外部地址时,如果外部网络不知道 Pod CIDR 的回程路由,节点可能需要对 Pod 源地址做 SNAT/MASQUERADE。
DNAT 和 SNAT#
PREROUTING 常见 DNAT。
改目标地址:你本来要去 A,现在改去 B。POSTROUTING 常见 SNAT。
改源地址:你本来来自 A,现在看起来来自 B。可以这样记:
| NAT 类型 | 常见链 | 修改内容 | 典型场景 |
|---|---|---|---|
| DNAT | PREROUTING | 目标地址/端口 | 端口转发、Service 转后端 |
| SNAT | POSTROUTING | 源地址/端口 | 内网出公网、Pod 出集群 |
| MASQUERADE | POSTROUTING | 动态 SNAT | 出口 IP 可能变化的场景 |
NAT 通常只在连接创建时决定转换关系,后续数据包依赖 conntrack 记住映射。
和路由表的关系#
iptables 和路由表不是一回事。
路由表回答:
这个包应该从哪个接口出去,下一跳是谁?iptables 回答:
这个包是否允许?
是否要修改源地址或目标地址?
是否要打标记?一个转发包的关键顺序是:
PREROUTING
↓
路由决策
↓
FORWARD
↓
POSTROUTING这也是为什么:
- 目标地址转换通常在路由前做。
- 源地址转换通常在路由后做。
- FORWARD 只处理被路由转发的包。
Kubernetes 中的典型场景#
iptables 在 Kubernetes 中最常见于以下位置:
- kube-proxy 的 iptables 数据面。
- Service ClusterIP 或 NodePort 到 Endpoint Pod IP 的 DNAT。
- Pod 访问集群外部网络时的 SNAT / MASQUERADE。
- CNI 安装的转发、隔离和 NAT 规则。
先确认集群实际使用的数据面。iptables、IPVS、nftables 和 eBPF 都可能承担 Service 转发职责;VXLAN、IPIP、WireGuard 等 CNI 封装也会改变跨节点路径。KUBE-SERVICES、KUBE-SVC-*、KUBE-SEP-* 只是 kube-proxy iptables 模式中常见的链名,不能把它们当作每个集群都必然存在的前提。
Service 流量#
以 kube-proxy 的 iptables 模式为例,访问 ClusterIP 或 NodePort 的报文会匹配 Service 规则,选择一个 Endpoint,并把目标改写为该 Endpoint 的 PodIP:targetPort。改写之后,内核再按 Pod IP 选择路由:目标 Pod 在本机时交给本机 veth;在远端时则交给 CNI 配置的路由或隧道。
客户端或 Pod
↓
nat/PREROUTING(本机进程发起时通常是 nat/OUTPUT)
↓
Service 规则选择 Endpoint,并 DNAT 到 PodIP:targetPort
↓
基于 PodIP 的路由、FORWARD 与必要的封装
↓
目标 Pod常见 Kubernetes 路径对照#
| 场景 | 典型流转路径 | 优先排查 |
|---|---|---|
| Pod 访问 ClusterIP | Pod veth → PREROUTING → Service 规则与 DNAT → 路由到后端 Pod | Service、EndpointSlice、kube-proxy 或 eBPF 数据面 |
| 节点本机进程访问 ClusterIP | OUTPUT → Service 规则与 DNAT → POSTROUTING | nat/OUTPUT,而不是 PREROUTING |
| 外部客户端访问 NodePort | eth0 → PREROUTING → Service 规则与 DNAT → FORWARD → Pod | NodePort 规则、EndpointSlice、FORWARD、回程 SNAT 策略 |
| Pod 访问互联网 | Pod veth → PREROUTING → FORWARD → POSTROUTING → eth0 | Pod CIDR 路由、FORWARD、MASQUERADE |
这些都是便于理解的典型路径。Pod 是否与源端同节点、CNI 是否使用隧道、externalTrafficPolicy、kube-proxy 模式和节点防火墙规则都会影响实际细节。
Pod 出网时,CNI 或节点网络配置通常会在 POSTROUTING 做 MASQUERADE,使外部网络只需把响应返回给 Node IP。不要把“Pod 出网一定由 kube-proxy 做 SNAT”当作通用结论;CNI、Pod CIDR 的路由方式、Service 配置和节点网络策略都会参与决定。
常用查看命令#
查看 filter 表:
iptables -L -n -v
iptables -S查看 nat 表:
iptables -t nat -L -n -v
iptables -t nat -S保存完整规则:
iptables-save
iptables-save -t nat查看路由:
ip route
ip rule查看连接跟踪:
conntrack -L
conntrack -L -p tcp抓包:
tcpdump -ni any host 10.0.0.10
tcpdump -ni eth0 tcp port 80排查时建议同时看:
iptables 规则
路由表
sysctl 转发开关
conntrack
tcpdump只看其中一个,很容易误判。
Kubernetes Service 排查顺序#
Service 请求异常时,先确认 API 对象和节点数据面是否都符合预期,再逐段追包:
# 1. Service 是否有可用后端
kubectl get svc -A
kubectl get endpointslice -A
# 2. 节点上由谁实现 Service 数据面
kubectl -n kube-system get ds kube-proxy
kubectl -n kube-system logs ds/kube-proxy
# 3. 确认 DNAT 后到目标 Pod IP 的路由和转发条件
ip route get <pod-ip>
sysctl net.ipv4.ip_forward
iptables -t nat -L PREROUTING -n -v --line-numbers
iptables -L FORWARD -n -v --line-numbers
iptables -t nat -L POSTROUTING -n -v --line-numbers若节点使用 iptables-nft 兼容层,iptables 命令仍可能可用,但底层规则由 nftables 管理;必要时同时检查:
nft list ruleset
conntrack -L
tcpdump -ni any host <pod-ip>检查应分别在源节点和目标节点进行。看到 Service 已 DNAT 到 Pod IP 只能证明前半段规则命中;后续的路由、FORWARD、CNI 封装、NetworkPolicy 与回程 NAT 仍可能使请求失败。
常见误区#
PREROUTING 只影响转发流量#
不准确。
进入本机的包也会先经过 PREROUTING,然后再由路由判断是进入 INPUT 还是 FORWARD。
FORWARD 会处理本机访问外部的包#
不会。
本机进程发出的包走 OUTPUT 和 POSTROUTING,不走 FORWARD。
POSTROUTING 只能做 SNAT#
POSTROUTING 常用于 SNAT/MASQUERADE,但它属于链的位置,不等于只能做一个动作。不同 table 和 target 能做的事由内核模块和 iptables 扩展决定。
iptables 负责选路#
iptables 可以修改包、过滤包、打标记,但真正决定下一跳的是路由系统。
有些高级场景会通过 mark 配合 policy routing,但那仍然是 iptables 和路由表协作。
看到 Kubernetes Service 的 DNAT 后就说明链路已通#
不成立。DNAT 只改写目标地址;后续仍可能因为 Pod 路由错误、FORWARD 拦截、CNI 封装、网络策略,或回程 SNAT 配置不当而失败。
所有 Kubernetes 集群都有 KUBE-* 链#
不成立。先确认 kube-proxy 的模式以及 CNI 类型。iptables、IPVS、nftables 或 eBPF 都可能实现 Service 数据面,实际规则与排查入口会不同。
节点本机访问 ClusterIP 也应该只看 PREROUTING#
不一定。本机进程发起的流量通常会走 OUTPUT;排查节点本机访问 Service 时,要检查 nat/OUTPUT,而不是只看 nat/PREROUTING。
小结#
三条链可以这样收束:
PREROUTING:进来先看,常做 DNAT;
FORWARD:路由后发现不是给本机,检查是否允许转发;
POSTROUTING:出去前看,常做 SNAT/MASQUERADE。排查网络时,先判断数据包属于哪类路径:
访问本机:PREROUTING -> INPUT
本机发出:OUTPUT -> POSTROUTING
经过本机转发:PREROUTING -> FORWARD -> POSTROUTING路径判断对了,再看具体 table 和规则,问题会清楚很多。