有人知道如何通过 Amazon SDK 将多个弹性 IP 关联到单个实例吗?在 Ruby 中,我尝试使用 aws-sdk 和 fog gem,它们对于单个地址工作正常,但尝试分配多个地址时出错。
通过 Web UI,这可以通过添加额外的私有 IP,然后将公共 IP 分配给网络接口 + 私有 IP 来完成,但是我在 SDK 中没有任何私有 IP 参数。
答案1
弹性 IP 正在运行
默认情况下,VPC 中的实例只会从 VPC 内的私有子网获取 IP,通常位于 10.0.0.0/8 子网中的某个位置。这意味着虽然这些实例可以访问同一子网内的其他实例,但它们无法连接到更广泛的互联网。
让每台机器都拥有访问权限的一种方法是设置一台 NAT 机器,所有机器都使用它来路由流量。我们不会深入讨论此选项。
另一种方法是给每台机器一个自己的全球可路由的弹性 IP 地址。亚马逊会将流量路由到弹性 IP 到您的内部 IP。从网络拓扑的角度来看,这使得此设置更简单。
VPC 中的路由通过为每个子网设置的路由表进行。您可以在 AWS 控制台的 VPC 选项卡中查看路由表。默认情况下,子网内的请求在本地路由,而该范围之外的请求则通过“互联网网关”路由。
例如,假设您有一个 IP 为 10.0.0.1 的实例。它有一个与之关联的弹性 IP,假设为 1.2.3.4。现在,每当您访问 10.0.0.0/8 子网上的其他内部机器时,您的请求都将来自您的私有 IP,并且流量不会发生任何事情。
当您访问子网外的计算机时,数据包将通过互联网网关(名称为 igw-9d7534f2 的 VPC 设备)进行路由。网关(不是实际的 EC2 实例,只是一个不透明的 AWS 系统)接受请求,然后查找请求来源的内部 IP,并检查此 IP 是否与任何弹性 IP 相关联。如果是,则重写请求以显示来源是弹性 IP,然后通过互联网发送出去。当包以弹性 IP 作为目的地返回网关时,网关会检查弹性 IP 是否与内部 IP 相关联,如果是,则将包重写为该 IP。然后将包转发到私有子网。
这就是弹性 IP 一对一 NAT 的工作方式。这种方法的优点是子网内的机器不需要知道它们的弹性 IP。这使得切换正在运行的实例的弹性 IP 变得容易,因为唯一需要更新的是互联网网关上的映射表。外部 IP 可以多次更改;由于包在到达实例之前被重写为使用内部 IP,因此实例永远不会知道这一点。
多个网络接口
过去,Amazon 添加了向 VPC 实例添加多个网络接口的选项。这些接口在您的机器上显示为单独的以太网卡,并将具有单独的内部 IP。单独的接口还意味着您需要正确设置这些接口之间的路由:如果您通过错误的接口发送数据包,则该数据包将被丢弃。
引入这些网络接口是为了让您能够将不同的子网连接在一起:您可以在每个子网中拥有一个接口,然后根据需要在它们之间路由流量。由于每个子网都有自己的 IP 范围,因此很容易将流量路由到正确的网络接口。
对于每个内部 IP,都可以关联一个外部弹性 IP。虽然这是可能的,但现在您陷入了有点棘手的路由情况。两个内部 IP(在 eth0 和 eth1 上)都有一个关联的外部 IP,并且应该能够通过让互联网网关将其内部 IP 转换为弹性 IP 向更广泛的互联网发出请求。但是,为了正确执行此操作,必须通过正确的接口发送请求。亚马逊自己也承认这并不简单:
默认情况下,Linux 有一个路由表,它将本地子网之外的所有流量路由到单个接口。您可以使用路由查找它:
# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 10.0.0.1 0.0.0.0 UG 0 0 0 eth0
default 10.0.0.1 0.0.0.0 UG 100 0 0 eth0
10.0.0.0 * 255.255.255.0 U 0 0 0 eth0
10.0.0.0 * 255.255.255.0 U 0 0 0 eth1
在这里,所有互联网范围内的流量都将通过接口 eth0 发出。即使源 IP 为 eth1 接口的数据包也将通过 eth0 发出,然后将被默默丢弃,而不是通过 NAT 发送到正确的弹性 IP。虽然可以执行基于源的路由来解决这个问题,但设置起来并不容易(请注意,在向机器添加另一个接口后,您需要运行 dhclient):
# ifconfig | grep eth\\\|inet\
eth0 Link encap:Ethernet HWaddr 02:86:10:77:7f:fe
inet addr:10.0.0.76 Bcast:10.0.0.255 Mask:255.255.255.0
eth1 Link encap:Ethernet HWaddr 02:86:10:65:fd:31
inet addr:10.0.0.226 Bcast:10.0.0.255 Mask:255.255.255.0
# curl --interface 10.0.0.76 ifconfig.me
116.x.x.x
# curl --interface 10.0.0.226 ifconfig.me
<< TIMEOUT >>>
# ip rule add from 10.0.0.226 table out2
# ip route add default via 10.0.0.1 dev eth1 table 2
# ip route flush cache
# curl --interface 10.0.0.226 ifconfig.me
116.x.x.x
# curl --interface 10.0.0.76 ifconfig.me
116.x.x.x
多个 IP 地址
这样,我们就可以避免上述一些路由问题:所有数据包都将通过 eth0 发送,无论您拥有哪个 IP。由于公有地址和私有地址是一对一映射,因此您首先需要向其中一个实例添加一些新的私有地址。
亚马逊的 API 已更新,支持分配辅助私有 IP,但对于此示例,只需转到 AWS 控制台即可。在 EC2 选项卡中,转到实例。找到要更新的实例,右键单击并选择“管理私有 IP 地址”。
现在,您将看到实例在您的子网中有两个私有 IP(由于接口被锁定到特定子网,因此该接口上的所有 IP 都必须位于同一子网内)。太好了!但是,如果您现在检查您的实例:
# ifconfig eth0
eth0 Link encap:Ethernet HWaddr 02:86:10:7b:e4:f5
inet addr:10.0.0.34 Bcast:10.0.0.255 Mask:255.255.255.0
它还没有新的 IP。让我们尝试通过 DHCP 检索它!
root@ip-10-0-0-34:/# dhclient -d eth0
Listening on LPF/eth0/02:86:10:7b:e4:f5
Sending on LPF/eth0/02:86:10:7b:e4:f5
DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 3
DHCPREQUEST of 10.0.0.34 on eth0 to 255.255.255.255 port 67
DHCPOFFER of 10.0.0.34 from 10.0.0.1
DHCPACK of 10.0.0.34 from 10.0.0.1
不,我们只获得主要私有 IP!使用 DHCP 您只能获得一个地址。将来,也许亚马逊会使用某些客户端标识符或其他机制添加对多个 IP 的支持,但目前您必须手动添加地址。希望 Ubuntu 的 cloud-init 将来会添加对此的支持,这样我们就不必自己动手了。
Amazon 建议创建一个新的虚拟接口,然后将其启动。虽然这可行,但这意味着您将接口状态存储在硬盘上,并且您在 AWS 上所做的任何更改都必须传播到这些文件中。
为了测试,我们可以做一些更简单的事情:
MAC_ADDR=$(ifconfig eth0 | sed -n 's/.*HWaddr \([a-f0-9:]*\).*/\1/p')
IP=($(curl http://169.x.x.x/latest/meta-data/network/interfaces/macs/$MAC_ADDR/local-ipv4s))
for ip in ${IP[@]:1}; do
echo "Adding IP: $ip"
ip addr add dev eth0 $ip/24
done
这将检查与 eth0 关联的所有内部 IP 的 EC2 实例元数据,并添加所有辅助 IP。
现在,您可以在 AWS 控制台中将另一个弹性 IP 关联到辅助 IP:
现在您有多个外部 IP!
root@ip-10-0-0-34:/# curl --interface 10.0.0.58 ifconfig.me
116.x.x.x
root@ip-10-0-0-34:/# curl --interface 10.0.0.34 ifconfig.me
116.x.x.x
虽然这适用于测试,但它在重启后不会持久。您可以创建一个 upstart 或 cloud-init 脚本来为您执行此操作。即便如此,当您通过 EC2 添加 IP 地址时,它们也不会自动添加。我不确定是否有好的方法可以做到这一点。最后,此脚本也不会删除您在此期间可能已删除的任何本地地址。
希望对你有帮助。