在一台物理机上安装 Proxmox VE 虚拟化平台,同时运行 Windows、Linux、OpenWrt 等多个系统。

📝 配置 #

配件 型号
CPU AMD Ryzen 5 7600X
主板 微星 B650M 迫击炮 WIFI
显卡 AMD RX 6600 XT 8G
内存 光威龙武 24GBx2 DDR5 6800 C34
固态硬盘 致态 NVMe Ti600 Gen4 2T
机械硬盘 西数紫盘 WD43PURZ 4Tx4
网卡 板载 RTL8125B 2.5G 1-Port
PCIE RTL8125B 2.5G 4-Port
电源 安耐美 GM750W
机箱 半岛铁盒 F30

📝 主板BIOS设置 #

  • 开启EXPO内存超频
  • 温度墙设置85°C
  • 调整风扇转速曲线
  • 虚拟化相关设置:开启IMMUO、开启SVM

📝 文件系统 #

2T 的 NVMe 选择 ext4,作为 pve 的跟目录系统盘,另外划分1个 lvm-thin 存储池给各虚拟机做系统盘,这在pve安装时完成:

  • swapsize:交换分区
  • maxroot:pve跟目录大小
  • minfree:预留大小
  • maxvz:lvm卷大小,留空自动计算

16T 的 HDD 选择 zfs 组 raidz-1,作为1个存储池分配虚拟机做数据盘。这在pve安装完成后再细说。

📝 网络系统 #

             无线AP             光猫--互联网                
               │                 │ 
 ┌╴╴╴╴╴╴╴╴╴╴╴╴╴┼╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┼╴╴╴╴┐
 │ ┌─────┐  ┌──┴──┐  ┌─────┐  ┌──┴──┐ │
 │ │ LAN │  │ LAN │  │ LAN │  │ WAN │ │
 │ └──┬──┘  └─────┘  └─────┘  └─────┘ │
 │    │      VM100 ImmortalWrt        │
 └╴╴╴╴┼╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘
   ┌──┴──┐ 
   │vmbr0├╴╴╴╴─┬╴╴╴╴╴╴╴─┬╴╴╴╴╴╴╴╴┐
   └──┬──┘     │        │        │
   ┌╴╴┴╴╴┐  ┌╴╴┴╴╴┐  ┌╴╴┴╴╴┐  ┌╴╴┴╴╴┐
   │VM200│  │VM300│  │VM400│  │VMXXX│
   └╴╴╴╴╴┘  └╴╴╴╴╴┘  └╴╴╴╴╴┘  └╴╴╴╴╴┘

独立网卡4个口全部直通给 ImmortalWrt 软路由。

板载网卡作为 pve 管理口,同时作为各虚拟机 VirtIO 网卡的网桥vmbr0, VirtIO 网卡在网桥内的速度基本上瓶颈只取决于CPU和内存有多块。

还有个板载无线网卡MT7922 (RZ616) Wi-Fi 6E闲置。目前该芯片在 openwrt 上有发射功率只有 3dBm 的 bug,等修复后直通给软路由做无线模块,连硬路由都可以省了。

📝 pve设置 #

pve安装后的一些基本设置

## 一些直通设置
vim /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet iommu=pt"
update-grub

echo "vfio" >> /etc/modules
echo "vfio_iommu_type1" >> /etc/modules
echo "vfio_pci" >> /etc/modules
update-initramfs -u -k all

## 禁用ipv6
echo 'net.ipv6.conf.all.disable_ipv6=1' >> /etc/sysctl.conf
echo 'net.ipv6.conf.default.disable_ipv6=1' >> /etc/sysctl.conf

## 终端粘贴后不要选中
echo "bind 'set enable-bracketed-paste off'" >> /etc/profile

## 重启
reboot

## 检查设置
dmesg | grep IOMMU
dmesg | grep -i vfio
dmesg | grep remapping


## 获取系统版本代号
export OS_NAME=$(grep VERSION_CODENAME /etc/os-release | cut -d '=' -f2)

## 换源
cp /etc/apt/sources.list /etc/apt/sources.list.$(date +"%Y%m%d%H%M%S")
echo "" > /etc/apt/sources.list
echo "deb http://mirrors.tencent.com/debian/ $OS_NAME main non-free-firmware" >> /etc/apt/sources.list
echo "deb http://mirrors.tencent.com/debian-security/ $OS_NAME-security main" >> /etc/apt/sources.list
echo "deb http://mirrors.tencent.com/debian/ $OS_NAME-backports main" >> /etc/apt/sources.list

## 禁用订阅源使用清华的pve源
echo "" > /etc/apt/sources.list.d/pve-enterprise.list
echo "" > /etc/apt/sources.list.d/ceph.list 
echo "deb https://mirrors.tuna.tsinghua.edu.cn/proxmox/debian/pve $OS_NAME pve-no-subscription" >> /etc/apt/sources.list

## 安装常用软件
apt-get update
apt-get install lsb-release curl wget git zip gnupg2 ca-certificates dnsutils vim -y

📝 创建ZFS存储盘 #

在 web 界面中选择 pve -> 磁盘 -> ZFS 创建存储池。查看文档了解更多。

默认情况下 zfs 不会应用精简配置,即划分 vm 磁盘时将立即占用全部空间,想实现像 lvm-thin 那样实际用多少就占用多少的效果,可以在数据中心 -> 存储中选择创建的 zfs 存储池勾选“精简配置”,或者在/etc/pve/storage.cfg添加sparse选项:

zfspool: zpool1
        pool zpool1
        content rootdir,images
        mountpoint /zpool1
        nodes pve
        sparse 1

一些zfs调优:

## ZFS 的去重功能 非常吃内存,视情况关闭,否则会占用大量 RAM。
zfs set dedup=off <pool_name>

## 默认情况下,ZFS 记录每次文件访问时间(atime),会导致额外的 IO 负担。关闭它可以提高性能
zfs set atime=off <pool_name>

## ARC是 ZFS 主要的内存缓存,默认会占用大量 RAM。对于低 RAM 设备,可以手动限制 ARC 以避免占用太多内存。
## 10 * 2^30 = 10737418240 = 10G 
echo "options zfs zfs_arc_max=10737418240" > /etc/modprobe.d/zfs.conf
update-initramfs -u -k all
reboot

📝 安装 ImmortalWrt #

也适用于 pve 安装 OpenWrt。大概步骤:

  1. 创建虚拟机,不使用任何iso镜像,删掉默认磁盘。
  2. 创建后添加 pci 设备选择对应的网卡直通。
  3. 在官网下载系统镜像并导入:
## 下载
wget https://downloads.immortalwrt.org/releases/24.10.1/targets/x86/64/immortalwrt-24.10.1-x86-64-generic-ext4-combined.img.gz -O immortalwrt.img.gz
gunzip immortalwrt.img.gz

## 导入
qm disk import <vmid> <source> <storage> [OPTIONS] ## 语法
qm disk import 100 immortalwrt.img local-lvm ## 示例
  1. 在 web 界面中找到未使用磁盘点击编辑添加
  2. 在选项中调整磁盘引导顺序
  3. 启动

📝 安装 Windows #

Windows 是 pve AIO 系统中的重点环节,包括各种直通设置等。安装完成后的配置截图:

一些性能优先的最佳实践:

  • 关闭内存膨胀
  • CPU类型选择host
  • VirtIO SCSI single 磁盘,勾选丢弃、IO thread、SSD 仿真,缓存设置无(适用nvme)
  • VirtIO 网卡,Multiqueue 设置为 cpu 相同个数

在设置相关直通之前,先在 pve 的 vnc 中最小化正常安装 win10,显卡暂时设置为默认。由于默认情况下 win 没有 virtio 驱动,需要在创建 vm 时添加额外的驱动镜像:

alt text

  • Windows 安装前:挂载 virtio-win.iso,手动加载虚拟磁盘驱动安装 Windows。
  • Windows 安装后:运行 virtio-win-guest-tools.exe,自动安装所有 VirtIO 驱动和 QEMU Guest Agent。

📝 显卡直通 #

windows 安装成功后,开始设置显卡直通。

首先找到显卡设备的id。以下是一个查看系统 pci 设备的脚本。注意查看设备的 IOMMU 组是否独立,以及设备地址、供应商ID和设备ID

for g in /sys/kernel/iommu_groups/*/devices/*; do echo "IOMMU Group ${g%/devices/*}:" $(lspci -nns ${g##*/}); done | grep -v '\[060[04]\]' | sed 's|/sys/kernel/iommu_groups/||' | sort -V

找到显卡相关输出,在我的例子中,03:00.0是显卡。03:00.1是显卡自带的 HDMI 声卡:

IOMMU Group 15: 03:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 23 [Radeon RX 6600/6600 XT/6600M] [1002:73ff] (rev c1)
IOMMU Group 16: 03:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 21/23 HDMI/DP Audio Controller [1002:ab28]

将显卡分配给 vfio-pci 驱动:

echo "options vfio-pci ids=1002:73ff,1002:ab28 disable_vga=1" >> /etc/modprobe.d/vfio.conf
update-initramfs -u -k all
reboot

将显卡直通给 windows 虚拟机。

qm set VMID -hostpciX 03:00,x-vga=1,pcie=1,rombar=1,romfile=ASRock.RX6600XT.8192.210607.rom

注意替换相应的字段:

  • VMID:在创建 vm 时设置的id
  • hostpciXx代表 vm 的 pci 设备编号,从hostpci0开始依次递增。
  • romfile:可在 techpowerup 上下载,并放入/usr/share/kvm/

然后在 web 界面上将 vm 的显示设置为无,并开机,查看显示器是否正常输出。正常的话从AMD官网下载显卡驱动安装。

📝 usb直通 #

没什么好说的,在 web 界面选择添加 usb 设备,直通 usb 端口即可。

📝 音频直通 #

将主板的 3.5mm 音频口直通给 windows 虚拟机。

首先根据上述的脚本找到主板的声卡:

IOMMU Group 31: 18:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Raphael [1002:164e] (rev c7)
IOMMU Group 32: 18:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Rembrandt Radeon High Definition Audio Controller [1002:1640]
IOMMU Group 36: 18:00.6 Audio device [0403]: Advanced Micro Devices, Inc. [AMD] Family 17h/19h HD Audio Controller [1022:15e3]

在我的例子中:

  • 18:00.0是 CPU 集成的核显
  • 18:00.1是核显的 HDMI 声卡
  • 18:00.6是主板集成的声卡

将声卡分配给 vfio-pci 驱动:

echo "options vfio-pci ids=1022:15e3" >> /etc/modprobe.d/vfio.conf
update-initramfs -u -k all
reboot

直通主板的声卡:

qm set VMID -hostpciX 18:00.6

然后在主板官网下载声卡驱动安装。

📝 硬盘直通 #

如果你想将整个硬盘直接分配给 vm 使用,可使用硬盘直通。注意硬盘直通后快照功能将不起作用,移除后可正常快照。

查找磁盘ID:

ls -l /dev/disk/by-id/ | grep -E '(ata-|nvme-)' | grep -vE '(part[0-9]|_[0-9] ->)' | awk '{print "/dev/disk/by-id/" $9 " -> " $11}'

硬盘直通:

qm set VMID -scsiX /dev/disk/by-id/ata-WDC_WD30EZRZ-00Z5HB0_WD-WCC4N6XD9JE5

📝 开机键直通 #

默认情况下,windows 虚拟机开机时需要找个另外的设备在 web 界面点击启动,这不太优雅。可以 hook 电源键事件到自定义脚本,按下电源键直接开机/关机虚拟机。物理机完全关机状态下,按下电源键是正常启动物理机。

修改默认电源键行为

## 编辑配置文件
vim /etc/systemd/logind.conf

## 将HandlePowerKey设置为ignore
## 默认为 poweroff
HandlePowerKey=ignore 

创建开关机脚本

## 安装acpi
apt update && apt install acpid acpi-support -y

## 创建脚本
touch /etc/acpi/power_btn_hook.sh

编辑/etc/acpi/power_btn_hook.sh

#!/bin/bash
VMID=300 ## 注意修改VMID
STATUS=$(qm status $VMID | awk '{print $2}')

if [ "$STATUS" == "running" ]; then
    logger -t qm "VM $VMID is shutting down..."
    qm shutdown $VMID
elif [ "$STATUS" == "stopped" ]; then
    logger -t qm "VM $VMID is starting..."
    qm start $VMID
fi

授予执行权限。后面会使用。

chmod +x /etc/acpi/power_btn_hook.sh

找到电源键事件ID

## 开始监听电源键事件
acpi_listen

## 按下电源键,这应该会输出
button/power PBTN 00000080 00000000
button/power LNXPWRBN:00 00000080 00000032

将电源键行为指向我们的脚本

编辑/etc/acpi/events/power-button

event=button/power PBTN 00000080 00000000
action=/etc/acpi/power_btn_hook.sh

重启acpid

systemctl restart acpid

📝 性能测试 #

内存

memtest

硬盘

NVMe VirtIO SCSI LVM

CrystalDiskMar

鲁大师

不得不多鲁大师是真的流氓软件,测试完赶紧快照回滚。

ludashi

网络

VirtIO --> VirtIO

root@debian:~# iperf3 -c 10.0.0.9
Connecting to host 10.0.0.9, port 5201
[  5] local 10.0.0.16 port 37314 connected to 10.0.0.9 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  3.81 GBytes  32.7 Gbits/sec    0   2.27 MBytes
[  5]   1.00-2.00   sec  6.41 GBytes  55.1 Gbits/sec    0   2.53 MBytes
[  5]   2.00-3.00   sec  6.48 GBytes  55.6 Gbits/sec    0   2.53 MBytes
[  5]   3.00-4.00   sec  5.31 GBytes  45.6 Gbits/sec    0   2.79 MBytes
[  5]   4.00-5.00   sec  6.45 GBytes  55.4 Gbits/sec    0   2.93 MBytes
[  5]   5.00-6.00   sec  3.61 GBytes  31.0 Gbits/sec    0   2.93 MBytes
[  5]   6.00-7.00   sec  2.38 GBytes  20.4 Gbits/sec   45   2.93 MBytes
[  5]   7.00-8.00   sec  6.38 GBytes  54.8 Gbits/sec    0   2.93 MBytes
[  5]   8.00-9.00   sec  6.40 GBytes  55.0 Gbits/sec    0   2.93 MBytes
[  5]   9.00-10.00  sec  6.46 GBytes  55.5 Gbits/sec    0   2.93 MBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  53.7 GBytes  46.1 Gbits/sec   45             sender
[  5]   0.00-10.00  sec  53.7 GBytes  46.1 Gbits/sec                  receiver

iperf Done.

VirtIO --> NIC passthrough

root@debian:~# iperf3 -c 10.0.0.1
Connecting to host 10.0.0.1, port 5201
[  5] local 10.0.0.16 port 37394 connected to 10.0.0.1 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec   284 MBytes  2.38 Gbits/sec    0   3.30 MBytes
[  5]   1.00-2.00   sec   281 MBytes  2.36 Gbits/sec    0   3.30 MBytes
[  5]   2.00-3.00   sec   280 MBytes  2.35 Gbits/sec    0   3.30 MBytes
[  5]   3.00-4.00   sec   281 MBytes  2.36 Gbits/sec    0   3.30 MBytes
[  5]   4.00-5.00   sec   280 MBytes  2.35 Gbits/sec    0   3.30 MBytes
[  5]   5.00-6.00   sec   280 MBytes  2.35 Gbits/sec    0   3.30 MBytes
[  5]   6.00-7.00   sec   281 MBytes  2.36 Gbits/sec    0   3.30 MBytes
[  5]   7.00-8.00   sec   280 MBytes  2.35 Gbits/sec    0   3.30 MBytes
[  5]   8.00-9.00   sec   281 MBytes  2.36 Gbits/sec    0   3.30 MBytes
[  5]   9.00-10.00  sec   280 MBytes  2.35 Gbits/sec    0   3.30 MBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  2.74 GBytes  2.36 Gbits/sec    0             sender
[  5]   0.00-10.01  sec  2.74 GBytes  2.35 Gbits/sec                  receiver

iperf Done.

📝 一些问题 #

显卡 reset 问题

我的显卡有 reset 问题,直通后进系统直接卡死崩溃:

Apr 09 17:59:30 pve pvedaemon[1809]: error writing '1' to '/sys/bus/pci/devices/0000:03:00.0/reset': Inappropriate ioctl for device
Apr 09 17:59:30 pve pvedaemon[1809]: failed to reset PCI device '0000:03:00.0', but trying to continue as not all devices need a reset

一个解决方案是在 pve 开机时强制重置1次解决,如果要使用请自行修改。

gpu_reset.sh

#!/bin/bash

TARGET="0000:03:00.0"
EXPECTED_NAME="RX 6600"

if [ -d "/sys/bus/pci/devices/$TARGET" ]; then
    if lspci -s "$TARGET" | grep -qi "$EXPECTED_NAME"; then
        echo 1 > "/sys/bus/pci/devices/$TARGET/remove"
        sleep 1s
        echo 1 > /sys/bus/pci/rescan
    fi
fi

gpu_reset.service

[Unit]
Description=Reset the PCI devices for smooth passthrough.
After=network.target

[Service]
Type=oneshot
ExecStart=bash /root/gpu_reset/gpu_reset.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

音频直通问题

后置3.5音频口可以正常使用,机箱前置音频口可以识别但没有任何声音。各种尝试后无解,目前使用 usb 耳机解决。

“安全删除硬件”问题

windows 将显卡、硬盘、网卡都识别为热插拔/可移动设备,并且可以在任务栏托盘点击“安全删除硬件并弹出”,查看相关讨论

暂时没有优雅的方法解决,不要点击即可。

虚拟机检测问题

很多网游过不了虚拟机检测,特别是腾讯系的游戏根本启动不了。单机游戏或其他主流软件目前没遇到虚拟化环境无法运行的问题。

有些方法可以去虚拟化,但基本上都会对 pve 系统进行破坏性更改,不建议这样做。