EC2:如何通过 SDK 将多个弹性 IP 分配给单个网络接口

EC2:如何通过 SDK 将多个弹性 IP 分配给单个网络接口

有人知道如何通过 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 地址时,它们也不会自动添加。我不确定是否有好的方法可以做到这一点。最后,此脚本也不会删除您在此期间可能已删除的任何本地地址。

希望对你有帮助。

相关内容