ProxmoxVE(PVE)踩坑记录
之前入了一个四网口H310的工控板,装上了i3 8100T cpu弄了一个ITX主机来做一个高端软路由,刚开始用的是esxi上面跑了一个Openwrt,一直用得挺稳定,没啥问题。当然,esxi是基于red hat深度定制的,使用的是vmware自家的虚拟化技术,因此对于硬件要求比较苛刻,装在民用主板上,会有很多功能模块没有驱动用不了,就比如最开始连最常见的Intel I211网卡的驱动都不支持,而且竟然不支持温度监控,所以,这么不自由的系统,还是决定弃坑了,转战PVE,而PVE是基于debian开发的,虚拟化技术支持openVZ和KVM,前端用的是qemu,都是开源软件,比较自由。当然,自由带来的代价就是,一如既往,坑非常多,所以,本文总结一下我所遇到的一些烦死人的坑吧。

一、如何让管理端通过虚拟机上网
由于我用这台机器来做软路由,所以我期望的网络拓扑如下图:

其中enp1s0~enp4s0是四个物理网口,其中enp1s0~enp3s0三个网口分别连接到vmbr0~vmbr2这三个虚拟桥接网络中,这三个vmbr作为oepnwrt虚拟机的三个LAN口,其中物理网口enp4s0直通openwrt虚拟机,作为WAN口使用。
pve管理界面的网络设置如下图:

虚拟机网卡直通教程网上有很多,我这里就不再赘述了,直接上图:

即添加一个PCI设备就行,其中只要前面的设备位置04:00.0这个要对应你想要直通的网卡在系统中的位置编号才行。
然后,按照这样设置,虚拟机里WAN口应该就能正常PPPOE拨号获得IP地址了,而插在LAN口上的网线也能自动获取IP地址。
那么关键问题来了,如何让主机自动获得一个IP地址呢?我尝试过修改/etc/network/interfaces中的内容,因为在这个文件中,vmbr0~vmbr2均被配置成manual,也就是说手动设置:
auto lo iface lo inet loopback iface enp1s0 inet manual iface enp2s0 inet manual iface enp3s0 inet manual iface enp4s0 inet manual auto vmbr0 iface vmbr0 inet manual bridge-ports enp1s0 bridge-stp off bridge-fd 0 auto vmbr1 iface vmbr1 inet manual bridge-ports enp2s0 bridge-stp off bridge-fd 0 auto vmbr2 iface vmbr2 inet manual bridge-ports enp3s0 bridge-stp off bridge-fd 0
我本来尝试把iface vmbr0 inet manal改成iface vmbr0 inet dhcp,结果发现并不能在开机时获取一个IP,后来经过查看日志发现,系统启动的过程,是会先去请求DHCP,当所有网络接口初始化完毕后才会启动虚拟机,因此由于主机vmbr0在请求DHCP的时候,虚拟机还没启动,所以自然无法获得IP。那怎么办呢?
后来我想了个办法,就是弄个计划任务,每隔1分钟检查vmbr0是否有IP,如果没有就去请求一个,这样就能解决问题了,脚本如下:
#!/bin/sh vmbr0_ip=$(/usr/sbin/ifconfig vmbr0 | grep "inet " | awk '{print $2}') if [ -z "$vmbr0_ip" ] then echo "vmbr0 has no IP,get a IP" /usr/sbin/dhclient -4 vmbr0 else echo "vmbr0 already has an IP,skip.." fi
文件命名为getip.sh,然后再crontab里面加下面一行就行:
* * * * * /root/getip.sh
注意,脚本要赋予执行权限,即chmod +x getip.sh,并且你们应该也注意到了,脚本里面的程序要写绝对路径,即/usr/bin/ifconfig,如果只写ifconfig就会因为环境变量有问题而找不到这个程序,这个是个大坑。
保存后,每次启动系统,crontab都会去执行这个脚本,这样vmbr0就能自动获得一个IP了:

二、关于无法使用pve关闭虚拟机
这是个大坑,因为每次重启主机,系统都会先等待所有虚拟机关闭才会执行,而我一开始不知道怎么回事,关机的qmshutdown命令一直卡死,虚拟机一点反应都没有,感觉虚拟机没有正确响应关机命令。
后来查了一些资料才发现,这是因为QEMU设置里面开启了QEMU代理引起的:

如果一开始不知道这个设置是什么玩意开了的话,那就容易碰到这个坑。
QEMU代理即qemu-guest-agent,是一个运行在虚拟机里面的程序,主机可以直接通过qemu-guest-agent获取虚拟机的运行状态,比如IP地址,进程列表之类的,还可以直接在虚拟机里执行命令,如果开启了这个功能,虚拟机中必须安装相对应的qemu-ga才行。然而,我实际测试,编译内核的时候把qemu-ga一起编译进去,qemu-ga可以正常运行,主机也可以正确获得虚拟机的信息。然而还是无法关机。经过分析发现,TMD竟然关机只是在虚拟机里执行/sbin/shutdown,而openwrt里面没这个命令,取而代之的叫做/sbin/poweroff。由于我的openwrt编译的是squashfs版本,所以没法修改/sbin目录,重启就会恢复原始状态,所以决定放弃QEMU代理这个设定了。
如果关闭了qemu代理的话,主机控制虚拟机的方式就会使用最底层的ACPI信号来发送关机命令,这样就没有问题了。
P.S. 竟然QEMU agent关机的时候竟然只是执行/sbin/shutdown,一点都不智能啊,这也太sb了吧。。