我有两个接口,假设为eth0
和eth0.4000
VLAN。两者都有一个默认网关。当进程直接侦听接口时,一切都按预期工作。
但不适用于hostPort
Kubernetes 的绑定。
vlan.gw-mac > eth0-mac, ethertype 802.1Q (0x8100), length 78: vlan 4000, p 0, ethertype IPv4 (0x0800), clientIP.38712 > vlanIP.80: Flags [S]
eth0-mac > eth0.gw-mac, ethertype IPv4 (0x0800), length 74: vlanIP.80 > clientIP.38712: Flags [S.]
SYN 来自vlan.gateway
,被转发到容器,但答案 SYN-ACK 离开堆栈eth0.gw
并且不正确,vlan.gw
但 tcpdump 显示源 IP 是vlanIP
。
路由表看起来不错:
# ip route get to <clientIP> from <vlanIP> dev eth0.4000
<clientIP> from <vlanIP> via <vlan.gw> dev eth0.4000 table 1 uid 0
hostPort 映射通过以下方式创建:CNI 插件端口映射它使用 DNAT 和 SNAT(详细信息链接)。因此网关查找发生得太早了。当我手动将路由从容器 IP 添加到查找表 1 时,它可以使用 vlan 接口工作,但会破坏 eth0。
所以问题是 - 需要做什么才能实现路由后NAT 将容器 IP 替换为接口 IP?
答案1
您说得对,DNAT 的隐式 SNAT 发生得太晚了:此时,路由决策已经做出,因此在错误的接口上使用正确的源 IP。
为了避免这种情况,您需要更深入地了解基于策略的路由。在https://superuser.com/questions/638044/source-based-policy-routing-nat-dnat-snat-aka-multi-wans-on-centos-5可以使用。
为此,您需要在 mangle 表的 PREROUTING 链中包含以下内容:
-A PREROUTING -i vlanIface -m state --state NEW,RELATED,ESTABLISHED -d <vlanIP> -j CONNMARK --set-mark 0x10/0x10
-A PREROUTING -m connmark --mark 0x10/0x10 -j CONNMARK --restore-mark --cfmask 0x10
这样,所有属于通过 vlanIface 发起的连接数据包的 fwmark 中都会设置 0x10。然后可以将其用于 PBR。假设您的 pod 网络是 10.0.0.0/8,辅助网关的表是 1:
ip rule add fwmark 0x10/0x10 from 10.0.0.0/8 table 1
您也许可以省略from 10.0.0.0/8
,但它是防止错误设置 fwmarks 的有用安全网(例如,由于其他东西使用了特定标记)。