文档中心>容器服务>隐患处理>kube-router iptables 版本兼容性隐患及其升级方法

kube-router iptables 版本兼容性隐患及其升级方法

最近更新时间:2026-07-29 11:28:02

我的收藏

问题现象

在已安装 NetworkPolicy 扩展组件(kube-router)的集群中,部分节点可能出现以下问题:
iptables 规则暴涨:节点 filter 表规则数达到数万甚至数十万条,kube-router Pod 的 CPU 使用率升高至数百 m 甚至 1 Core 以上。
端口不通:SSH(22)、kubelet(10250)等关键端口不可达,导致节点 NotReady。
其他组件规则累积:nodelocaldns 等共享 filter 表的组件规则反复追加,DNS 解析受影响。

根因分析

该问题由 kube-router 与 filter 表上其他组件(如 kube-proxy、nodelocaldns 等)之间的 iptables-nft 版本跨 v1.8.8 边界不兼容导致。
Linux iptables 存在两种后端实现:
legacy:传统的 iptables 工具,直接操作内核 iptables 模块。
nf_tables:新一代后端,通过 nftables 内核子系统实现规则管理。
netfilter 社区在 iptables-nft v1.8.8 中改变了 --dport/--sport/--mark 等匹配项的内部表达式格式。低于 v1.8.8 的 iptables-save 在读取高版本组件(如 kube-proxy v1.8.9)写入的规则时,这些参数会静默丢失
kube-router 使用全表 iptables-save/iptables-restore 同步 filter 表规则。一旦低版本的 iptables-save 丢失参数后,restore 将变形规则写回内核,导致 filter 表上所有组件(kube-proxy、nodelocaldns 等)写入的规则被破坏:
规则判重失效 → 规则反复追加 → iptables 规则暴涨
REJECT 规则的 --dport 丢失 → 阻断所有 TCP 端口 → 节点不可达

kube-router 各版本的 iptables 行为

组件版本
kube-router 镜像
iptables 策略
风险
≤ 1.0.3
v1.3.2 / v1.3.3
固定 iptables v1.8.7;后端自适应(对比 legacy 与 nft 规则数量决定)
v1.8.7 < v1.8.8,若后端选到 nf_tables 则存在跨版本兼容性风险。
1.0.4
v1.3.4
版本自适应(OS ≤ 1.8.7 用 v1.8.7,> 1.8.7 用 v1.8.9);后端 follow kubelet
版本自适应:OS ≤ 1.8.7 用 v1.8.7(+ nft 后端有风险),> 1.8.7 用 v1.8.9(无风险);后端 follow kubelet。
1.0.6
v1.3.7
固定 v1.8.9 + 后端自适应
无风险,从根本上消除兼容性问题。
kube-router v1.3.4(对应 networkpolicy 组件版本 1.0.4)通过容器内置 wrapper 自适应选择 iptables 版本和后端:版本根据 OS 自带的 iptables 版本决定,OS ≤ 1.8.7 时用 v1.8.7,> 1.8.7 时用 v1.8.9;后端 follow kubelet(即发行版 iptables 默认后端)。在 TencentOS Server 4(v1.8.9 + legacy)上自动使用 v1.8.9 + legacy,无风险;但在 TencentOS Server 3.1(v1.8.5 + nft)上会用 v1.8.7 + nft,低于 v1.8.8 的版本在 nft 后端下仍存在跨版本兼容性风险。
kube-router v1.3.7(对应 networkpolicy 组件版本 1.0.6)固定 iptables 版本为 v1.8.9,后端自适应(同 v1.3.3 逻辑,对比 legacy 与 nft 规则数量决定)。nft 参数丢失是单向的——只有低版本读高版本会丢,高版本读低版本不会丢。固定到当前最高版本 v1.8.9 后,无论 filter 表上其他组件用什么版本,kube-router 都能完整读取其规则,从根本上消除了兼容性问题。

影响范围

kube-router 的 iptables 兼容性隐患主要由其容器内使用的 iptables 版本与后端决定。只有 kube-router 使用低于 v1.8.8 的 iptables 版本且后端为 nf_tables 时,才存在跨版本兼容性风险(低版本 nft 读高版本规则时参数丢失)。

iptables 版本与后端选择策略

各 addon 组件版本的 kube-router 所采用的 iptables 策略如下:
组件版本
kube-router 镜像
iptables 策略
≤ 1.0.3
v1.3.2 / v1.3.3
iptables 固定 v1.8.7;后端自适应(简单对比 legacy 与 nft 规则数量决定使用哪个后端)
1.0.4
v1.3.4
版本自适应(OS 自带 iptables ≤ 1.8.7 时用 v1.8.7,> 1.8.7 时用 v1.8.9);后端 follow kubelet(即发行版 iptables 默认后端)
1.0.6
v1.3.7
iptables 固定 v1.8.9;后端自适应(同 v1.3.3 逻辑,对比规则数量决定)

风险判定标准

存在风险的组合需满足以下三个条件:
1. kube-router 实际使用的 iptables 版本 < v1.8.8(即 v1.8.7)。
2. kube-router 实际使用的后端为 nf_tables。
3. 节点上有其他组件也使用 nf_tables 后端 写入过规则(如 nodelocaldns 容器内 iptables v1.8.9 + nft)。
满足条件的节点上,所有 iptables 规则都以 nft 表达式形式存在于内核中。kube-router 的 iptables-save v1.8.7 在读取由其他组件(≥ v1.8.8)写入的 nft 表达式时,因格式不兼容导致 --dport/--sport 等匹配参数静默丢失,iptables-restore 将残缺规则写回 filter 表,引发自激循环。

各 kube-router 版本在不同操作系统下的风险

操作系统
OS iptables 版本
OS 默认后端
v1.3.3 (≤ 1.0.3)
v1.3.4 (1.0.4)
v1.3.7 (1.0.6)
TencentOS Server 3.1/3.2/3.3
v1.8.5
nf_tables
高风险(v1.8.7 + nft)
高风险(≤ 1.8.7 → v1.8.7 + nft)
无风险(固定 v1.8.9)
TencentOS Server 4
v1.8.9
legacy
无风险(后端选到 legacy,不涉及 nft 转换)
无风险(> 1.8.7 → v1.8.9 + legacy)
无风险(固定 v1.8.9)
CentOS 8.0 / RHEL 8.6
v1.8.5
nf_tables
高风险(v1.8.7 + nft)
高风险(≤ 1.8.7 → v1.8.7 + nft)
无风险(固定 v1.8.9)
Ubuntu 22.04 LTS
v1.8.7
nf_tables
高风险(v1.8.7 + nft)
高风险(≤ 1.8.7 → v1.8.7 + nft)
无风险(固定 v1.8.9)
Ubuntu 24.04 LTS / RHEL 9.5
v1.8.10
nf_tables
高风险(v1.8.7 + nft)
无风险(> 1.8.7 → v1.8.9)
无风险(固定 v1.8.9)
Rocky Linux 9.3
v1.8.8
nf_tables
高风险(v1.8.7 + nft)
无风险(> 1.8.7 → v1.8.9)
无风险(固定 v1.8.9)
CentOS 7 / Ubuntu 20.04
v1.4.x / v1.8.4
legacy
无风险(legacy 后端不涉及 nft 转换)
无风险(≤ 1.8.7 → v1.8.7 + legacy)
无风险(固定 v1.8.9)
说明:
v1.3.3(addon ≤ 1.0.3):在所有 nf_tables 后端的节点上均为高风险,因为固定 v1.8.7 + nft。
v1.3.4(addon 1.0.4):仅在 OS 自带 iptables ≤ v1.8.7 且后端为 nf_tables 的节点上存在风险(如 TencentOS Server 3.x、Ubuntu 22.04)。OS iptables > v1.8.7 的节点自动使用 v1.8.9,无风险。
v1.3.7(addon 1.0.6):固定 v1.8.9,所有节点均无风险。

预检方法

在升级前,建议先运行预检脚本评估集群当前状态。预检脚本为只读操作,不会修改任何资源,仅检测以下内容:
networkpolicy 组件当前镜像版本。
各节点的 iptables 后端(legacy / nf_tables)。
nft 后端节点的 INPUT 链中 169.254.20.10 重复规则数量。
识别极度膨胀节点(filter 表已不兼容,iptables-saveincompatible)。

使用预检脚本

前提条件:
已安装 kubectl
已配置好 KUBECONFIG,确保 kubectl 可以操作目标集群。可参考 连接集群 获取集群访问凭证。
1. 将以下脚本保存为 precheck-kube-router.sh,并赋予执行权限。
#!/usr/bin/env bash
#
# kube-router iptables 兼容性预检脚本(只读,不执行任何修改操作)
# 用法: ./precheck-kube-router.sh [--threshold N] [--help]
#
# 检测内容:
# 1. networkpolicy 组件当前镜像版本
# 2. 各节点 iptables 后端(legacy / nf_tables)
# 3. nft 后端节点的 INPUT 链 169.254.20.10 重复规则数
# 4. 识别极度膨胀节点(iptables-save 报 incompatible)
#
set -euo pipefail

RED='\\033[0;31m'
GREEN='\\033[0;32m'
YELLOW='\\033[1;33m'
NC='\\033[0m'

log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }

THRESHOLD=1000
NAMESPACE="kube-system"

usage() {
cat <<EOF
用法: $0 [选项]

选项:
--threshold N 重复规则判定阈值,默认 1000
--help 显示帮助

前置条件:
- kubectl 已安装,KUBECONFIG 已正确配置
- 对目标集群有足够权限
EOF
exit 0
}

while [[ $# -gt 0 ]]; do
case "$1" in
--threshold) THRESHOLD="$2"; shift ;;
--help) usage ;;
*) echo "未知选项: $1"; usage ;;
esac
shift
done

# 前置检查
command -v kubectl >/dev/null 2>&1 || { log_error "未安装 kubectl"; exit 1; }
kubectl cluster-info --request-timeout=5s >/dev/null 2>&1 || { log_error "无法连接集群,请检查 KUBECONFIG"; exit 1; }
kubectl get ds networkpolicy -n "$NAMESPACE" >/dev/null 2>&1 || { log_error "未找到 DaemonSet $NAMESPACE/networkpolicy,请确认 networkpolicy 组件已安装"; exit 1; }

echo "=== kube-router iptables 兼容性预检 ==="
echo "集群: $(kubectl config current-context)"
echo ""

# 当前镜像版本
current_image=$(kubectl get ds networkpolicy -n "$NAMESPACE" -o jsonpath='{.spec.template.spec.containers[0].image}')
echo "当前 networkpolicy 镜像: $current_image"
echo ""

# 遍历节点检测
echo "正在扫描各节点..."
echo "重复规则判定阈值: > ${THRESHOLD} 条"
echo ""

nodes=$(kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\\n"}{end}')

total=0; legacy=0; nft_ok=0; inflated=0; extreme=0; skipped=0

while IFS= read -r node_name; do
[[ -z "$node_name" ]] && continue
total=$((total + 1))

# 找该节点的 kube-proxy Pod
kp_pod=$(kubectl get pod -n "$NAMESPACE" -l k8s-app=kube-proxy \\
--field-selector spec.nodeName="${node_name}" \\
-o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)

if [[ -z "$kp_pod" ]]; then
skipped=$((skipped + 1))
echo " [$total] $node_name: 未找到 kube-proxy Pod,跳过"
continue
fi

# 检测 iptables 后端
backend=$(kubectl exec -n "$NAMESPACE" "$kp_pod" -- sh -c 'iptables --version 2>/dev/null' 2>/dev/null | grep -o 'nf_tables\\|legacy' || echo "unknown")

if [[ "$backend" == "legacy" ]]; then
legacy=$((legacy + 1))
echo " [$total] $node_name: legacy 后端 → 无风险"
continue
fi

if [[ "$backend" != "nf_tables" ]]; then
skipped=$((skipped + 1))
echo " [$total] $node_name: 后端未知 ($backend),跳过"
continue
fi

# nft 后端:检测 INPUT 链重复规则
save_output=$(kubectl exec -n "$NAMESPACE" "$kp_pod" -- timeout 15 sh -c 'iptables -t filter -S INPUT 2>/dev/null' 2>/dev/null || true)

if echo "$save_output" | grep -q "incompatible"; then
extreme=$((extreme + 1))
echo " [$total] $node_name: ⚠ filter 表不兼容(极度膨胀,建议重启节点)"
continue
fi

count=$(echo "$save_output" | grep -c "169.254.20.10" || true)

if [[ "$count" -gt "$THRESHOLD" ]]; then
inflated=$((inflated + 1))
echo " [$total] $node_name: nft,${count} 条重复规则 → ⚠ 膨胀"
else
nft_ok=$((nft_ok + 1))
echo " [$total] $node_name: nft,${count} 条 → 正常"
fi
done <<< "$nodes"

echo ""
echo "=== 预检结果汇总 ==="
echo " 扫描节点总数: $total"
echo " legacy 后端: $legacy (无风险)"
echo " nft 正常: $nft_ok"
echo " nft 膨胀: $inflated (需清理)"
echo " 极度膨胀: $extreme (建议重启节点)"
echo " 跳过: $skipped"
echo ""
if [[ "$inflated" -gt 0 || "$extreme" -gt 0 ]]; then
log_warn "发现 $((inflated + extreme)) 个需处理的节点,请参照下方升级方法和清理指引操作。"
else
log_info "未发现膨胀节点。"
fi
2. 执行预检脚本。
chmod +x precheck-kube-router.sh
./precheck-kube-router.sh
3. 如需调整重复规则判定阈值(默认 1000 条),可使用 --threshold 参数。
./precheck-kube-router.sh --threshold 500

结果解读

预检脚本会对每个节点输出检测结果,各结果含义及建议操作如下:
结果
含义
建议操作
legacy 后端 → 无风险
该节点使用 legacy iptables 后端,不涉及 nft 转换。
无需处理
nft,N 条 → 正常
该节点使用 nft 后端,重复规则数在正常范围内(≤ 阈值)。
无需处理
nft,N 条 → 膨胀
该节点存在大量重复规则,需清理。
filter 表不兼容(极度膨胀)
该节点 filter 表已严重膨胀,iptables 无法读取。
重启节点清理
脚本最后会输出汇总信息,包括各类型节点数量及需处理的节点总数。

升级方法

注意:
NetworkPolicy 为基础网络组件,为防止升级操作引发事故,TKE 控制台暂不支持该组件的一键升级功能。如需升级,请通过 kubectl 手动修改 DaemonSet 配置完成。
1. 查询最新镜像版本。前往 组件变更记录,查看 NetworkPolicy 组件的最新版本及对应的 kube-router 镜像版本号。
2. 执行以下命令编辑 networkpolicy DaemonSet。
kubectl edit ds networkpolicy -n kube-system
3. 在打开的编辑器中,找到 containers 配置,修改 image 为最新版本号。示例:
spec:
template:
spec:
containers:
- name: networkpolicy
image: ccr.ccs.tencentyun.com/tkeimages/kube-router:v1.3.7 # 替换为最新版本
4. 保存退出后,DaemonSet 会自动触发滚动更新。执行以下命令查看滚动更新状态:
kubectl rollout status ds networkpolicy -n kube-system --timeout=600s
5. 确认所有 networkpolicy Pod 正常运行:
kubectl get pods -n kube-system -l k8s-app=networkpolicy -o wide
说明:
如预检脚本发现存在膨胀节点,建议先完成存量规则清理(见下方 清理存量重复规则 章节)再执行升级。
升级前可使用 kubectl get ds networkpolicy -n kube-system -o yaml > networkpolicy-backup.yaml 备份当前配置,以便回滚。

清理存量重复规则

升级 kube-router 镜像版本后,新的重复规则不会再产生,但已有的残缺规则不会自动消除。如果预检脚本发现存在膨胀节点(重复规则数 > 1000 条)或极度膨胀节点(filter 表不兼容),需要清理这些存量规则。
清理存量规则最彻底的方式是重启节点。重启后,内核 nft 表会被清空,所有组件(kube-router、kube-proxy、nodelocaldns 等)会在启动时重新全量写入干净的规则。
警告:
请在业务低峰时段执行节点重启操作。
重启节点会导致该节点上的 Pod 被驱逐到其他节点,请确保集群有足够的冗余资源。
逐个节点操作,避免多个节点同时重启导致业务影响。
1. 登录 TKE 控制台,进入集群详情页。
2. 在左侧导航栏选择节点管理 > 节点池,点击需要操作的节点池进入节点列表。
3. 找到预检脚本标记为膨胀的节点,选择 封锁,将节点标记为不可调度。
4. 选择 驱逐,驱逐节点上的 Pod。等待驱逐完成。
5. 重启该节点(可通过 TKE 控制台的节点重启功能,或通过 云服务器控制台 重启)。
6. 等待节点重启完成并恢复 Ready 状态后,选择 取消封锁,恢复节点调度。
7. 对所有预检标记为膨胀或极度膨胀的节点重复步骤 3 - 6。
说明:
封锁节点可防止新 Pod 被调度到该节点,驱逐操作将存量 Pod 安全迁移到其他节点,两者配合避免重启导致业务中断。
对于预检脚本标记为"极度膨胀"(filter 表不兼容)的节点,必须通过重启节点的方式清理,其他方式无法恢复。

无法重启节点时

如果您的业务为重要生产环境,无法接受节点重启操作,请 提交工单 联系腾讯云技术团队。技术团队将提供专用脚本协助您完成 kube-router 升级和存量规则清理操作,无需重启节点。