AI Infra 训练营
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub

iptables —— Linux 内核包过滤 / NAT 规则

一句话定义

iptables 是 Linux 内核网络框架 netfilter 的用户态配置工具。所有进出本机的数据包都会经过 netfilter 钩子;iptables 决定怎么过滤、转发、NAT、改写这些包。K8s 的 kube-proxy 默认用 iptables 实现 service —— 你要看懂"为什么 ClusterIP 能通到 pod",必须看懂 iptables 链。

典型场景

训练营文档里 iptables 出场 42 次,主要在:

  • 看 kube-proxy 生成的规则:iptables -t nat -L KUBE-SERVICES
  • 排查 NodePort / ClusterIP 不通:链路追踪
  • 集群清理:iptables -F && iptables -t nat -F
  • 防火墙基础:放行/禁止端口

现代发行版正在迁移到 nftables(iptables-nft),命令兼容、底层不同。但 K8s 1.31 之前仍以 iptables 模式为主,所以这篇内容仍然适用。


心智模型:5 个表 / 5 条链 / 链路顺序

表(table)—— 干啥用

表用途你需要懂
filter包过滤(接受 / 拒绝)✅ 必懂
nat地址转换(DNAT / SNAT)✅ K8s service 全靠它
mangle改包头(TTL / TOS / mark)看懂就行
raw跳过 conntrack性能调优
securitySELinux / MAC几乎不用

-t <table> 指定表,不指定默认是 filter。

链(chain)—— 什么时候跑

链时机
PREROUTING包刚到,路由决策之前
INPUT路由后,发往本机的包
FORWARD路由后,要转发出去的包
OUTPUT本机产生的包
POSTROUTING出去之前,路由决策之后

不是所有表都有所有链:

PREROUTINGINPUTFORWARDOUTPUTPOSTROUTING
filter✓✓✓
nat✓✓✓✓
mangle✓✓✓✓✓

数据包流动路径

入站包(发给本机):

网卡 → raw PREROUTING → mangle PREROUTING → nat PREROUTING → 路由决策
                                                              │
                                                              ├─发给本机→ mangle INPUT → filter INPUT → nat INPUT → 本地进程
                                                              │
                                                              └─转发→ mangle FORWARD → filter FORWARD → mangle POSTROUTING → nat POSTROUTING → 网卡

出站包(本机发起):

本地进程 → raw OUTPUT → mangle OUTPUT → nat OUTPUT → filter OUTPUT → mangle POSTROUTING → nat POSTROUTING → 网卡

不需要背 —— 但要知道:DNAT 在 PREROUTING,SNAT 在 POSTROUTING。这就是为什么 K8s 的 KUBE-SERVICES 主要挂在 nat 表的 PREROUTING 和 OUTPUT。


最常用命令(90% 用法)

iptables -L                                   # 列 filter 表所有规则
iptables -L -n -v                             # -n 不解析名字、-v 含计数
iptables -L INPUT -n -v --line-numbers        # 看 INPUT 链,加行号
iptables -t nat -L                            # 看 nat 表
iptables -t nat -L KUBE-SERVICES -n           # 看 K8s 那条
iptables -S                                   # 以"可重放"的命令形式列出
iptables -S KUBE-SERVICES                      # 单链
flag含义
-L [chain]列出规则
-S [chain]以命令形式列出(复制粘贴友好)
-t <table>指定表(默认 filter)
-n不解析 IP / port 名字(必加,否则慢)
-v含字节 / 包计数
--line-numbers加行号(删特定规则时要)

记住 -t nat -L -n -v --line-numbers 这套组合:K8s 排错最常用。


添加 / 删除规则

# 添加:放行 8080 端口
iptables -A INPUT -p tcp --dport 8080 -j ACCEPT

# 添加到指定位置:放在第 1 行
iptables -I INPUT 1 -p tcp --dport 8080 -j ACCEPT

# 删除:按内容
iptables -D INPUT -p tcp --dport 8080 -j ACCEPT

# 删除:按行号
iptables -D INPUT 3                           # 删第 3 条规则

# 清空一整条链
iptables -F INPUT                             # flush

# 清空所有规则
iptables -F                                   # filter 表所有链
iptables -t nat -F
iptables -t mangle -F
iptables -X                                   # 删自定义链

-A (append) / -I (insert) / -D (delete) / -F (flush) / -X (delete custom chain) / -N (new chain)。


常用 match 条件

-p tcp / udp / icmp                           # 协议
-s <src> / -d <dst>                           # 源/目的 IP(含 CIDR)
--sport <port> / --dport <port>               # 源/目的端口
-i <iface> / -o <iface>                       # 入/出网卡
-m state --state ESTABLISHED,RELATED          # 连接状态(依赖 conntrack)
-m conntrack --ctstate ESTABLISHED            # 新写法
-m multiport --dports 80,443,8080             # 多端口
-m mark --mark 0x1                            # 含 mark

-j 跳转(action)

目标含义
ACCEPT接受
DROP丢弃(对方不知道,体现为超时)
REJECT拒绝(发 ICMP unreachable,对方立刻知道)
LOG记日志(dmesg 里看)
RETURN从子链返回上一层
DNAT --to-destination IP:port目的 NAT(改目标 IP)
SNAT --to-source IP源 NAT
MASQUERADE动态 SNAT(出口 IP 自动选)
自定义链名跳到自定义链

K8s 视角:看 kube-proxy 生成的链

K8s 把 kube-proxy 创建的规则分成几条"主链":

filter 表:
  KUBE-EXTERNAL-SERVICES   ←  external service
  KUBE-FIREWALL            ←  内部防火墙
  KUBE-FORWARD             ←  pod 转发策略
  KUBE-NODEPORTS           ←  NodePort 入口

nat 表:
  KUBE-SERVICES            ←  所有 service 的入口(最重要)
  KUBE-NODEPORTS           ←  NodePort 服务
  KUBE-MARK-MASQ           ←  打标记给后续 SNAT
  KUBE-POSTROUTING         ←  做 SNAT
  KUBE-SVC-XXXXX           ←  每个 service 一条
  KUBE-SEP-XXXXX           ←  每个 endpoint 一条

看一个 service 怎么走

# 找你的 service
kubectl get svc -A | grep myapp
# default  myapp  ClusterIP  10.96.1.5  ...  80/TCP

# 在节点上看 nat 表 KUBE-SERVICES 链
iptables -t nat -L KUBE-SERVICES -n | grep 10.96.1.5
# Chain KUBE-SERVICES (2 references)
# target              prot opt source  destination
# KUBE-SVC-MYAPP123   tcp  --  0.0.0.0/0  10.96.1.5  /* default/myapp:http cluster IP */ tcp dpt:80

# 跳到那个 svc 链
iptables -t nat -L KUBE-SVC-MYAPP123 -n
# KUBE-SEP-EP1   ...  /* probability 0.3333 */
# KUBE-SEP-EP2   ...  /* probability 0.5 */
# KUBE-SEP-EP3   ...  /* */

# 看一个 endpoint 链
iptables -t nat -L KUBE-SEP-EP1 -n
# DNAT  tcp  ...  to:10.244.1.5:8080

ClusterIP 通信流程:

  1. pod 发请求到 10.96.1.5:80
  2. 包经 nat PREROUTING → 进 KUBE-SERVICES 链
  3. 匹配 KUBE-SVC-MYAPP123 子链
  4. 随机选一个 endpoint(用 statistic match probability)
  5. 跳进 KUBE-SEP-EPx 子链
  6. DNAT 改目的 IP 到 10.244.1.5:8080(真实 pod IP)
  7. 路由表把包发到那个 pod

排查 ClusterIP 不通:沿这条链查规则在不在、计数有没有递增。

iptables -t nat -L KUBE-SERVICES -n -v | grep myapp
# 看 pkts 列:每次有人访问 ClusterIP 应该递增
# 不递增 = kube-proxy 没生成规则、或者 service selector / endpoint 有问题

NodePort 怎么走

iptables -t nat -L KUBE-NODEPORTS -n
# KUBE-EXT-MYAPP123  tcp  ...  tcp dpt:30080

30080 是 NodePort,进来后跳到 KUBE-EXT-MYAPP123 → 走和 ClusterIP 一样的链。

外部访问 <node-ip>:30080 通:

  1. 包到 PREROUTING
  2. 进 NodePorts 链
  3. DNAT 到某 pod IP
  4. 包出去(也可能要 SNAT)

conntrack(连接追踪)—— iptables 的"记忆"

# 看 conntrack 表
cat /proc/net/nf_conntrack | head
# 或者
apt install conntrack
conntrack -L | head

netfilter 用 conntrack 记忆每个连接的状态。-m state --state ESTABLISHED,RELATED 就是问 conntrack。

排查"连接数耗尽":

cat /proc/sys/net/netfilter/nf_conntrack_count       # 当前连接数
cat /proc/sys/net/netfilter/nf_conntrack_max         # 上限

满了:包被 nf_conntrack: table full, dropping packet(看 dmesg)。

调高:

sysctl -w net.netfilter.nf_conntrack_max=1048576

K8s 节点跑大流量必调。


看规则计数(排查"规则没生效")

iptables -L INPUT -n -v
# pkts bytes target     prot opt in     out     source        destination
# 12345 1.2M  ACCEPT     tcp  --  *      *       0.0.0.0/0     0.0.0.0/0    tcp dpt:22

pkts 是命中这条规则的包数。每次连接进来应该递增。

规则没生效的常见诊断:

# 重置计数
iptables -Z

# 让目标流量跑一会
curl http://node-ip:30080

# 再看计数
iptables -L -n -v | grep 30080
# 如果计数 0 → 规则没匹配到,看规则顺序 / 条件

训练营典型用法

1. 装机审计:看默认规则

iptables -L -n -v
iptables -t nat -L -n -v
# 干净的 Ubuntu 应该几乎没规则(默认 policy ACCEPT)
# 如果 IDC 塞了一堆规则 → 可能干扰 K8s

2. reset 之后清理(Day1 / 故障排查必做)

iptables -F                                   # 清 filter
iptables -X                                   # 删自定义链
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT                      # 重置默认 policy
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

不清 iptables 直接 kubeadm reset 再 init 是 K8s 重装失败的 #1 原因。kube-proxy 第二次 init 时遇到一堆历史规则,行为不可预测。

3. 排查 service 不通

# 1. service 有没有 endpoint
kubectl get endpoints myapp
# 没有 → selector 选不到 pod / pod 没 ready

# 2. iptables 有没有规则
iptables -t nat -L KUBE-SERVICES -n | grep myapp
# 没有 → kube-proxy 出问题、看它日志

# 3. 规则有没有被命中
iptables -t nat -L KUBE-SERVICES -n -v | grep myapp
# pkts 0 → 流量没到这里,路由问题

# 4. DNAT 之后路由
ip route get <pod-ip>
# 不通 → CNI 问题

4. 允许只从特定 IP ssh 进来

iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP

先 ACCEPT、再 DROP(顺序敏感)。否则 DROP 在前 → 谁都连不进。


iptables vs nftables vs IPVS

工具用途性能
iptables老工具规则多时慢(线性查找)
iptables-nft兼容包装,底层是 nftables同上但慢慢被推广
nft (nftables)iptables 继任者更好,但语法不同
IPVS内核 L4 LB规则多时显著快,专为 LB 设计

K8s kube-proxy 支持两种模式:

kubectl get configmap -n kube-system kube-proxy -o yaml | grep mode
# mode: ""           ← 默认 iptables
# mode: "ipvs"       ← IPVS

万级 service 推荐切 IPVS。看 IPVS 用 ipvsadm 而不是 iptables。


持久化 iptables 规则

iptables 规则只在内存,重启就没。要持久:

Ubuntu

apt install iptables-persistent
# 提示是否保存当前规则到 /etc/iptables/rules.v4 和 rules.v6

netfilter-persistent save
netfilter-persistent reload

通用:导出 / 导入

iptables-save > /etc/iptables/rules.v4
iptables-restore < /etc/iptables/rules.v4

但 K8s 节点上 kube-proxy 自己管自己的规则——你不应该手动持久化它的链,否则升级 / reset 出乱。手动加的规则要放在 K8s 之外的链(比如自定义链)。


常见踩坑

坑 1:iptables 命令显示一堆乱七八糟,看不懂

iptables -L
# 一坨 chain,K8s 装完几百条规则

加 -n:

iptables -L -n -v --line-numbers

不加 -n iptables 会反向 DNS / 解析端口名,慢且没用。

坑 2:规则顺序错,DROP 先于 ACCEPT

iptables -A INPUT -j DROP                     # 先 DROP 一切
iptables -A INPUT -p tcp --dport 22 -j ACCEPT # 再放行 22 ← 永远到不了这里

iptables 按顺序匹配,第一个匹配的 -j 就执行了。ACCEPT 放前面 / DROP 放最后。

坑 3:用 iptables -F 顺手把自己锁外面

ssh m1 'iptables -F && iptables -P INPUT DROP'
# ❌ -P INPUT DROP 把默认 policy 设成 DROP,然后 flush 之后没规则放行 22
# 立刻断 ssh,再也连不上

修改 INPUT 链规则之前先:

iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT     # 第 1 行放行 22(救命通道)
# 再做其它修改

并保留物理 console 备份。

坑 4:清不干净 K8s 残留

kubeadm reset
kubeadm init                                  # 失败:iptables 残留规则冲突

reset 不清 iptables。手动:

iptables -F && iptables -t nat -F && iptables -t mangle -F
iptables -X && iptables -t nat -X && iptables -t mangle -X

或者 ipvsadm -C(IPVS 模式)。

坑 5:iptables 规则在但流量不通

可能是 nftables 兼容层 问题。看实际后端:

update-alternatives --display iptables
# /usr/sbin/iptables-nft       ← 现在用 nftables 后端
# /usr/sbin/iptables-legacy    ← 老的

# K8s 1.21+ 推荐 nft 模式
update-alternatives --set iptables /usr/sbin/iptables-nft

部分老组件(calico / flannel 老版本)只认 iptables-legacy,混用就乱套。

坑 6:在节点上看到的规则与 kube-proxy 期望不一致

kube-proxy 是个 daemon,每隔几秒 reconcile 一次规则。如果你手动改了 kube-proxy 的链 —— 几秒后被改回来。

要持久改:去改 kube-proxy 的 configmap、或者在它管不到的链上加。

坑 7:conntrack 表满,连接随机失败

# dmesg
nf_conntrack: table full, dropping packet

调高 net.netfilter.nf_conntrack_max、调短 conntrack timeout。K8s 节点 / Ingress 节点必要的运维项。

坑 8:用 service iptables save (CentOS 6 老语法)

service iptables save                         # ❌ 现代系统不存在这服务

用 iptables-save > file 或 netfilter-persistent save。


关联命令

  • ip —— 看路由 / 网卡
  • ss —— 看监听端口
  • tcpdump —— 抓包验证规则有没有生效
  • nft —— nftables CLI
  • ipvsadm —— IPVS 模式的 LB 规则
  • conntrack —— 看 / 改 conntrack 表
  • iptables-save / iptables-restore —— 备份恢复
在 GitHub 上编辑此页