如何为 2 个 KVM-Guest 分配多个公共 IP 地址

如何为 2 个 KVM-Guest 分配多个公共 IP 地址

我对这个主题还很陌生,我花了好几天的时间才弄清楚如何通过 KVM 主机为 KVM 客户机分配多个公共 IP 地址。我找到了大量示例,了解如何通过 1 个公共 IP 运行此类设置。

以下是我的设置:服务器只有一个 NIC/MAC,运行 2 个 KVM-Guest,带有 apache(和其他东西)。两个客户环境都是 ubuntu server 11.10,必须在单独的 VM 中运行。5 个公共 IP 地址用于处理 SSL 证书和其他东西。第一个 VM 应该使用 5 个地址/证书中的 3 个。第二个 VM 使用其余的。apache 东西配置正确。

我尝试了多种不同的方式通过 iptables 将流量从主机 NIC 路由到客户机 NIC。尽管其中一种方法是正确的,但只是实施错误,但我没有透露细节,以免让您感到困惑。问题是:理想的做法是什么?

应满足以下条件:

  • Apache 必须获取访问者的原始 IP 地址
  • Apache 必须知道使用了哪个公共 IP 地址才能使用正确的 ssl-vhost
  • 流量不能通过主机上的(反向)代理进行路由,因为其他 VM 客户机上还有另外 2 个非 http 服务,应该可以从公共网络访问。并且:只有 sshd 应该直接在主机上监听 - 没有其他东西
  • 每个虚拟机都应该能够直接访问互联网。
  • 数据中心的网络是基于 MAC 交换的。据我所知,与互联网通信的唯一方式是通过 eth0 及其 MAC 地址。

如果我丢弃所有虚拟化内容,这将非常容易,因为 apache 直接从特定的 ip 地址获取请求。

我愿意接受任何可行的解决方案。

图表

答案1

在您的 dom0(例如 KVM 主机)WAN 接口上使用桥接器。这需要安装bridge-utils包。由于这是基于 Debian 的发行版,您可以在以下位置进行配置/etc/network/interfaces

iface eth0 inet manual

auto br_wan
iface br_wan inet dhcp
    # Assuming DHCP to get address, otherwise migrate all WAN connection options here
    #address 192.168.122.0
    bridge_ports eth0 tap_guest1
    bridge_stp      off
    bridge_maxwait  0
    bridge_fd       0
    pre-up ip tuntap add dev tap_guest1 user guest1 mode tap
    # This command is required if your ISP allocates static IPs depending on MAC address
    # You shouldn't use this but might be handy some time
    #pre-up sysctl -q -w net/ipv4/conf/tap_guest1/proxy_arp=1
    post-down ip tuntap del tap_guest1 mode tap

预备命令设置 TAP 接口以将您的 KVM 客户端连接到桥接器。请注意,此设置允许从非特权用户 guest1 运行 kvm。请注意,net.ipv4.ip_forward = 1使用 sysctl 进行设置也可能有用。

我使用了包ip tuntap中的命令iproute2。Debian 包中尚未记录该命令,但很快就会在上游的手册页中提供。由于此包安装在每个基于 Debian 的服务器上,因此您无需安装uml-utilitiesopenvpn打包即可创建这些接口。

这种方法在管理大量 tap 接口时确实缺乏一些优雅性,因为您需要创建与tap_guest1接口类似的 pre-up 和 post-down 线路。这可以通过在/etc/network/pre-up.d和中编写额外的脚本来解决/etc/network/post-down.d。如果您想br_wan在 KVM 客户机仍在运行时使用 ifdown/ifup 脚本重新配置接口,这也是一个问题 — 您需要删除除桥接eth0配置之外的所有接口并手动将它们从桥接中分离(然后不要忘记在桥接重新配置后将它们重新连接起来)或关闭桥接上运行的所有 KVM 实例。

另一种方法,也许更简洁,是为 KVM 本身编写自定义 ifup 脚本,并将其用作scriptNIC 的选项。您可以在 中找到一个示例/etc/qemu-ifup。请参阅kvm 手册页了解详情。

然后你可以像这样运行你的 KVM 盒:

kvm -net nic,model=virtio,macaddr=12:34:56:78:9a:bc \
    -net tap,ifname=tap_guest1,script=no,downscript=no \
    -boot c -nographic -display none -daemonize \
    guest1-drive.qcow2

可以使用命令手动为 KVM 客户机在一个接口上设置多个 IP 地址

ip address add aaa.bbb.ccc.101/24 dev eth0

或者永久地像/etc/network/interfaces这样:

auto eth0 eth0:1
iface eth0 inet static
    address aaa.bbb.ccc.100
    network aaa.bbb.ccc.0
    netmask 255.255.255.0
    broadcast aaa.bbb.ccc.255
    gateway aaa.bbb.ccc.1

iface eth0:1 inet static
    address aaa.bbb.ccc.101
    network aaa.bbb.ccc.0
    netmask 255.255.255.0
    broadcast aaa.bbb.ccc.255
    gateway aaa.bbb.ccc.1

请注意,如果您的数据中心/提供商不希望您在同一网络上显示其他盒子,他可能不会配置它们,并且它们将不可用。在这种情况下,您可能需要创建内部桥接并使用 iptables 使用 DNAT 和 SNAT 在您的 WAN 接口和此桥接之间转发数据包。假设您的本地虚拟桥接网络是 10.0.0.0/8,您的 guest1 是 10.0.0.2,您将需要以下内容:

iptables -t nat -A PREROUTING --dst aaa.bbb.ccc.100 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.2
iptables -t nat -A PREROUTING --dst aaa.bbb.ccc.101 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.2
...
iptables -t nat -A POSTROUTING -p tcp --dst 10.0.0.2 -j SNAT --to-source aaa.bbb.ccc.100

请注意,您需要为每个 KVM 客户端设置与外部 IP 数量相同的 DNAT 命令,但只需一条 SNAT 规则即可访问互联网。此外,您还可以通过仅允许所需端口来仅允许 HTTP/HTTPS/SSH 流量。如果您省略该--dport语句,则所有端口都将被转发。除非您愿意托管 DHCP 服务器,否则您的 KVM 客户端应具有静态网络设置,并以 KVM 主机作为默认网关。

答案2

您使用网桥而不是使用 iptables 转发数据包。启动客户机后,您只需将 IP 配置到客户机上的 NIC(如果您有多个虚拟 NIC)即可。

参考此文档

答案3

@jollyroger:非常感谢您的全面指南。遗憾的是,就我而言,它不起作用。但您的指南帮助我更好地了解了 linux-networking/bridging 与 KVM 结合使用的功能。

所以我恢复了所有内容,并直接从托管公司获得了一些帮助。该场景非常简单,只需使用虚拟管理器维尔什用于添加自定义网络配置。以下是最终对我有用的解决方案:

我有一个 /29 子网(+主机上用于 ssh 的另一个不同 IP)。数据中心的网络是基于 mac 交换的,因此所有流量都必须通过本地网关(据我所知)。我的提供商是德国的 Hetzner。我使用了http://www.subnet-calculator.com/subnet.php?net_class=A计算网络配置 xml 的所有必要设置:

<network>
        <name>{some systemwide unique name. e.g.: subnet1}</name>
        <uuid>{> call uuidgen from shell to generate a uuid}</uuid>
        <forward dev="{interface e.g.: eth0}" mode="route" />
        <bridge name="{name of a _new_ virtual interface e.g.: virbr2}" stp="off" forwardDelay="0" />
        <ip address="{subnet-calc: Host Address Range Start Address}" netmask="subnet-calc: Subnet Mask">
                <dhcp>
                        <range start="{subnet-calc: Host Address Range Start Address+1}" end="{subnet-calc: Host Address Range End Address}" />
                </dhcp>
        </ip>
</network>

我保存了这个 xml 数据到类似/tmp/subnet1.xml并通过以下方式应用这个新的虚拟网络:

sudo virsh net-define /tmp/subnet1.xml

我用虚拟管理器0.9.0(通过我的 Windows 机器上的 Putty 通过 x11 转发)创建和编辑所有虚拟机。因此,我的 2 个公共虚拟机都获得了这个新的虚拟网络。在每个虚拟机中,我为每个公共 IP 创建了一个新虚拟网络接口。我已记下哪个 MAC 地址用于哪个公共 IP。因此,如果我想将公共 IP 地址移动到另一个虚拟机,只需删除虚拟机 A 中的虚拟 NIC 并使用相同的 MAC 地址在虚拟机 B 中创建它即可。

另外,如果您尝试重现此场景:在启动虚拟机之前,请确保虚拟网络“子网 1”(sa)处于活动状态。在 virt-manager 的主窗口中,转到编辑 > 连接详细信息并跳转到 Tab虚拟网络。如果网络“subnet1”呈灰色,只需标记它并单击播放按钮。

现在启动虚拟机并输入是否配置. 就我而言,一切都直接起作用。

如果我在本报告中遗漏了任何内容,请直接询问。如果有人有更好的解决方案,请随时在此处添加。

相关内容