网关 Netfilter 规则¶
Kube-OVN 使用网关 Netfilter 后端实现默认 VPC 下容器网络(Overlay)的网关 NAT 功能。 后端可以使用 iptables 或 nftables,本文同时保留 iptables 后端的规则参考。
网关后端选择¶
kube-ovn-cni daemon 支持三种网关 Netfilter 模式:
| 模式 | 行为 |
|---|---|
auto | 自动检测本地 kube-proxy 模式。iptables 和 ipvs 使用 iptables 后端,nftables 使用 nftables 后端。 |
iptables | 始终使用 Kube-OVN 的 iptables 和 ipset 规则。 |
nftables | 始终使用 Kube-OVN 的 nftables 表和规则。 |
默认模式为 auto。冷启动时会轮询 kube-proxy 的 proxyMode 接口;如果在检测超时前接口不可用,则读取 kube-system 中的 kube-proxy ConfigMap。默认接口为 http://localhost:10249/proxyMode,默认超时为 30 秒。运行期间连续三次观察到模式变化后才会切换后端,避免一次临时响应触发切换。
运行 bash install.sh 前,可以通过环境变量设置模式和检测参数;也可以在 kube-ovn-cni DaemonSet 中设置:
export GATEWAY_NETFILTER_MODE=auto
export KUBE_PROXY_MODE_ENDPOINT=http://localhost:10249/proxyMode
export GATEWAY_NETFILTER_DETECT_TIMEOUT=30s
args:
- --gateway-netfilter-mode=auto
- --kube-proxy-mode-endpoint=http://localhost:10249/proxyMode
- --gateway-netfilter-detect-timeout=30s
使用 Helm 安装时,根据 Chart 版本设置对应的值:
# charts/kube-ovn
networking:
GATEWAY_NETFILTER_MODE: auto
KUBE_PROXY_MODE_ENDPOINT: http://localhost:10249/proxyMode
GATEWAY_NETFILTER_DETECT_TIMEOUT: 30s
# charts/kube-ovn-v2
agent:
gatewayNetfilterMode: auto
kubeProxyModeEndpoint: http://localhost:10249/proxyMode
gatewayNetfilterDetectTimeout: 30s
nftables 后端在适用的 IPv4、IPv6 nftables family 中分别管理 Kube-OVN 自有的 kube-ovn 表,用于 Service 和 NodePort NAT、子网 NAT、NAT policy、TProxy、filter 和 mangle 规则以及子网流量统计。它不会读取或修改 kube-proxy 私有的 nftables 对象或标记,也不会清理 conntrack 表项。
后端切换时,Kube-OVN 会先准备并同步目标后端,再清理旧后端。切换和卸载时只清理 Kube-OVN 自有的 iptables、ipset 和 nftables 对象。如果清理失败,会保留当前后端并在后续 reconcile 中重试。
Nftable LoadBalancer Service¶
控制器参数 --enable-nftable-lb-svc 用于启用由 VPC NAT Gateway nftable share-DNAT 实现的 LoadBalancer Service。当前 master 中该参数默认值为 true,且需要全局参数 --enable-lb=true 才能生效。
对应的 Helm 配置键如下:
# charts/kube-ovn
func:
ENABLE_NFTABLE_LB_SVC: true
# charts/kube-ovn-v2
features:
enableNftableLoadbalancerService: false
v2 chart 仅在 enableNftableLoadbalancerService 为 true 时渲染控制器参数。当该值为 false 时会省略参数,而控制器默认值仍为 true;在 chart 提供有效的关闭方式前,如需关闭应显式设置控制器参数。
nftable LoadBalancer Service 进入终止状态时,会立即释放其 EIP:port:protocol 标识。后续 Service 可以复用该标识并被编程,无需等待已删除 Service 的 finalizer 完成。
使用的 ipset 如下表所示:
| 名称(IPv4/IPv6) | 类型 | 存储对象 |
|---|---|---|
| ovn40services/ovn60services | hash:net | Service 网段 |
| ovn40subnets/ovn60subnets | hash:net | Overlay 子网网段以及 NodeLocal DNS IP 地址 |
| ovn40subnets-nat/ovn60subnets-nat | hash:net | 开启 NatOutgoing 的 Overlay 子网网段 |
| ovn40subnets-distributed-gw/ovn60subnets-distributed-gw | hash:net | 开启分布式网关的 Overlay 子网网段 |
| ovn40other-node/ovn60other-node | hash:net | 其它节点的内部 IP 地址 |
| ovn40local-pod-ip-nat/ovn60local-pod-ip-nat | hash:ip | 已弃用 |
| ovn40subnets-nat-policy | hash:net | 配置了 natOutgoingPolicyRules 的所有子网网段 |
| ovn40natpr-418e79269dc5-dst | hash:net | natOutgoingPolicyRules 中 rule 对应的 dstIPs |
| ovn40natpr-418e79269dc5-src | hash:net | natOutgoingPolicyRules 中 rule 对应的 srcIPs |
使用的 iptables 规则(IPv4)如下表所示:
| 表 | 链 | 规则 | 用途 | 备注 |
|---|---|---|---|---|
| filter | INPUT | -m set --match-set ovn40services src -j ACCEPT | 允许 k8s Service 和 Pod 相关流量通过 | -- |
| filter | INPUT | -m set --match-set ovn40services dst -j ACCEPT | 同上 | -- |
| filter | INPUT | -m set --match-set ovn40subnets src -j ACCEPT | 同上 | -- |
| filter | INPUT | -m set --match-set ovn40subnets dst -j ACCEPT | 同上 | -- |
| filter | FORWARD | -m set --match-set ovn40services src -j ACCEPT | 同上 | -- |
| filter | FORWARD | -m set --match-set ovn40services dst -j ACCEPT | 同上 | -- |
| filter | FORWARD | -m set --match-set ovn40subnets src -j ACCEPT | 同上 | -- |
| filter | FORWARD | -m set --match-set ovn40subnets dst -j ACCEPT | 同上 | -- |
| filter | FORWARD | -s 10.16.0.0/16 -m comment --comment "ovn-subnet-gateway,ovn-default" | 用于计数从 subnet 访问外部网络的报文 | 10.16.0.0/16 为 subnet 的 cidr ,comment 中逗号前面的 ovn-subnet-gateway 用于标识该 iptables 规则用于 subnet 出入网关报文计数,逗号后面 ovn-default 是该 subnet 的名字 |
| filter | FORWARD | -d 10.16.0.0/16 -m comment --comment "ovn-subnet-gateway,ovn-default" | 用于计数从外部网络访问 subnet 的报文 | 同上 |
| filter | OUTPUT | -p udp -m udp --dport 6081 -j MARK --set-xmark 0x0 | 清除流量标记,避免执行 SNAT | UDP: bad checksum on VXLAN interface |
| nat | PREROUTING | -m comment --comment "kube-ovn prerouting rules" -j OVN-PREROUTING | 进入 OVN-PREROUTING 链处理 | -- |
| nat | POSTROUTING | -m comment --comment "kube-ovn postrouting rules" -j OVN-POSTROUTING | 进入 OVN-POSTROUTING 链处理 | -- |
| nat | OVN-PREROUTING | -i ovn0 -m set --match-set ovn40subnets src -m set --match-set ovn40services dst -j MARK --set-xmark 0x4000/0x4000 | 为 Pod 访问 Service 流量添加 masquerade 标记 | 作用于关闭内置 LB 的场景 |
| nat | OVN-PREROUTING | -p tcp -m addrtype --dst-type LOCAL -m set --match-set KUBE-NODE-PORT-LOCAL-TCP dst -j MARK --set-xmark 0x80000/0x80000 | 为 ExternalTrafficPolicy 为 Local 的 Service 流量(TCP)添加特定标记 | 仅 kube-proxy 使用 ipvs 模式时存在 |
| nat | OVN-PREROUTING | -p udp -m addrtype --dst-type LOCAL -m set --match-set KUBE-NODE-PORT-LOCAL-UDP dst -j MARK --set-xmark 0x80000/0x80000 | 为 ExternalTrafficPolicy 为 Local 的 Service 流量(UDP)添加特定标记 | 同上 |
| nat | OVN-POSTROUTING | -m set --match-set ovn40services src -m set --match-set ovn40subnets dst -m mark --mark 0x4000/0x4000 -j SNAT --to-source | 当节点通过 Service IP 访问 Overlay Pod 时,保持源 IP 为节点 IP。 | 仅 kube-proxy 使用 ipvs 模式时生效 |
| nat | OVN-POSTROUTING | -m mark --mark 0x4000/0x4000 -j MASQUERADE | 为特定标记的流量执行 SNAT | -- |
| nat | OVN-POSTROUTING | -m set --match-set ovn40subnets src -m set --match-set ovn40subnets dst -j MASQUERADE | 为通过节点的 Pod 之间的 Service 流量执行 SNAT | -- |
| nat | OVN-POSTROUTING | -m mark --mark 0x80000/0x80000 -m set --match-set ovn40subnets-distributed-gw dst -j RETURN | 对于 ExternalTrafficPolicy 为 Local 的 Service 流量,若 Endpoint 使用分布式网关,无需执行 SNAT | -- |
| nat | OVN-POSTROUTING | -m mark --mark 0x80000/0x80000 -j MASQUERADE | 对于 ExternalTrafficPolicy 为 Local 的 Service 流量,若 Endpoint 使用集中式网关,执行 SNAT | -- |
| nat | OVN-POSTROUTING | -p tcp -m tcp --tcp-flags SYN NONE -m conntrack --ctstate NEW -j RETURN | Pod IP 对外暴露时,不执行 SNAT | -- |
| nat | OVN-POSTROUTING | -s 10.16.0.0/16 -m set ! --match-set ovn40subnets dst -j SNAT --to-source 192.168.0.101 | Pod 访问集群外网络时,若子网开启 NatOutgoing 且使用指定 IP 的集中式网关,执行 SNAT | 10.16.0.0/16 为子网网段,192.168.0.101 为指定的网关节点 IP |
| nat | OVN-POSTROUTING | -m set --match-set ovn40subnets-nat src -m set ! --match-set ovn40subnets dst -j MASQUERADE | Pod 访问集群外网络时,若子网开启 NatOutgoing,执行 SNAT | -- |
| nat | OVN-POSTROUTING | -m set --match-set ovn40subnets-nat-policy src -m set ! --match-set ovn40subnets dst -j OVN-NAT-POLICY | Pod 访问集群外网络时,若子网配置了 natOutgoingPolicyRules,符合策略的报文执行 SNAT | 配置了 natOutgoingPolicyRules 子网的出外网报文进入 OVN-NAT-POLICY 链 |
| nat | OVN-POSTROUTING | -m mark --mark 0x90001/0x90001 -j MASQUERADE --random-fully | 同上 | 从 OVN-NAT-POLICY 出来后,如果被打上 tag 0x90001/0x90001 就会做 SNAT |
| nat | OVN-POSTROUTING | -m mark --mark 0x90002/0x90002 -j RETURN | 同上 | 从 OVN-NAT-POLICY 出来后, 如果被打上 tag 0x90002/0x90002 不会做 SNAT |
| nat | OVN-NAT-POLICY | -s 10.0.11.0/24 -m comment --comment natPolicySubnet-net1 -j OVN-NAT-PSUBNET-aa98851157c5 | 同上 | 10.0.11.0/24 表示子网 net1 的 CIDR, OVN-NAT-PSUBNET-aa98851157c5 这条链下的规则就对应这个子网的 natOutgoingPolicyRules 配置 |
| nat | OVN-NAT-PSUBNET-xxxxxxxxxxxx | -m set --match-set ovn40natpr-418e79269dc5-src src -m set --match-set ovn40natpr-418e79269dc5-dst dst -j MARK --set-xmark 0x90002/0x90002 | 同上 | 418e79269dc5 表示 natOutgoingPolicyRules 中的一条规则的 ID,可以通过 status.natOutgoingPolicyRules[index].RuleID 查看到, 表示 srcIPs 满足 ovn40natpr-418e79269dc5-src, dstIPS 满足 ovn40natpr-418e79269dc5-dst 会打上 tag 0x90002 |
| mangle | OVN-OUTPUT | -d 10.241.39.2/32 -p tcp -m tcp --dport 80 -j MARK --set-xmark 0x90003/0x90003 | 将 kubelet 的探测流量加上特定标记从而引入到 tproxy | |
| mangle | OVN-PREROUTING | -d 10.241.39.2/32 -p tcp -m tcp --dport 80 -j TPROXY --on-port 8102 --on-ip 172.18.0.3 --tproxy-mark 0x90004/0x90004 | 将 kubelet 的探测流量加上特定标记从而引入到 tproxy |