Libvirt 端口转发
2016 年 08 月 13 日通过 libvirt 创建的 KVM 虚拟机,如果虚拟网络设置为 NAT 而不是 bridge 的话,从宿主机之外是没有办法直接访问的,只能在宿主机上进行连接。
如果想开放虚拟机的某个服务端口,比如 ssh 或者 http,可以在宿主机上设置 iptables 规则。
本文参考 libvirt 网络配置文档。
禁用 firewalld
在 CentOS 7 下 firewalld
与 libvirtd
有冲突,必须先禁用
firewalld
。
$ sudo systemctl stop firewalld.service
$ sudo systemctl disable firewalld.service
允许路由转发
添加 /etc/sysctl.conf
选项允许 ip forward:
net.ipv4.ip_forward = 1
修改后要重启才会生效。如果要即时生效,需要直接运行:
$ sudo sysctl -p
设置 iptables 转发规则
需要实现的是,当访问宿主机 (HOST_IP
) 的特定端口 (HOST_PORT
)
时,转发给指定的虚拟机端口 (GUEST_IP:GUEST_PORT
)。
在宿主机上运行以下 iptables
命令:
$ sudo iptables -I FORWARD -o virbr0 -d $GUEST_IP --dport $GUEST_PORT -j ACCEPT
$ sudo iptables -t nat -I PREROUTING -p tcp --dport $HOST_PORT -j DNAT --to $GUEST_IP:$GUEST_PORT
然后就可以通过 HOST_IP:HOST_PORT
访问到虚拟机的端口了。
不过这样操作并不是很方便,虚拟机以及端口多了的话会很混乱。
使用 hook 脚本自动配置
通过 virsh start
启动和虚拟机关闭时,会自动调用 hook 脚本
/etc/libvirt/hooks/qemu
,于是可以通过脚本来自动添加和删除
iptables 规则。
为了简化虚拟机端口转发配置,我写了 libvirt-forward 这个程序。此程序在 CentOS 6/7 下面成功测试过。
程序支持 json
和 yaml
两种配置格式,如果要使用
yaml
格式需要安装 PyYAML
:
$ sudo yum install PyYAML
复制 qemu-hook
程序到 /etc/libvirt/hooks
目录下面,建立符号链接:
$ sudo cp libvirt-forward/qemu-hook /etc/libvirt/hooks/qemu-hook
$ sudo ln -s qemu-hook qemu
创建配置文件目录:
$ sudo mkdir -p /etc/libvirt/hooks/config
$ sudo cp libvirt-forward/config/config.yaml.example /etc/libvirt/hooks/config/config.yaml
编辑 config.yaml
:
public_ip: 222.222.222.222
local_range: 192.168.122.0/24
domain:
MySQL:
private_ip: 192.168.122.20
local_range: 192.168.122.0/25
port_map:
tcp:
- [10022, 22]
- 3306
Apache:
private_ip: 192.168.122.30
port_map:
tcp:
- [20022, 22]
- 80
- 443
public_ip
为宿主机 ip 地址。每个虚拟机的转发规则对应
domain
下某个选项,选项名字和
libvirt 虚拟机名字相同,虚拟机名字可以通过
virsh list --all
查看。
private_ip
则是虚拟机的 ip 地址。
port_map
里设置需要转发的端口列表,转发端口相同的话只需要指定一个端口号,否则需要指定
[HOST_PORT, GUEST_PORT]
。
修改完配置后需要关闭虚拟机,然后通过 virsh start VMNAME
启动时才会生效,
虚拟机关闭后,转发规则也会自动删除。