本地搭建AI及实验平台

一条命令输出,硬件配置

echo "===== CPU ====="; lscpu | grep -E 'Model name|CPU\(s\)'; echo -e "\n===== 内存 ====="; free -h; echo -e "\n===== AMD显卡 ====="; lspci | grep -E "VGA|3D"; echo -e "\n===== 显卡完整信息 ====="; sudo lshw -C display; echo -e "\n===== 磁盘 ====="; df -h


===== CPU =====
CPU(s) scaling MHz:                      49%

===== 内存 =====
               total        used        free      shared  buff/cache   available
内存:          15Gi       690Mi        14Gi       1.5Mi       560Mi        14Gi
交换:         4.0Gi          0B       4.0Gi

===== AMD显卡 =====
01:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Polaris 20 XL [Radeon RX 580 2048SP] (rev e7)

===== 显卡完整信息 =====
  *-display
       description: VGA compatible controller
       product: Polaris 20 XL [Radeon RX 580 2048SP]
       vendor: Advanced Micro Devices, Inc. [AMD/ATI]
       physical id: 0
       bus info: pci@0000:01:00.0
       version: e7
       width: 64 bits
       clock: 33MHz
       capabilities: pm pciexpress msi vga_controller bus_master cap_list rom
       configuration: driver=amdgpu latency=0
       resources: irq:31 memory:e0000000-efffffff memory:f0000000-f01fffff ioport:e000(size=256) memory:f7e00000-f7e3ffff memory:c0000-dffff

===== 磁盘 =====
文件系统        大小  已用  可用 已用% 挂载点
tmpfs           1.6G  1.5M  1.6G    1% /run
/dev/sda2       116G   12G   99G   11% /
tmpfs           7.8G     0  7.8G    0% /dev/shm
tmpfs           5.0M   12K  5.0M    1% /run/lock
efivarfs        128K   38K   86K   31% /sys/firmware/efi/efivars
/dev/sda1       1.1G  6.2M  1.1G    1% /boot/efi
tmpfs           1.6G   80K  1.6G    1% /run/user/1000
shitou@shitou-To-be-filled-by-O-E-M:~$

llama.cpp(不使用 Ollama)

RX580‑2048SP 不能用 ROCm,只能 Vulkan 后端,llama.cpp 是底层原生推理引擎,可控性更高,没有 ollama 那一层封装,可以直接跑 GGUF 千问模型。

第一步安装依赖

sudo apt install -y build-essential cmake git libvulkan-dev vulkan-tools mesa-vulkan-drivers glslang-tools spirv-headers

识别显卡


shitou@shitou-To-be-filled-by-O-E-M:~$ vulkaninfo --summary
WARNING: [../src/amd/vulkan/radv_physical_device.c:2153] Code 0 : Could not open device /dev/dri/renderD128: Permission denied (VK_ERROR_INCOMPATIBLE_DRIVER)
==========
VULKANINFO
==========

Vulkan Instance Version: 1.3.275


Instance Extensions: count = 24
-------------------------------
VK_EXT_acquire_drm_display             : extension revision 1
VK_EXT_acquire_xlib_display            : extension revision 1
VK_EXT_debug_report                    : extension revision 10
VK_EXT_debug_utils                     : extension revision 2
VK_EXT_direct_mode_display             : extension revision 1
VK_EXT_display_surface_counter         : extension revision 1
VK_EXT_headless_surface                : extension revision 1
VK_EXT_surface_maintenance1            : extension revision 1
VK_EXT_swapchain_colorspace            : extension revision 5
VK_KHR_device_group_creation           : extension revision 1
VK_KHR_display                         : extension revision 23
VK_KHR_external_fence_capabilities     : extension revision 1
VK_KHR_external_memory_capabilities    : extension revision 1
VK_KHR_external_semaphore_capabilities : extension revision 1
VK_KHR_get_display_properties2         : extension revision 1
VK_KHR_get_physical_device_properties2 : extension revision 2
VK_KHR_get_surface_capabilities2       : extension revision 1
VK_KHR_portability_enumeration         : extension revision 1
VK_KHR_surface                         : extension revision 25
VK_KHR_surface_protected_capabilities  : extension revision 1
VK_KHR_wayland_surface                 : extension revision 6
VK_KHR_xcb_surface                     : extension revision 6
VK_KHR_xlib_surface                    : extension revision 6
VK_LUNARG_direct_driver_loading        : extension revision 1

Instance Layers: count = 3
--------------------------
VK_LAYER_INTEL_nullhw       INTEL NULL HW                1.1.73   version 1
VK_LAYER_MESA_device_select Linux device selection layer 1.4.303  version 1
VK_LAYER_MESA_overlay       Mesa Overlay layer           1.4.303  version 1

Devices:
========
GPU0:
        apiVersion         = 1.4.318
        driverVersion      = 25.2.8
        vendorID           = 0x10005
        deviceID           = 0x0000
        deviceType         = PHYSICAL_DEVICE_TYPE_CPU
        deviceName         = llvmpipe (LLVM 20.1.2, 256 bits)
        driverID           = DRIVER_ID_MESA_LLVMPIPE
        driverName         = llvmpipe
        driverInfo         = Mesa 25.2.8-0ubuntu0.24.04.2 (LLVM 20.1.2)
        conformanceVersion = 1.3.1.1
        deviceUUID         = 6d657361-3235-2e32-2e38-2d3075627500
        driverUUID         = 6c6c766d-7069-7065-5555-494400000000

========================================================================================================================================================================================

系统版本:Ubuntu 24.04.4 LTS

显卡:AMD Radeon RX580 2048SP(amdgpu 驱动正常适配)

内存:16G 大内存(满足多套云组件、虚拟机、AI 推理运行)

磁盘规划

  • 系统盘 sda:119G,已用12%,剩余空间充足,用于存放系统、实验环境、镜像文件

  • 数据盘 sdb:465G 闲置裸盘,可直通虚拟机、单独做虚拟机数据盘,不占用系统盘空间

ip 确定

### 想切回全部 DHCP 自动获取(回滚)

重新编辑 `01-network-manager-all.yaml`:

```
network:
  ethernets:
    enp3s0:
      dhcp4: yes
      dhcp6: yes
  version: 2
  renderer: NetworkManager
```


设置为静态,
network:
  ethernets:
    enp3s0:
      dhcp4: no
      addresses:
        - 192.168.31.29/24
      routes:
        - to: default
          via: 192.168.31.1
      nameservers:
        addresses:
          - 223.5.5.5
          - 114.114.114.114
      dhcp6: yes
  version: 2
  renderer: NetworkManager
shitou@shitou-To-be-filled-by-O-E-M:~$

搭建前准备

1 .先确认,是否支持虚拟化

by-O-E-M:~$
egrep -c '(vmx|svm)' /proc/cpuinfo
16

16个核心已经支持,///

确认kvm 是否可用

#lsmod | grep kvm

kvm_intel             540672  0
kvm                  1507328  1 kvm_intel
irqbypass              16384  1 kvm
shitou@shitou-To-be-filled-by-O-E-M:~$
**KVM 内核模块全部正常加载**

- `kvm_intel`:Intel KVM 驱动已载入
- `kvm`:KVM 核心框架
- `irqbypass`:虚拟机中断直通依赖模块

> 
> `kvm_intel 后面的 0`:代表**当前没有正在运行的 KVM 虚拟机**,属于正常现象,启动虚拟机后这个数字会上涨。

安装 KVM 基础虚拟化栈(Ubuntu24.04)

sudo apt update
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager ovmf


sudo systemctl enable --now libvirtd  设置开机启动,可自己设置是否开机启动,

sudo usermod -aG libvirt $USER
sudo usermod -aG kvm $USER
### 两个组分别作用

1. **libvirt 组**
控制访问 `libvirtd` 服务,允许普通用户操作 virsh、virt‑manager:创建 / 启停虚拟机、管理网络存储。
不加:`virsh list` 会报权限拒绝,需要 sudo 才能操作。
2. **kvm 组**
访问 `/dev/kvm` 设备节点,直接调用 KVM 硬件虚拟化;
libvirt 后台 root 运行时其实不太依赖这个组;**如果你直接裸跑 qemu(不通过 libvirt)才必须 kvm 组权限**。

> 
> 稳妥做法两个都加上,兼容 libvirt 和直接 qemu 调用。

sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager ovmf

1. qemu‑kvm

QEMU + KVM 后端,真正的虚拟机执行引擎。

  • 负责 CPU、内存、磁盘、网卡模拟,调用 /dev/kvm 硬件加速,没有它无法运行 KVM 虚拟机。

2. libvirt‑daemon‑system

libvirt 系统级后台服务 libvirtd

  • 守护进程,管理全部虚拟机生命周期:启动、停止、快照、网络、存储池。

  • 系统开机自启,virshvirt‑manager 都要和这个 daemon 通信。

3. libvirt‑clients

libvirt 命令行工具集,核心就是 virsh

  • virsh listvirsh startvirsh define 等全部命令来自这个包;日常管理虚拟机终端工具。

4. bridge‑utils

网桥工具 brctl

  • 用来创建桥接网络,让虚拟机拿到局域网真实 IP,而不是仅 NAT 内网。

现代也支持用 iproute2,bridge‑utils 是传统网桥管理工具。

5. virt‑manager

图形化虚拟机管理器(GUI)

  • 桌面软件,可视化创建虚拟机、调硬件、看控制台、管理快照网络;需要桌面环境才能打开。

  • 命令:virt-manager

6. ovmf

UEFI 固件,替代传统 BIOS 启动虚拟机。

  • 虚拟机支持 UEFI 启动、Secure Boot;现在 Windows11 虚拟机必须用 OVMF,旧 BIOS 无法安装 Win11。

  • 固件文件一般放在 /usr/share/OVMF/

允许普通用户操作

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo usermod -aG libvirt $USER

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo usermod -aG kvm $USER

然后用整块磁盘做 PV,删掉 sdb1 分区

shitou@shitou-To-be-filled-by-O-E-M:~$ lsblk
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
loop0    7:0    0    74M  1 loop /snap/core22/2292
loop1    7:1    0  66.8M  1 loop /snap/core24/1643
loop2    7:2    0     4K  1 loop /snap/bare/5
loop3    7:3    0 251.7M  1 loop /snap/firefox/7766
loop4    7:4    0  18.5M  1 loop /snap/firmware-updater/210
loop5    7:5    0  16.5M  1 loop /snap/firmware-updater/226
loop6    7:6    0 531.4M  1 loop /snap/gnome-42-2204/247
loop7    7:7    0 614.5M  1 loop /snap/gnome-46-2404/164
loop8    7:8    0  91.7M  1 loop /snap/gtk-common-themes/1535
loop9    7:9    0   402M  1 loop /snap/mesa-2404/1839
loop10   7:10   0  10.8M  1 loop /snap/snap-store/1270
loop11   7:11   0  11.8M  1 loop /snap/snap-store/1390
loop12   7:12   0  48.1M  1 loop /snap/snapd/25935
loop13   7:13   0   576K  1 loop /snap/snapd-desktop-integration/343
sda      8:0    0 119.2G  0 disk
├─sda1   8:1    0     1G  0 part /boot/efi
└─sda2   8:2    0 118.2G  0 part /
sdb      8:16   0 465.8G  0 disk
└─sdb1   8:17   0 465.8G  0 part
shitou@shitou-To-be-filled-by-O-E-M:~$ sudo wipefs -a /dev/sdb
/dev/sdb:8 个字节已擦除,位置偏移为 0x00000200 (gpt): 45 46 49 20 50 41 52 54
/dev/sdb:8 个字节已擦除,位置偏移为 0x7470c05e00 (gpt): 45 46 49 20 50 41 52 54
/dev/sdb:2 个字节已擦除,位置偏移为 0x000001fe (PMBR): 55 aa
/dev/sdb:将调用 ioctl 来重新读分区表:成功
shitou@shitou-To-be-filled-by-O-E-M:~$ lsblk
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
loop0    7:0    0    74M  1 loop /snap/core22/2292
loop1    7:1    0  66.8M  1 loop /snap/core24/1643
loop2    7:2    0     4K  1 loop /snap/bare/5
loop3    7:3    0 251.7M  1 loop /snap/firefox/7766
loop4    7:4    0  18.5M  1 loop /snap/firmware-updater/210
loop5    7:5    0  16.5M  1 loop /snap/firmware-updater/226
loop6    7:6    0 531.4M  1 loop /snap/gnome-42-2204/247
loop7    7:7    0 614.5M  1 loop /snap/gnome-46-2404/164
loop8    7:8    0  91.7M  1 loop /snap/gtk-common-themes/1535
loop9    7:9    0   402M  1 loop /snap/mesa-2404/1839
loop10   7:10   0  10.8M  1 loop /snap/snap-store/1270
loop11   7:11   0  11.8M  1 loop /snap/snap-store/1390
loop12   7:12   0  48.1M  1 loop /snap/snapd/25935
loop13   7:13   0   576K  1 loop /snap/snapd-desktop-integration/343
sda      8:0    0 119.2G  0 disk
├─sda1   8:1    0     1G  0 part /boot/efi
└─sda2   8:2    0 118.2G  0 part /
sdb      8:16   0 465.8G  0 disk

# 创建物理卷、卷组

sudo pvcreate /dev/sdb

sudo vgcreate vg-vmdata /dev/sdb

sudo vgs

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo pvcreate /dev/sdb
  Physical volume "/dev/sdb" successfully created.
shitou@shitou-To-be-filled-by-O-E-M:~$ sudo vgcreate vg-vmdata /dev/sdb
  Volume group "vg-vmdata" successfully created
shitou@shitou-To-be-filled-by-O-E-M:~$ sudo vgs
  VG        #PV #LV #SN Attr   VSize    VFree
  vg-vmdata   1   0   0 wz--n- <465.76g <465.76g
shitou@shitou-To-be-filled-by-O-E-M:~$

然后创建存储池

/

下面报错了,

libvirt 存储池配置:

```
cat > ~/vm-pool.xml <<'EOF'
<pool type='logical'>
  <name>vm-lvm-pool</name>
  <source>
    <vgname>vg-vmdata</vgname>
  </source>
  <target>
    <path>/dev/vg-vmdata</path>
  </target>
</pool>
EOF
```

导入、启动、开机自启:过程与报错整理
sudo virsh pool-define ~/vm-pool.xml
sudo virsh pool-start vm-lvm-pool
sudo virsh pool-autostart vm-lvm-poo 

shitou@shitou-To-be-filled-by-O-E-M:~$ cat > ~/vm-pool.xml <<'EOF'
<pool type='logical'>
  <name>vm-lvm-pool</name>
  <source>
    <vgname>vg-vmdata</vgname>
  </source>
  <target>
    <path>/dev/vg-vmdata</path>
  </target>
</pool>
EOF
shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-define ~/vm-pool.xml
Pool vm-lvm-pool defined from /home/shitou/vm-pool.xml

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-start vm-lvm-pool
error: Failed to start pool vm-lvm-pool
error: unsupported configuration: cannot find logical volume group name 'vm-lvm-pool'

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo vgs
  VG        #PV #LV #SN Attr   VSize    VFree
  vg-vmdata   1   0   0 wz--n- <465.76g <465.76g
shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-undefine vm-lvm-pool
Pool vm-lvm-pool has been undefined

shitou@shitou-To-be-filled-by-O-E-M:~$ cat > ~/vm-pool.xml <<'EOF'
<pool type='logical'>
  <name>vm-lvm-pool</name>
  <source>
    <vgname>vg-vmdata</vgname>
  </source>
  <target>
    <path>/dev/vg-vmdata</path>
  </target>
</pool>
EOF
shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-define ~/vm-pool.xml
Pool vm-lvm-pool defined from /home/shitou/vm-pool.xml

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-start vm-lvm-pool
error: Failed to start pool vm-lvm-pool
error: unsupported configuration: cannot find logical volume group name 'vm-lvm-pool'

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-destroy vm-lvm-pool
error: Failed to destroy pool vm-lvm-pool
error: Requested operation is not valid: storage pool 'vm-lvm-pool' is not active

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-undefine vm-lvm-pool
Pool vm-lvm-pool has been undefined

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-create-as --type logical vm-lvm-pool --source-vg vg-vmdata --target /dev/vg-vmdata
error: command 'pool-create-as' doesn't support option --source-vg
shitou@shitou-To-be-filled-by-O-E-M:~$ cat <<'EOF' > /tmp/vm-pool.xml
<pool type='logical'>
  <name>vm-lvm-pool</name>
  <source>
    <vgname>vg-vmdata</vgname>
  </source>
  <target>
    <path>/dev/vg-vmdata</path>
  </target>
</pool>
EOF
shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-define /tmp/vm-pool.xml
Pool vm-lvm-pool defined from /tmp/vm-pool.xml

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-start vm-lvm-pool
error: Failed to start pool vm-lvm-pool
error: unsupported configuration: cannot find logical volume group name 'vm-lvm-pool'

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-autostart vm-lvm-pool
Pool vm-lvm-pool marked as autostarted

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-list --all
 Name          State      Autostart
-------------------------------------
 vm-lvm-pool   inactive   yes

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-info vm-lvm-pool
Name:           vm-lvm-pool
UUID:           6da9c0ab-db62-4e00-ade3-079fe1569fce
State:          inactive
Persistent:     yes
Autostart:      yes

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-undefine vm-lvm-pool
Pool vm-lvm-pool has been undefined

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-list --all
 Name   State   Autostart
---------------------------

shitou@shitou-To-be-filled-by-O-E-M:~$ cat <<'EOF' > /tmp/vm-pool.xml
<pool type='logical'>
  <name>vm-lvm-pool</name>
  <source>
    <name>vg-vmdata</name>
  </source>
  <target>
    <path>/dev/vg-vmdata</path>
  </target>
</pool>
EOF
shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-define /tmp/vm-pool.xml
Pool vm-lvm-pool defined from /tmp/vm-pool.xml

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-start vm-lvm-pool
Pool vm-lvm-pool started

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-autostart vm-lvm-pool
Pool vm-lvm-pool marked as autostarted

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-list --all
 Name          State    Autostart
-----------------------------------
 vm-lvm-pool   active   yes

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-info vm-lvm-pool
Name:           vm-lvm-pool
UUID:           6c223438-46c3-49d4-894f-ceab17a45669
State:          running
Persistent:     yes
Autostart:      yes
Capacity:       465.76 GiB
Allocation:     0.00 B
Available:      465.76 GiB

# 失败根因解释

## 1、报错原文

```
error: unsupported configuration: cannot find logical volume group name 'vm-lvm-pool'
```

> 
> 现象:明明 LVM 卷组叫`vg‑vmdata`,libvirt 却拿着存储池名字`vm‑lvm‑pool`去系统找 LVM 卷组,当然找不到,启动失败。

### 错误 XML(网上大量旧教程错误写法)

```
<pool type='logical'>
  <name>vm-lvm-pool</name>
  <source>
    <vgname>vg-vmdata</vgname>   <!-- ❌错误标签 Ubuntu/Debian libvirt不识别 <vgname> -->
  </source>
  <target>
    <path>/dev/vg-vmdata</path>
  </target>
</pool>
```

- 很多网上教程写 `<vgname>xxx</vgname>`,**这个标签不是 Ubuntu libvirt 的合法标签**。
- libvirt 读到不认识的`<vgname>`标签,直接忽略这个 source 段,**fallback 逻辑:拿 pool 的`<name>`(也就是`vm‑lvm‑pool`)当作 LVM 卷组名字去查找**。
- 系统里面不存在叫`vm‑lvm‑pool`的 VG,于是报错找不到卷组。

### ✅正确 XML 标签

```
<pool type='logical'>
  <name>vm-lvm-pool</name>
  <source>
    <name>vg-vmdata</name>  <!-- ✅在source内部用 <name> 指定LVM卷组名称 -->
  </source>
  <target>
    <path>/dev/vg-vmdata</path>
  </target>
</pool>
```

> 
> `<source><name>实际LVM卷组名</name></source>`,告诉 libvirt 去读取哪个物理卷组。

### 区分两个名字(最容易混淆)

表格

| 名称 | 属于哪一层 | 说明 |
| --- | --- | --- |
| `vm‑lvm‑pool` | libvirt 层 | **存储池名字**,仅 libvirt 内部识别,操作系统 LVM 看不见这个名字 |
| `vg‑vmdata` | 操作系统 LVM 层 | 真实卷组,`vgs`命令看到,操作系统内核识别 |

> 
> 坑:很多人把这两个名字搞混;网上复制来的 xml 大量使用`<vgname>`这个错误标签,Debian/Ubuntu 系 libvirt 不支持该标签,会触发 fallback bug。

---

# 本次完整正确操作总结

## 前置校验(必须确认)

```
# sdb裸盘,无分区
lsblk
# LVM卷组正常,465.76G空闲
sudo vgs
```

输出确认:`vg‑vmdata`,`VFree <465.76g`。

## 步骤 1:生成正确 xml(使用 source 内<name>标签,不是 vgname)

```
cat <<'EOF' > /tmp/vm-pool.xml
<pool type='logical'>
  <name>vm-lvm-pool</name>
  <source>
    <name>vg-vmdata</name>
  </source>
  <target>
    <path>/dev/vg-vmdata</path>
  </target>
</pool>
EOF
```

## 步骤 2:逐条执行,不要一次性堆一行,方便定位报错

```
# 将池配置注册进libvirt数据库
sudo virsh pool-define /tmp/vm-pool.xml

# 立刻启动存储池
sudo virsh pool-start vm-lvm-pool

# 设置开机自动启动
sudo virsh pool-autostart vm-lvm-pool
```

## 步骤 3:校验状态

```
sudo virsh pool-list --all
sudo virsh pool-info vm-lvm-pool
```

成功标志:

```
State:          running
Capacity:       465.76 GiB
Available:      465.76 GiB
```

## 步骤 4:清理临时文件

```
rm /tmp/vm-pool.xml
```

## 配套:libvirt 默认 NAT 网络检查

```
virsh net-list --all
# 如果default是inactive,执行
sudo virsh net-start default
sudo virsh net-autostart default
```

## 用户权限提醒

```
sudo usermod -aG libvirt $USER
sudo usermod -aG kvm $USER
```

> 
> ⚠️**必须注销重新登录系统,组权限才生效,su/sudo -s 不会刷新用户组**。

---

# 当前环境状态

1. CPU 硬件虚拟化 vmx 开启 ✔
2. kvm_intel 内核模块加载 ✔
3. qemu‑kvm + libvirt 整套软件安装完成 ✔
4. libvirtd 服务开机自启运行 ✔
5. sdb 磁盘创建 LVM 卷组`vg‑vmdata` ✔
6. libvirt LVM 存储池`vm‑lvm‑pool`状态 running,465.76G 可用 ✔
7. default NAT 网络就绪 ✔

> 
> 后续:virt‑manager 或者 cockpit 网页端新建虚拟机,磁盘选择存储池`vm‑lvm‑pool`,磁盘就落在 sdb,完全不占用系统盘 sda。

创建导入,存储池,

shitou@shitou-To-be-filled-by-O-E-M:~$ cat <<'EOF' > /tmp/vm-pool.xml
<pool type='logical'>
  <name>vm-lvm-pool</name>
  <source>
    <name>vg-vmdata</name>
  </source>
  <target>
    <path>/dev/vg-vmdata</path>
  </target>
</pool>
EOF
shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-define /tmp/vm-pool.xml
Pool vm-lvm-pool defined from /tmp/vm-pool.xml

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-start vm-lvm-pool
Pool vm-lvm-pool started

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-autostart vm-lvm-pool
Pool vm-lvm-pool marked as autostarted

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-list --all
 Name          State    Autostart
-----------------------------------
 vm-lvm-pool   active   yes

shitou@shitou-To-be-filled-by-O-E-M:~$ sudo virsh pool-info vm-lvm-pool
Name:           vm-lvm-pool
UUID:           6c223438-46c3-49d4-894f-ceab17a45669
State:          running
Persistent:     yes
Autostart:      yes
Capacity:       465.76 GiB
Allocation:     0.00 B
Available:      465.76 GiB

创建网络,查看网络状态,

cat <<'EOF' > /tmp/default-net.xml
<network>
  <name>default</name>
  <forward mode='nat'/>
  <bridge name='virbr0' stp='on' delay='0'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>
EOF

sudo virsh net-define /tmp/default-net.xml
sudo virsh net-start default
sudo virsh net-autostart default
rm /tmp/default-net.xml

sudo virsh net-list --all
 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes

开始管理虚拟机

选项 1:Cockpit 网页管理(推荐,不用桌面窗口,浏览器就能操作)

sudo apt install -y cockpit cockpit-machines
sudo systemctl enable --now cockpit.socket
sudo ufw allow 9090/tcp

查看宿主机 IP:

ip a

浏览器访问:https://你的IP:9090,输入宿主机账号密码登录,左侧【机器】管理虚拟机、存储池。

选项 2:桌面图形 virt‑manager

virt-manager

创建虚拟机的关键要点(一定要记住)

  1. 安装源:准备好系统 ISO 镜像(ISO 放系统盘 sdb 不用,放 sda 即可)

  2. 磁盘:存储池选择 vm‑lvm‑pool,这样硬盘才存在 sdb,不占用系统盘。

  3. 固件:选择OVMF (UEFI),Win11 必须这个。

  4. 磁盘总线、网卡总线:选virtio,性能最高。

  5. 网卡默认就是 default 网络,直接上网。

安装出错sudo apt install -y cockpit cockpit‑machines

sudo apt install -y cockpit cockpit‑machines
[sudo] shitou 的密码:

正在读取软件包列表... 完成

正在分析软件包的依赖关系树... 完成

正在读取状态信息... 完成

E: 无法定位软件包 cockpit‑machines

然后

sudo apt update

. /etc/os-release

sudo apt install -t ${VERSION_CODENAME}-backports cockpit cockpit-machines -y

sudo systemctl enable --now cockpit.socket

sudo ufw allow 9090/tcp

sudo usermod -aG libvirt,kvm $USER

然后现在完全直通,显卡,

#sudo dmesg | grep -i iommu
[sudo] shitou 的密码:
[    0.111439] DMAR-IR: IOAPIC id 2 under DRHD base  0xfed90000 IOMMU 0
[    0.209427] iommu: Default domain type: Translated
[    0.209429] iommu: DMA domain TLB invalidation policy: lazy mode
[    0.247476] pci 0000:00:00.0: Adding to iommu group 0
[    0.247498] pci 0000:00:01.0: Adding to iommu group 1
[    0.247513] pci 0000:00:1a.0: Adding to iommu group 2
[    0.247527] pci 0000:00:1b.0: Adding to iommu group 3
[    0.247562] pci 0000:00:1c.0: Adding to iommu group 4
[    0.247593] pci 0000:00:1c.4: Adding to iommu group 5
[    0.247624] pci 0000:00:1c.5: Adding to iommu group 6
[    0.247639] pci 0000:00:1d.0: Adding to iommu group 7
[    0.247669] pci 0000:00:1f.0: Adding to iommu group 8
[    0.247684] pci 0000:00:1f.2: Adding to iommu group 8
[    0.247698] pci 0000:00:1f.3: Adding to iommu group 8
[    0.247707] pci 0000:01:00.0: Adding to iommu group 1
[    0.247719] pci 0000:01:00.1: Adding to iommu group 1
[    0.247734] pci 0000:03:00.0: Adding to iommu group 9
[    0.247748] pci 0000:04:00.0: Adding to iommu group 10

修改 GRUB 内核参数(Intel 平台)

sudo nano /etc/default/grub

修改:

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash intel_iommu=on iommu=pt"

保存更新 grub

sudo update-grub
sudo reboot

dmesg | grep -i DMAR
sudo dmesg | grep -i DMAR
[sudo] shitou 的密码:
[    0.011441] ACPI: DMAR 0x00000000DEFEC9B8 000078 (v01 INTEL  SNB      00000001 INTL 00000001)
[    0.011454] ACPI: Reserving DMAR table memory at [mem 0xdefec9b8-0xdefeca2f]
[    0.038946] DMAR: IOMMU enabled
[    0.110874] DMAR: Host address width 36
[    0.110875] DMAR: DRHD base: 0x000000fed90000 flags: 0x1
[    0.110881] DMAR: dmar0: reg_base_addr fed90000 ver 1:0 cap c9008020660262 ecap f0105a
[    0.110884] DMAR: RMRR base: 0x000000df6a4000 end: 0x000000df6b2fff
[    0.110887] DMAR-IR: IOAPIC id 2 under DRHD base  0xfed90000 IOMMU 0
[    0.110889] DMAR-IR: HPET id 0 under DRHD base 0xfed90000
[    0.110890] DMAR-IR: Queued invalidation will be enabled to support x2apic and Intr-remapping.
[    0.111190] DMAR-IR: Enabled IRQ remapping in x2apic mode
[    0.241964] DMAR: No ATSR found
[    0.241966] DMAR: No SATC found
[    0.241967] DMAR: dmar0: Using Queued invalidation
[    0.242259] DMAR: Intel(R) Virtualization Technology for Directed I/O

安装依赖

sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils ovmf swtpm

这是 Ubuntu/Debian 安装 KVM+Libvirt 完整虚拟化环境 的一键安装命令,做显卡 / PCI 直通虚拟机必备包。逐个拆解每个软件包作用:

表格

包名

作用

qemu‑kvm

KVM 虚拟化底层,真正的虚拟机硬件模拟器,CPU 硬件加速核心

libvirt‑daemon‑system

libvirt 后台服务,管理虚拟机、网络、存储的守护进程

libvirt‑clients

客户端工具,virsh 命令就在这里,命令行管理虚拟机

bridge‑utils

网桥工具,用来做桥接网络,让虚拟机和主机同局域网(直通环境常用)

ovmf

UEFI 固件!虚拟机用 UEFI 启动,显卡直通必须要用 UEFI,传统 BIOS 容易黑屏失败

swtpm

TPM2.0 模拟器,虚拟机模拟 TPM 芯片,装 Windows10/1

把当前用户加入 libvirt/kvm 用户组,否则 virsh 会权限报错

sudo usermod -aG libvirt $USER
sudo usermod -aG kvm $USER

 sudo usermod -aG libvirt shitou
 sudo usermod -aG kvm shitou

安装 vendor‑reset(解决 RX580 复位 bug)

# 1.安装编译依赖、内核头文件
sudo apt install git dkms build-essential linux-headers-$(uname -r)


sudo apt install git dkms build-essential linux-headers-$(uname -r)
正在读取软件包列表... 完成
正在分析软件包的依赖关系树... 完成
正在读取状态信息... 完成
git 已经是最新版 (1:2.43.0-1ubuntu7.3)。
build-essential 已经是最新版 (12.10ubuntu1)。
linux-headers-7.0.0-31-generic 已经是最新版 (7.0.0-31.31~24.04.1)。
linux-headers-7.0.0-31-generic 已设置为手动安装。
下列软件包是自动安装的并且现在不需要了:
  libfwupd2 libwoff1
使用'sudo apt autoremove'来卸载它(它们)。
建议安装:
  menu
下列【新】软件包将被安装:
  dkms
升级了 0 个软件包,新安装了 1 个软件包,要卸载 0 个软件包,有 21 个软件包未被升级。
需要下载 51.5 kB 的归档。
解压缩后会消耗 196 kB 的额外空间。
您希望继续执行吗? [Y/n] y
获取:1 http://archive.ubuntu.com/ubuntu noble/main amd64 dkms all 3.0.11-1ubuntu13 [51.5 kB]
已下载 51.5 kB,耗时 1秒 (39.9 kB/s)
正在选中未选择的软件包 dkms。
(正在读取数据库 ... 系统当前共安装有 207870 个文件和目录。)
准备解压 .../dkms_3.0.11-1ubuntu13_all.deb  ...
正在解压 dkms (3.0.11-1ubuntu13) ...
正在设置 dkms (3.0.11-1ubuntu13) ...
正在处理用于 man-db (2.12.0-4build2) 的触发器 ...
# 2.克隆源码(会下载到当前目录,生成 vendor-reset 文件夹)
git clone https://github.com/gnif/vendor-reset.git

git clone https://github.com/gnif/vendor-reset.git
正克隆到 'vendor-reset'...
remote: Enumerating objects: 1063, done.
remote: Counting objects: 100% (251/251), done.
remote: Compressing objects: 100% (50/50), done.
remote: Total 1063 (delta 219), reused 203 (delta 200), pack-reused 812 (from 1)
接收对象中: 100% (1063/1063), 10.86 MiB | 6.98 MiB/s, 完成.
处理 delta 中: 100% (728/728), 完成.



# 3.进入源码目录
cd vendor-reset

# 4.dkms编译并安装内核模块
sudo dkms install .

sudo dkms install .
Sign command: /usr/bin/kmodsign
Certificate or key are missing, generating them using update-secureboot-policy...
Secure Boot not enabled on this system.
Signing key: /var/lib/shim-signed/mok/MOK.priv
Public certificate (MOK): /var/lib/shim-signed/mok/MOK.der
Creating symlink /var/lib/dkms/vendor-reset/0.1.1/source -> /usr/src/vendor-reset-0.1.1

Building module:
Cleaning build area...
make -j8 KERNELRELEASE=7.0.0-31-generic KDIR=/lib/modules/7.0.0-31-generic/build....
Signing module /var/lib/dkms/vendor-reset/0.1.1/build/vendor-reset.ko
Cleaning build area...

vendor-reset.ko.zst:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/7.0.0-31-generic/updates/dkms/
depmod....

# 5.把模块写入开机自动加载
echo "vendor-reset" | sudo tee -a /etc/modules

echo "vendor-reset" | sudo tee -a /etc/modules
vendor-reset


# 6.更新initramfs启动镜像,确保开机加载模块
sudo update-initramfs -u

sudo update-initramfs -u
update-initramfs: Generating /boot/initrd.img-7.0.0-31-generic

关键说明

  1. linux-headers-$(uname -r)当前正在运行内核的头文件,用来编译内核模块;内核升级后需要重新安装对应头文件,dkms 会自动重编译。

  2. dkms:动态内核模块支持,内核升级模块不用手动重新编译。

  3. /etc/modules:开机自动加载内核模块列表,写入vendor-reset开机自动加载。

  4. update-initramfs -u 更新内存盘,不执行的话开机不会加载模块。

验证是否安装 & 加载成功

#查看模块是否存在
dkms status

#重启后检查是否加载成功
lsmod | grep vendor_reset
  1. vendor‑reset 主要针对 AMD GCN 显卡(RX580/RX480 等),解决虚机关机后显卡不复位,宿主机无输出、pci 报错。

  2. 老 SNB 平台,部分主板 RMRR 会和此模块叠加,直通虚拟机 XML 建议加上:

下面就是些如果安装虚拟机win11 ,如何如何,我嫌麻烦,就直接部署OpenNebula

<vendor_id state='on' value='whatever'/>
  1. 如果以后删除卸载这个模块:

sudo dkms remove vendor-reset/0.1 --all
sudo sed -i '/vendor-reset/d' /etc/modules
sudo update-initramfs -u

编辑虚拟机 xml:

virsh edit win11

1. ✅`dkms status`输出:`vendor‑reset/0.1.1 ... installed`
vendor‑reset **DKMS 模块编译安装成功**。
2. ⚠️`lsmod | grep vendor_reset`没有输出:

> 
> 还没重启机器!模块只是编译安装到磁盘,**尚未加载进内核**,重启主机后执行 `lsmod | grep vendor_reset` 就会出现。

3. ❌`virsh edit win11` → `error: failed to get domain 'win11'`
**错误原因:还没有名字叫 win11 的虚拟机**。`win11`是我举例用的虚拟机名,你本地还没创建这个虚拟机,所以找不到。

## 查看你现有的虚拟机列表

```
virsh list --all
```

- 会列出所有虚拟机,看真实名字是什么;
- 假设虚拟机名叫 `windows`,编辑命令就是:

```
virsh edit windows
```

> 
> 如果输出为空,代表一台虚拟机都还没创建,需要先新建虚拟机,再去修改 XML。

找到 <features> 区域,把这行加进去,放在 features 大括号里面,示例:

<features>
  <acpi/>
  <apic/>
  <vendor_id state='on' value='whatever'/>
  <hyperv>
  ...
  </hyperv>
  ...
</features>

<vendor_id state='on' value='whatever'/> 作用:欺骗 Windows,隐藏宿主机真实 CPU 型号,规避 Windows 看出来是虚拟化环境,防止部分 AMD 显卡驱动报错 43,RX580 直通非常需要这个。

virsh edit 修改规则

  1. 虚拟机必须关机才能编辑 XML,开机状态编辑会报错。

  2. 修改保存退出后,virsh 会自动校验配置。

  3. 启动虚拟机才生效。


RX580 直通完整 features 参考片段,直接复制替换你的 features 块

<features>
  <acpi/>
  <apic/>
  <vendor_id state='on' value='whatever'/>
  <hyperv>
    <relaxed state="on"/>
    <vapic state="on"/>
    <spinlocks state="on" retries="8191"/>
  </hyperv>
  <vmport state='off'/>
</features>

============================================================================================

lsmod | grep vendor_reset
vendor_reset          126976  0
shitou@shitou-To-be-filled-by-O-E-M:~$ #!/bin/bash
for d in /sys/kernel/iommu_groups/*/devices/*; do
  n=${d#*/iommu_groups/*}; n=${n%%/*}
  printf 'IOMMU Group %s ' "$n"
  lspci -nns "${d##*/}"
done
IOMMU Group 0 00:00.0 Host bridge [0600]: Intel Corporation Xeon E3-1200 v2/Ivy Bridge DRAM Controller [8086:0158] (rev 09)
IOMMU Group 10 04:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL810xE PCI Express Fast Ethernet controller [10ec:8136] (rev 07)
IOMMU Group 1 00:01.0 PCI bridge [0604]: Intel Corporation Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port [8086:0151] (rev 09)
IOMMU Group 1 01:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Polaris 20 XL [Radeon RX 580 2048SP] [1002:6fdf] (rev e7)
IOMMU Group 1 01:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere HDMI Audio [Radeon RX 470/480 / 570/580/590] [1002:aaf0]
IOMMU Group 2 00:1a.0 USB controller [0c03]: Intel Corporation 6 Series/C200 Series Chipset Family USB Enhanced Host Controller #2 [8086:1c2d] (rev 05)
IOMMU Group 3 00:1b.0 Audio device [0403]: Intel Corporation 6 Series/C200 Series Chipset Family High Definition Audio Controller [8086:1c20] (rev 05)
IOMMU Group 4 00:1c.0 PCI bridge [0604]: Intel Corporation 6 Series/C200 Series Chipset Family PCI Express Root Port 1 [8086:1c10] (rev b5)
IOMMU Group 5 00:1c.4 PCI bridge [0604]: Intel Corporation 6 Series/C200 Series Chipset Family PCI Express Root Port 5 [8086:1c18] (rev b5)
IOMMU Group 6 00:1c.5 PCI bridge [0604]: Intel Corporation 6 Series/C200 Series Chipset Family PCI Express Root Port 6 [8086:1c1a] (rev b5)
IOMMU Group 7 00:1d.0 USB controller [0c03]: Intel Corporation 6 Series/C200 Series Chipset Family USB Enhanced Host Controller #1 [8086:1c26] (rev 05)
IOMMU Group 8 00:1f.0 ISA bridge [0601]: Intel Corporation H61 Express Chipset LPC Controller [8086:1c5c] (rev 05)
IOMMU Group 8 00:1f.2 SATA controller [0106]: Intel Corporation 6 Series/C200 Series Chipset Family 6 port Desktop SATA AHCI Controller [8086:1c02] (rev 05)
IOMMU Group 8 00:1f.3 SMBus [0c05]: Intel Corporation 6 Series/C200 Series Chipset Family SMBus Controller [8086:1c22] (rev 05)
IOMMU Group 9 03:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller [10ec:8125] (rev 05)

我直接部署OpenNebula

创建虚拟机,的时候必须要

  • 物理机:Ubuntu 系统,主板上插着 RX580 显卡。

  • 目标:开一个 Windows 虚拟机,让 Windows 直接用这块真实的 RX580 显卡,不是虚拟显卡。

  • Ubuntu 宿主机要用 CPU 核显来显示画面,显示器插主板接口。

XML 就是这个 Windows 虚拟机的

置记事本。 你要往这个记事本里面写几句话,告诉虚拟机:“把主机那块 RX580 显卡分配给你用”。 这个记事本不能在黑框终端里直接跑,只能编辑修改。

1、第一步:先创建虚拟机(图形界面点鼠标)

输入命令打开图形窗口

virt-manager

点「新建虚拟机」,装 Windows。

✅关键点:固件一定要选 UEFI(OVMF),不要 BIOS。 硬盘、内存、CPU 按需要分配,这里新建的时候不要添加任何 PCI 硬件! 创建完,把这个 Windows 虚拟机彻底关机

现在你有了一台虚拟机,比如名字叫 win 执行看名字:

virsh list --all

假设名字输出叫win,那编辑命令就是:

virsh edit win

敲完这条,会弹出文本编辑器,里面一大坨乱七八糟代码,这个就是虚拟机的配置记事本(XML)。


把记事本内容分三块理解

① cpu 部分(告诉虚拟机给它什么样的 CPU)

<cpu mode='host-passthrough' check='none'>
  <topology sockets='1' dies='1' cores='4' threads='8'/>
</cpu>

作用:把你真实 CPU 完整交给 Windows,性能高。 放到文件靠前的位置,<memory>内存那一块附近。

② features 部分(解决 AMD 显卡 43 报错)

<features>
  <acpi/>
  <apic/>
  <vendor_id state='on' value='whatever'/>
  <hyperv>
    <relaxed state="on"/>
    <vapic state="on"/>
    <spinlocks state="on" retries="8191"/>
  </hyperv>
  <vmport state='off'/>
</features>

重点就是这行:<vendor_id state='on' value='whatever'/> 骗 Windows:“你不是运行在虚拟机里面”,不然 RX580 驱动直接报错 43 用不了。 放在上面 cpu 代码的后面。

③ hostdev 两段(最重要!把 RX580 显卡交给虚拟机)

<hostdev mode='subsystem' type='pci' managed='yes'>
  <source>
    <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
  </source>
  <rom bar='on'/>
  <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
</hostdev>

<hostdev mode='subsystem' type='pci' managed='yes'>
  <source>
    <address domain='0x0000' bus='0x01' slot='0x00' function='0x1'/>
  </source>
  <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
</hostdev>

第一段拿显卡画面输出(01:00.0 RX580) 第二段拿显卡自带的声音(01:00.1) ✅这两段代码必须粘贴到 <devices> 和 </devices> 中间! devices 里面存放虚拟机所有硬件:硬盘、网卡、光驱,我们把显卡也加到这里。

文件简化框架,看位置!!

<domain type='kvm'>
  <name>win</name>

  <!-- ==========【这里粘贴cpu整段】========== -->
  <cpu mode='host-passthrough' check='none'>
    <topology sockets='1' dies='1' cores='4' threads='8'/>
  </cpu>

  <!-- ==========【这里粘贴features整段】========== -->
  <features>
    <acpi/>
    <apic/>
    <vendor_id state='on' value='whatever'/>
    <hyperv>
      <relaxed state="on"/>
      <vapic state="on"/>
      <spinlocks state="on" retries="8191"/>
    </hyperv>
    <vmport state='off'/>
  </features>

  <memory unit='KiB'>8388608</memory>
  <vcpu placement='static'>4</vcpu>

  <devices>
    <!-- =========【这里粘贴两段hostdev显卡代码!!!】========= -->
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <source>
        <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
      </source>
      <rom bar='on'/>
      <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
    </hostdev>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <source>
        <address domain='0x0000' bus='0x01' slot='0x00' function='0x1'/>
      </source>
      <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
    </hostdev>

    <!-- 下面原来硬盘、网卡、OVMF loader这些内容,不要删!保留不动! -->
    <disk type='file' device='disk'>
    ......
  </devices>
</domain>

实操步骤,照着顺序做

  1. virt-manager图形界面新建 Windows 虚拟机,固件选 UEFI,关机

  2. virsh list --all 查到虚拟机名字,比如叫win

  3. 执行 virsh edit win,打开这个配置记事本。

  4. 找到对应位置,把上面三块完整粘贴进去。

  5. 保存退出编辑器。

如果提示错误:就是粘贴错位置、标签没配对,不会保存,重新改。

  1. ⚠️物理显示器:Ubuntu 宿主机插主板视频口;虚拟机的显示器插 RX580 显卡接口

  2. 在 virt-manager 启动虚拟机。

  3. 进到 Windows 系统,安装 AMD RX580 驱动。