
从K8s故障排查到iptables深度解析:手把手教你玩转Linux防火墙规则
背景
在昨日处理一起Kubernetes集群故障时,技术团队遭遇典型挑战:
某工作节点通过NodePort方式访问集群服务时出现连接失败现象。
历经数小时深入排查,最终锁定故障根源为节点防火墙规则集异常配置。
此次排障过程充分暴露了传统iptables命令行工具在复杂场景下的局限性,并催生了可视化诊断工具的诞生。
iptables基础知识
四表五链
四表:
- • filter: 过滤数据包,用于防火墙规则。
- • nat: 网络地址转换,用于修改数据包的源或目的IP地址。
- • mangle: 数据包内容修改,用于修改数据包的内容或者优先级等。
- • raw: 控制不经过连接跟踪的数据包处理方式。
五链(chain):
- • PREROUTING: 对于目标地址是本机的数据包的处理;
- • INPUT: 对于进入本机并被路由到本地的数据包的处理;
- • FORWARD: 对于所有转发出去的数据包的处理;
- • OUTPUT: 对于本地产生的向外发送的数据包的处理;
- • POSTROUTING: 对于离开本机的数据包的处理。
默认的四表的顺序为:raw -> mangle -> nat -> filter
简记为:rmnf–>制导(五笔编码)


▌入站路由前阶段(PREROUTING)
外部流量进入 → ├─ raw表(优先级1):处理连接跟踪例外 ├─ mangle表(优先级2):修改TOS/TTL等包头 └─ nat表(优先级3):执行DNAT目标地址转换 顺序为:123
▌路由决策阶段
根据路由表判断走向 → ├─ 本机处理分支 → INPUT链 │ ├─ mangle表(优先级2):最终包标记调整 # 有一种说法是NAT表在INPUT链中也执行 │ └─ filter表(优先级4):实施入站过滤策略 │ 顺序为:234 │ └─ 转发处理分支 → FORWARD链 ├─ mangle表(优先级2):支持复杂包修改 └─ filter表(优先级4):定义转发策略(默认拒绝) 顺序为24
▌本机外发阶段(OUTPUT)
本地进程产生流量 → ├─ raw表(优先级1):出站连接跟踪例外 ├─ mangle表(优先级2):修改出站包头 ├─ nat表(优先级3):执行SNAT源地址转换 └─ filter表(优先级4):最终出站过滤 顺序为1234
▌出站路由后阶段(POSTROUTING)
准备离开本机 → ├─ mangle表(优先级2):最后修改机会(如TTL) └─ nat表(优先级3):完成SNAT/MASQUERADE 顺序为23
iptables命令格式
iptables -t 表名 [-A|-D|-F|-L|-Z|-N|-X|-P|-E|-I] 链名 [匹配条件] [-j 处理动作]
- • 表名
- • -t: –table,指定要操作的表。如果不加,默认为filter表。
- • commands
- • -A: –append,向指定的链中追加一条规则。
- • -D: –delete,从指定的链中删除一条规则。
- • -F: –flush,清空指定链的所有规则。
- • -L: –list,列出指定链中的所有规则。
- • -Z: –zero,清空指定链的计数器。
- • -N: –new-chain,创建一条新的链。
- • -X: –delete-chain,删除一条自定义的链。
- • -P: –policy,设置链的默认策略。
- • -E: –rename-chain,重命名一条链。
- • -I: –insert,在指定的链中插入一条规则。
- • 匹配条件
- • -p: –protocol,指定协议类型。 例如,-p tcp表示只匹配TCP协议的数据包。
- • -s: –source,指定源IP地址。例如,-s 192.168.1.100表示只匹配来自该IP的数据包。
- • -d: –destination,指定目的IP地址。例如,-d 192.168.1.100表示只匹配到该IP的数据包。
- • -i: –in-interface,指定进入本机的网络接口。例如,-i eth0表示只匹配通过该接口的数据包。
- • -o: –out-interface,指定离开本机的网络接口。例如,-o eth0表示只匹配通过该接口的数据包。
- • –sport, –sport: 指定源端口。例如,–sport 80表示只匹配来自该端口的TCP数据包。
- • –dport, –dport: 指定目的端口。例如,–dport 80表示只匹配到该端口的TCP数据包。
- • 处理动作
- • -j: –jump,指定处理动作。例如,-j ACCEPT表示接受数据包,-j DROP表示丢弃数据包。-j LOG表示记录日志。-j RETURN表示返回,不再继续匹配后续规则。
iptables常用命令
- • 查看iptables规则
- • 查看所有链的规则(-L不写链是所有链的规则,不加-t是默认filter表)
iptables -L
- • 查看指定表的规则
iptables -t nat -L
- • 查看指定链的规则
iptables -L INPUT
- • 查看指定链的规则编号
iptables -L INPUT --line-numbers
- • 查看指定链的规则编号和计数器
iptables -L INPUT --line-numbers --verbose
- • 查看指定链的规则编号和计数器,并以树状显示
iptables -L INPUT --line-numbers --verbose --list
- • 查看所有链的规则(-L不写链是所有链的规则,不加-t是默认filter表)
脚本
面对海量iptables规则带来的排查困境,传统命令行工具暴露出三大核心缺陷:
- • 信息过载问题:数千条规则以线性文本呈现,链间跳转逻辑难以追溯
- • 语义断裂现象:-j KUBE-SERVICES等目标链缺乏上下文解释
- • 变更风险隐患:直接编辑生产规则易引发服务中断
- 针对以上问题,编写以下脚本,该脚本通过树状可视化与颜色标记,智能检测循环引用,支持交互式选择,兼容多环境,自动清理临时文件,显著提升iptables规则排查效率。
以下脚本仅在centos7.6(3.10.0-957.el7.x86_64)上实验通过。
脚本内容
vim show_iptables.sh #!/bin/bash #脚本用于动态分析指定iptables表的链关系并以树状结构展示 #set-x #定义颜色(兼容更多终端) RED=$'\033[31m' GREEN=$'\033[32m' YELLOW=$'\033[33m' BLUE=$'\033[34m' PURPLE=$'\033[35m' CYAN=$'\033[36m' GRAY=$'\033[90m' NC=$'\033[0m' #临时文件 TEMP_FILE="/tmp/iptables_rules.txt" #全局关联数组(显式声明) declare -A VISITED_CHAINS #获取所有可用表 get_tables() { if [[ -f /proc/net/ip_tables_names ]]; then cat /proc/net/ip_tables_names 2>/dev/null else # 兼容旧系统 iptables -L -n 2>/dev/null | grep -Po 'Table: \K\w+' | sort -u fi } #提取链名(增加过滤) extract_chains() { grep -E "^:[A-Za-z0-9_-]+ " "$TEMP_FILE" | cut -d ' ' -f 1 | tr -d ':' | grep -v '^$' } #获取链的规则(增强过滤) find_rules_for_chain() { local chain=$1 [[ -z "$chain" ]] && return grep -E "^-A $chain " "$TEMP_FILE" | sed '/^#/d' } #提取目标链(严格校验) extract_targets() { local rule=$1 echo "$rule" | grep -oP '\s-(j|g)\s+\K[^\s]+' | grep -E '^[A-Za-z0-9_-]+$' } #规则格式化(防御性处理) format_rule() { local rule=$1 # 移除链声明和注释 rule=$(echo "$rule" | sed -E 's/^-A [^ ]* //; s/(--comment "[^"]*")//g') # 高亮关键元素 echo "$rule" | sed -E \ -e "s/(-j |-g )([^ ]+)/${RED}\1${YELLOW}\2${NC}/g" \ -e "s/(-[pm] |--(src|dport|sport|destination|match))/${CYAN}\1${NC}/g" } #树状打印(关键修复) print_tree() { local chain=$1 local prefix=$2 local visited=$3 local depth=$4 # 空链名防御 if [[ -z "$chain" ]]; then echo -e "${prefix}${RED} 无效空链名${NC}" return fi # 循环检测 if [[ "$visited" == *"|$chain|"* ]]; then echo -e "${prefix}${RED}└── 循环引用: $chain${NC}" return fi # 深度限制 if (( depth > 15 )); then echo -e "${prefix}${YELLOW}└── 达到最大深度${NC}" return fi # 记录访问链(安全写入) if [[ -n "$chain" ]]; then VISITED_CHAINS["$chain"]=1 fi # 获取规则 local rules=() while IFS= read -r rule; do rules+=("$rule") done <<< "$(find_rules_for_chain "$chain")" # 提取子链 local targets=() for rule in "${rules[@]}"; do while IFS= read -r target; do if [[ -n "$target" && ! " ${targets[*]} " =~ " $target " ]]; then targets+=("$target") fi done <<< "$(extract_targets "$rule")" done # 打印当前链 local color case $((depth % 6)) in 0) color=$BLUE;; 1) color=$GREEN;; 2) color=$PURPLE;; 3) color=$CYAN;; 4) color=$YELLOW;; *) color=$RED;; esac echo -e "${prefix}${color}├── ${chain}${NC}" # 打印规则 local rule_prefix="│ " for rule in "${rules[@]}"; do echo -e "${prefix}${rule_prefix}${GRAY}├─ ▪ ${NC}$(format_rule "$rule")" done # 打印子链 local total=${#targets[@]} for i in "${!targets[@]}"; do local target=${targets[$i]} if (( i == total - 1 )); then print_tree "$target" "${prefix} └── " "${visited}|$chain|" $((depth + 1)) else print_tree "$target" "${prefix} ├── " "${visited}|$chain|" $((depth + 1)) fi done } #主程序 main() { echo -e "${GREEN}■ iptables链关系拓扑 (规则内联显示) ■${NC}" echo -e "${YELLOW}说明:" echo -e " ${GRAY}▪ 灰色条目为规则${NC}" echo -e " ${RED}红色${NC}表示跳转目标" echo -e " ${CYAN}青色${NC}表示匹配条件\n" echo -e "${BLUE}▏ 链 [${selected_chain}] 拓扑:${NC}" print_tree "$selected_chain" "" "" 0 echo "" } #执行流程 #1. 选择表 tables=($(get_tables)) if [[ ${#tables[@]} -eq 0 ]]; then echo -e "${RED} 错误:未找到任何iptables表${NC}" exit 1 fi echo "可用iptables表:" select selected_table in "${tables[@]}"; do if [[ -n "$selected_table" ]]; then break else echo -e "${RED} 无效选择,请重新输入${NC}" fi done #2. 选择链 iptables-save -t "$selected_table" > "$TEMP_FILE" chains=($(extract_chains)) if [[ ${#chains[@]} -eq 0 ]]; then echo -e "${RED} 错误:表 ${selected_table} 中未找到任何链${NC}" rm -f "$TEMP_FILE" exit 1 fi echo "表 ${selected_table} 的可用链:" select selected_chain in "${chains[@]}"; do if [[ -n "$selected_chain" ]]; then break else echo -e "${RED} 无效选择,请重新输入${NC}" fi done #3. 执行分析 main rm -f "$TEMP_FILE"
测试
- • 生成两条规则查看输出
#在filter表的INPUT链创建测试规则 sudo iptables -t filter -A INPUT -p tcp --sport 12345 -j LOG --log-prefix "FILTER_TEST " #创建测试规则(记录日志但永不匹配实际流量) sudo iptables -t filter -A cali-INPUT -p tcp --sport 65535 -j LOG --log-prefix "CALI_TEST_RULE "
- • 执行脚本
./show_iptables.sh 可用iptables表: 1) raw 2) mangle 3) filter 4) nat #? 3 表 filter 的可用链: 1) INPUT 19) cali-from-hep-forward 2) FORWARD 20) cali-from-host-endpoint 3) OUTPUT 21) cali-from-wl-dispatch 4) DOCKER 22) cali-fw-cali163c2dd037c 5) DOCKER-ISOLATION-STAGE-1 23) cali-fw-caliceb7f36db92 6) DOCKER-ISOLATION-STAGE-2 24) cali-pri-_56duOTW9GxmBnwvgZx 7) DOCKER-USER 25) cali-pri-_RRPF6JYgiXDfvzOhm- 8) KUBE-EXTERNAL-SERVICES 26) cali-pri-_pJvVwNmnIJS_Hgp2My 9) KUBE-FIREWALL 27) cali-pro-_56duOTW9GxmBnwvgZx 10) KUBE-FORWARD 28) cali-pro-_RRPF6JYgiXDfvzOhm- 11) KUBE-KUBELET-CANARY 29) cali-pro-_pJvVwNmnIJS_Hgp2My 12) KUBE-NODEPORTS 30) cali-to-hep-forward 13) KUBE-PROXY-CANARY 31) cali-to-host-endpoint 14) KUBE-SERVICES 32) cali-to-wl-dispatch 15) cali-FORWARD 33) cali-tw-cali163c2dd037c 16) cali-INPUT 34) cali-tw-caliceb7f36db92 17) cali-OUTPUT 35) cali-wl-to-host 18) cali-cidr-block #? 1 ■ iptables链关系拓扑 (规则内联显示) ■ 说明: ▪ 灰色条目为规则 红色表示跳转目标 青色表示匹配条件 ▏ 链 [INPUT] 拓扑: ├── INPUT │ ├─ ▪ -m comment -j cali-INPUT │ ├─ ▪ -m comment -j KUBE-NODEPORTS │ ├─ ▪ -m conntrack --ctstate NEW -m comment -j KUBE-EXTERNAL-SERVICES │ ├─ ▪ -j KUBE-FIREWALL │ ├─ ▪ -p tcp -m tcp --sport 12345 -j LOG --log-prefix "FILTER_TEST " ├── ├── cali-INPUT ├── │ ├─ ▪ -p ipv4 -m comment -m comment -m set --match-set cali40all-hosts-net src -m addrtype --dst-type LOCAL -j ACCEPT ├── │ ├─ ▪ -p ipv4 -m comment -m comment -j DROP ├── │ ├─ ▪ -i cali+ -m comment -g cali-wl-to-host ├── │ ├─ ▪ -m comment -m mark --mark 0x10000/0x10000 -j ACCEPT ├── │ ├─ ▪ -m comment -j MARK --set-xmark 0x0/0xf0000 ├── │ ├─ ▪ -m comment -j cali-from-host-endpoint ├── │ ├─ ▪ -m comment -m comment -m mark --mark 0x10000/0x10000 -j ACCEPT ├── │ ├─ ▪ -p tcp -m tcp --sport 65535 -j LOG --log-prefix "CALI_TEST_RULE "
- • 清理测试规则
sudo iptables -t filter -D INPUT -p tcp --sport 12345 -j LOG --log-prefix "FILTER_TEST " sudo iptables -t filter -D cali-INPUT -p tcp --sport 65535 -j LOG --log-prefix "CALI_TEST_RULE "
通过以上脚本,能够快速的查看iptables规则的拓扑关系,便于理解和调试。
* * * $3,222 deposit available * * * hs=8ae64778bd085cbeed1f283a859d44a7* ххх*
2025年11月4日acclkx
JosephMor
2026年1月3日素材精彩极了。感谢 独创性。 河畔步道 我尊重这样的项目, 这里分享真实经验。你的内容 就是 正是这样的。加油。
JosephMor
2026年1月4日读起来像小说。由衷感谢 真情。 最佳季節 不常看到, 这么鲜明的文字。太棒了。
philucky
2026年1月9日That’s a solid point about responsible gaming – platforms like philucky login are making it easier with quick verification & deposits (₱100 min!). It’s all about balancing excitement with smart choices, right? Definitely a step up for PH players.
JosephMor
2026年1月21日我喜欢, 这里有真诚的评论。你的博客 就是 属于这里的。很出色。 丹戎貝諾瓦 这个页面 认真地 帮助别人。继续!
jl55ph
2026年2月5日Interesting read! Seeing more platforms like JL55 PH pushing competitive casino gaming is cool. The focus on tournaments & fast gameplay sounds intense-check out the jl55 ph link for details. RTP is key in those competitions, right? 🤔
jili56
2026年2月19日Smart players are always looking for an edge, and speed is a factor! I’ve seen platforms like jili56 app casino prioritize fast access & quick wins-interesting for those who like data-driven insights too. Seems streamlined!