端口转发至子网中没有公共 IP 的实例

端口转发至子网中没有公共 IP 的实例

使用 iptables DNAT 和使用 syctl 启用 IPv4 转发的传统方法似乎有效。Google 的文档也建议这样做。

然而,所有到达后端虚拟机的流量似乎来自头节点(源 IP 被替换为头节点的本地 IP)。不用说,这会破坏很多东西,因为后端 VM 不知道连接来自哪里(例如,出于识别和日志记录目的)。

将端口 8000 转发到后端的规则:

iptables -t nat -A PREROUTING -p tcp -i eth0 -d <1-local> --dport 8000 -j DNAT --to-destination <2-local>

传出流量返回头节点的规则:

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

图例:<1-local> = 头部本地 IP,<2-local> = 后端 VM 本地 IP

请注意,根据 Google 文档,已向网络添加了一条用于传出流量的路由(运行良好)。我知道负载平衡下有一个非常全面的端口转发功能,但说实话,我不知道如何在这种简单情况下使用它。

我如何确保原始源 IP 得到保留?我是否遗漏了什么,或者这是 GCE 子网的“功能”? 

答案1

您可以将 HTTP 负载均衡器与目标代理一起使用,并从请求标头中的 X-Forwarded 字段中保留客户端 IP。有关它的更多信息,请参阅帮助中心文章

答案2

最后我找到了一个解决方案并在生产网络中成功测试了它。

GCE 中端口转发的挑战在于实例只有一个网络接口,因此使用 DNAT 转发的数据包在通过 POSTROUTING 链时,其源 IP 会立即被 SNAT 替换。由于这种情况发生在它们到达目标实例之前,因此 DNAT 似乎不起作用。现在的修复方法是通过跳过 POSTROUTING 中的该规则来保护 DNAT 之后转发的数据包免受立即 SNAT 的影响。下面的第二条规则正是这样做的:

iptables -t nat -A PREROUTING -i eth0 -p tcp -d <1-local> --dport 8000 -j DNAT --to-destination <2-local>
iptables -t nat -A POSTROUTING -o eth0 -p tcp -d <2-local> --dport 8000 -j RETURN

上述规则可以重复用于转发任意数量的端口。下面的最后一条规则确保本地网络中的所有实例都可以访问互联网,而无需拥有公共 IP(此规则取代了 GCE 文档中建议的 MASQUERADE 规则):

iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source <1-local>

在将数据包发送回互联网之前,网络网关会将 <1-local> 替换为公共 IP。

请注意,必须添加 GCE 防火墙规则以允许来自任何地方的所有转发端口,包括头部(堡垒)和后端实例。

此解决方案支持将端口转发到没有公共 IP 的后端实例,同时这些实例也可以完全访问 Internet。后者还需要为头节点启用 IP 转发,并向子网添加默认路由,如下所述:https://cloud.google.com/compute/docs/networking在“配置 NAT 网关”部分。

答案3

针对您的情况,我采取的方法是使用 UDP 或 TCP 负载平衡。如果您在与虚拟机相同的区域中尚未拥有合适的公共 IP,则需要为此目的分配一个新 IP。

您可以使用单个公共 IP 地址创建多个负载均衡器,只要这些负载均衡器使用不同的端口号即可。

仅具有单个后端且没有健康检查的 UDP 或 TCP 负载均衡器与传统的端口转发非常相似。

相关内容