摘要:沿 Linux 数据包处理路径理解 Netfilter、iptables、DNAT、SNAT 与 conntrack,为分析 Kubernetes Service 转发和容器出口流量建立基础。
这一节继续深入 Linux 内核的数据包处理机制,理解一个 IP 数据包进入 Linux 后,如何经过过滤、地址转换和连接跟踪。
这部分知识与 Kubernetes 网络直接相关:
- kube-proxy 如何通过 iptables 实现 Service 转发。
- 为什么客户端访问 ClusterIP,后端 Pod 收到的目标 IP 却不同。
- 为什么返回流量能够自动恢复正确的地址。
- 为什么连接跟踪表耗尽可能导致网络异常。
- 如何使用
iptables-save、conntrack和tcpdump排查故障。
先记住四个概念:
| 概念 | 主要作用 |
|---|---|
| Netfilter | Linux 内核中的数据包过滤、修改和相关处理框架 |
| iptables | 配置和管理 Netfilter 规则的传统工具 |
| conntrack | 跟踪连接及其流量状态 |
| NAT | 修改数据包的源地址或目标地址等信息 |
一、Netfilter:Linux 内核的数据包处理框架
Linux 收到一个数据包之后,并不是直接把它交给应用程序。数据包可能经过路由判断、过滤规则、NAT 规则等多个处理阶段。
例如,客户端向服务器发起 TCP 请求:
flowchart TB
N0["客户端"]
N1["Linux 网卡"]
N2["内核网络协议栈"]
N3["Netfilter 相关处理点"]
N4["交给本地应用"]
N5["继续转发"]
N0 --> N1
N1 --> N2
N2 --> N3
N3 -->|"路由到本机"| N4
N3 -->|"路由到其他主机"| N5
Netfilter 是内核提供的基础设施。iptables 则是一种配置规则的用户空间工具。
因此,二者不是同一个东西:
- Netfilter 是内核中的数据包处理框架。
- iptables 是配置相关规则的工具之一。
- nftables 是较新的规则管理接口。
- conntrack 是连接跟踪机制,可供 NAT 和过滤规则等功能使用。
二、数据包经过哪些处理点?
在传统 IPv4 Netfilter 路径中,最常见的五个钩子是:
PREROUTINGINPUTFORWARDOUTPUTPOSTROUTING
其中,前三个方向判断与路由选择的关系尤其重要。
flowchart TB
N0["数据包进入网卡"]
N1["PREROUTING<br/>可能执行 DNAT 等处理"]
N2["路由判断<br/>判断目标是本机还是其他主机"]
N3["INPUT<br/>交给本机应用"]
N4["FORWARD<br/>转发到其他主机"]
N5["POSTROUTING<br/>可能执行 SNAT 或 MASQUERADE"]
N0 --> N1
N1 --> N2
N2 -->|"目标是本机"| N3
N2 -->|"目标是其他主机"| N4
N4 --> N5
上图是便于学习的简化路径。实际处理还涉及路由缓存、连接跟踪、过滤规则、策略路由以及内核版本和网络配置等因素。
五个钩子分别有什么作用?
| 钩子 | 典型用途 |
|---|---|
PREROUTING | 在常规路由决策前处理进入本机的包,例如 DNAT |
INPUT | 处理最终交给本机的包 |
FORWARD | 处理经本机转发的包 |
OUTPUT | 处理本机进程产生的包 |
POSTROUTING | 在常规路由决策后、发出接口之前处理包,例如 SNAT |
一个容易考的区别是:
访问本机服务与经过本机转发,是两条不同的处理路径。
如果目标是本机应用,通常会经过 INPUT;如果目标是其他主机,且本机负责转发,则通常会经过 FORWARD。
三、iptables:如何组织过滤和 NAT 规则?
iptables 使用“表(table)”和“链(chain)”组织规则。
常见的表包括:
| 表 | 主要用途 |
|---|---|
filter | 允许或拒绝数据包 |
nat | 配置地址转换规则 |
mangle | 修改特定数据包字段或设置相关标记 |
raw | 控制连接跟踪等特定处理行为 |
在传统 iptables 配置中,filter 表常用 INPUT、FORWARD、OUTPUT 链;nat 表常用 PREROUTING、OUTPUT、POSTROUTING 链。
查看当前规则:
sudo iptables -L -n -vsudo iptables -t nat -L -n -vsudo iptables-save参数含义:
-L:列出规则。-n:不将地址和端口转换为名称。-v:显示详细信息及数据包计数。-t nat:指定 NAT 表。iptables-save:输出当前规则配置。
注意:部分 Linux 系统中的 iptables 使用 nf_tables 后端。Kubernetes 也可能使用 nftables 或 eBPF 数据面,所以不能认为所有集群的规则都一定能在传统 KUBE-* 链中找到。
规则是如何匹配的?
例如:
sudo iptables -A INPUT \ -p tcp --dport 8080 -j ACCEPT这条规则表示:匹配进入本机、协议为 TCP、目标端口为 8080 的数据包,并执行 ACCEPT。
几个常见参数:
-A:追加规则。-p tcp:匹配 TCP。--dport 8080:匹配目标端口。-j ACCEPT:允许匹配的数据包。
但这条命令只是在 INPUT 链中添加规则。如果数据包走的是 FORWARD 路径,这条规则并不会因此自动允许转发流量。
生产环境不要随意修改防火墙规则,尤其不要清空 Kubernetes 自动维护的规则链,否则可能造成业务中断。
四、NAT:为什么数据包的 IP 地址会变化?
NAT(Network Address Translation,网络地址转换)主要用于修改 IP 数据包的源地址或目标地址。
最重要的两种类型是:
- DNAT:修改目标地址。
- SNAT:修改源地址。
1. DNAT:目标地址转换
假设有一个 Kubernetes Service:
Service ClusterIP:10.96.120.30:8080后端 Pod:10.244.2.20:80客户端访问:
curl http://10.96.120.30:8080在采用传统 iptables Service 数据面的场景中,数据包可能经过 DNAT:
flowchart TB
N0["转换前<br/>源:10.244.1.10:40000<br/>目标:10.96.120.30:8080"]
N1["DNAT<br/>修改目标 IP 和目标端口"]
N2["转换后<br/>源:10.244.1.10:40000<br/>目标:10.244.2.20:80"]
N0 --> N1
N1 --> N2
在这个示例中,源地址保持不变,目标地址被改为实际后端 Pod 的地址。
可以通过以下命令理解 DNAT 的基本用法:
sudo iptables -t nat -A PREROUTING \ -p tcp -d 192.0.2.10 --dport 8080 \ -j DNAT --to-destination 10.10.1.20:80这是一个原理示例,使用的是文档示例地址,不应直接照搬到生产环境。它只演示地址转换,不保证路由、转发策略和返回路径已经配置正确。
2. SNAT:源地址转换
SNAT 用于修改数据包的源地址。
例如,多个 Pod 访问外部网络时,节点可能需要将 Pod 的源 IP 转换为节点 IP:
flowchart LR
subgraph G0["转换前"]
direction LR
N0["10.244.1.10"]
N1["203.0.113.20"]
end
subgraph G1["转换后"]
direction LR
N2["192.168.1.10"]
N3["203.0.113.20"]
end
N0 --> N1
N2 --> N3
外部网络看到的是节点地址,而不是原始 Pod 地址。
一种常见规则形式是:
sudo iptables -t nat -A POSTROUTING \ -s 10.244.0.0/16 -o eth0 \ -j MASQUERADEMASQUERADE 可以根据出口接口地址执行动态源地址伪装。实际集群是否需要这种规则,取决于 CNI、出口网络和现有 NAT 配置。
不要在 Kubernetes 节点上未经分析就添加或修改 SNAT 规则。 不正确的源地址转换可能破坏访问控制、连接追踪和返回路径。
五、conntrack:Linux 如何记住一条连接?
如果只有 NAT 规则,还需要解决一个问题:
客户端访问 Service 时,目标地址被改成了后端 Pod IP。等后端返回数据时,Linux 怎么知道应该把响应转换回原来的 Service 地址?
这就涉及连接跟踪(Connection Tracking,简称 conntrack)。
conntrack 会跟踪网络流量的连接信息,并为 NAT 等机制提供连接状态关联。
例如:
flowchart TB
N0["客户端<br/>10.244.1.10:40000"]
N1["Service<br/>10.96.120.30:8080"]
N2["后端 Pod<br/>10.244.2.20:80"]
N0 --> N1
N1 -->|"DNAT"| N2
响应返回时,内核根据已建立的连接跟踪状态进行相应的反向地址转换,使客户端看到的响应仍然属于原来的 Service 连接。
可以把 conntrack 理解为:内核保存了这条连接的相关状态,因此不必对返回流量重新执行一次独立的后端选择。
如何查看连接跟踪信息?
如果系统安装了 conntrack 工具:
sudo conntrack -L只查看 TCP 连接:
sudo conntrack -L -p tcp查看连接跟踪事件:
sudo conntrack -E输出中可能包含:
- 原始方向的源、目标地址和端口。
- 返回方向的源、目标地址和端口。
- TCP 连接状态。
- 连接跟踪条目的超时信息。
不同版本的工具输出格式可能不同。即使一个 TCP 连接还没有完全建立,也可能已经存在相应的 conntrack 条目。
为什么 conntrack 会影响 Kubernetes 网络?
如果连接跟踪资源不足,或者连接状态异常,可能出现新连接失败、部分连接超时等问题。
常见检查:
sysctl net.netfilter.nf_conntrack_countsysctl net.netfilter.nf_conntrack_max第一个值表示当前连接跟踪条目数量,第二个值表示最大条目数。
不要仅仅因为当前数量接近上限就盲目调大参数。还应检查连接创建速率、连接生命周期、NAT 负载和内核日志,确认是否确实发生了连接跟踪耗尽。
六、把 Netfilter、NAT 和 conntrack 串起来
我们用一次访问 Kubernetes Service 的请求来总结。
假设客户端访问:
10.96.120.30:8080后端是:
10.244.2.20:80在典型的传统 iptables Service 数据面中:
- 客户端发送请求。
- 数据包进入节点的网络处理路径。
- Netfilter 相关规则匹配 Service 转发规则。
- DNAT 将目标地址改为后端 Pod 地址。
- 路由和 CNI 将数据包发送到目标 Pod。
- 后端返回响应。
- conntrack 关联原始连接并支持反向 NAT。
- 客户端收到与原始 Service 连接相对应的响应。
这是一条帮助理解的逻辑链路。实际执行顺序和处理点会随流量来源、是否跨节点、CNI、Service 实现和内核配置而变化。
如果集群使用 Cilium 的 eBPF Service 数据面,则可能不经过传统的 kube-proxy iptables 规则,因此排障时必须先确认实际的数据面实现。
七、本节总结
本节需要记住:
- Netfilter:Linux 内核的数据包处理框架。
- iptables:配置过滤与 NAT 规则的传统工具。
- DNAT:修改目标地址,常用于 Service 流量转发。
- SNAT/MASQUERADE:修改源地址,常用于出口流量处理。
- conntrack:跟踪连接状态,为双向流量和 NAT 提供关联。