仓库源文

.. Kenneth Lee 版权所有 2018-2020

:Authors: Kenneth Lee :Version: 1.0

如何为libvirt设置虚拟主机


最近在ARM Server上分析虚拟机的数据压力,其中一种场景类似Docker,要把guest中的端 口映射到host中,类似对Docker Image中做这样的动作:::

    docker run -p 8080:80 my_web_server

但libvirt没有这样的配置,只在手册(Networking - Libvirt Wiki)中这样建议:::

    iptables -I FORWARD -o virbr0 -d  $GUEST_IP \
            -j ACCEPT iptables -t nat -I PREROUTING \
            -p tcp --dport $HOST_PORT \
            -j DNAT --to $GUEST_IP:$GUEST_PORT

但实际上你这样做了,映射根本过不去。

所以,我和Docker的规则对了一下,发现区别在这个地方:

首先,DNAT不仅仅要对PREROUTING链来做,还要对OUTPUT链来做:::

    iptables -t nat -A OUTPUT -p tcp --dport $HOST_PORT 
            -j DNAT --to-destination $GUEST_IP:$GUEST_IP

第二,要给反向的包做SNAT:::

    iptables -t nat -A POSTROUTING -d $GUEST_IP \
            -s $GUEST_IP -p tcp --dport $GUEST_PORT \
            -j MASQUERADE

这样就通了。

深入分析一下,其实第二条是不需要的,因为如果你的机器使用默认的NAT网络,本来就有 这个配置,而且,很多协议并不需要双向连接,没有SNAT并不会引起问题。

而增加第一个配置的原因可以从这个图上看出来(来源: https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg)

    .. figure:: _static/qemu-iptable.jpg

veth是路由一层的协议,不经过nat链在链路层布下的PREROUTING钩子的,所以如果不在 OUTPUT上做DNAT,就没有DNAT了。

libvirt在这个问题上处理得好的话,应该把这种映射直接做在网络的XML配置中的,不过 libvirt的应用场景和docker不一样,前者通常是用vxlan连接多个跨节点的虚拟机的,不 需要通过本地的Host做防火墙,所以这个功能就没人弄了。但其实做单机测试和验证这个 功能却很常用,希望圈内人士可以把这个功能加进去。