问题现象
在已安装 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-save 报 incompatible)。使用预检脚本
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 pipefailRED='\\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=1000NAMESPACE="kube-system"usage() {cat <<EOF用法: $0 [选项]选项:--threshold N 重复规则判定阈值,默认 1000--help 显示帮助前置条件:- kubectl 已安装,KUBECONFIG 已正确配置- 对目标集群有足够权限EOFexit 0}while [[ $# -gt 0 ]]; docase "$1" in--threshold) THRESHOLD="$2"; shift ;;--help) usage ;;*) echo "未知选项: $1"; usage ;;esacshiftdone# 前置检查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=0while IFS= read -r node_name; do[[ -z "$node_name" ]] && continuetotal=$((total + 1))# 找该节点的 kube-proxy Podkp_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" ]]; thenskipped=$((skipped + 1))echo " [$total] $node_name: 未找到 kube-proxy Pod,跳过"continuefi# 检测 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" ]]; thenlegacy=$((legacy + 1))echo " [$total] $node_name: legacy 后端 → 无风险"continuefiif [[ "$backend" != "nf_tables" ]]; thenskipped=$((skipped + 1))echo " [$total] $node_name: 后端未知 ($backend),跳过"continuefi# 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"; thenextreme=$((extreme + 1))echo " [$total] $node_name: ⚠ filter 表不兼容(极度膨胀,建议重启节点)"continueficount=$(echo "$save_output" | grep -c "169.254.20.10" || true)if [[ "$count" -gt "$THRESHOLD" ]]; theninflated=$((inflated + 1))echo " [$total] $node_name: nft,${count} 条重复规则 → ⚠ 膨胀"elsenft_ok=$((nft_ok + 1))echo " [$total] $node_name: nft,${count} 条 → 正常"fidone <<< "$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 ]]; thenlog_warn "发现 $((inflated + extreme)) 个需处理的节点,请参照下方升级方法和清理指引操作。"elselog_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: networkpolicyimage: 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 表不兼容)的节点,必须通过重启节点的方式清理,其他方式无法恢复。