,
本地搭建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
1616个核心已经支持,///
确认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
守护进程,管理全部虚拟机生命周期:启动、停止、快照、网络、存储池。
系统开机自启,
virsh、virt‑manager都要和这个 daemon 通信。
3. libvirt‑clients
libvirt 命令行工具集,核心就是 virsh
virsh list、virsh start、virsh 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
创建虚拟机的关键要点(一定要记住)
安装源:准备好系统 ISO 镜像(ISO 放系统盘 sdb 不用,放 sda 即可)
磁盘:存储池选择
vm‑lvm‑pool,这样硬盘才存在 sdb,不占用系统盘。固件:选择
OVMF (UEFI),Win11 必须这个。磁盘总线、网卡总线:选
virtio,性能最高。网卡默认就是 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 rebootdmesg | 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 直通虚拟机必备包。逐个拆解每个软件包作用:
表格
把当前用户加入 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关键说明
linux-headers-$(uname -r):当前正在运行内核的头文件,用来编译内核模块;内核升级后需要重新安装对应头文件,dkms 会自动重编译。dkms:动态内核模块支持,内核升级模块不用手动重新编译。
/etc/modules:开机自动加载内核模块列表,写入vendor-reset开机自动加载。update-initramfs -u更新内存盘,不执行的话开机不会加载模块。
验证是否安装 & 加载成功
#查看模块是否存在
dkms status
#重启后检查是否加载成功
lsmod | grep vendor_resetvendor‑reset 主要针对 AMD GCN 显卡(RX580/RX480 等),解决虚机关机后显卡不复位,宿主机无输出、pci 报错。
老 SNB 平台,部分主板 RMRR 会和此模块叠加,直通虚拟机 XML 建议加上:
下面就是些如果安装虚拟机win11 ,如何如何,我嫌麻烦,就直接部署OpenNebula
<vendor_id state='on' value='whatever'/>
如果以后删除卸载这个模块:
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 修改规则
虚拟机必须关机才能编辑 XML,开机状态编辑会报错。
修改保存退出后,virsh 会自动校验配置。
启动虚拟机才生效。
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>
实操步骤,照着顺序做
用
virt-manager图形界面新建 Windows 虚拟机,固件选 UEFI,关机。virsh list --all查到虚拟机名字,比如叫win。执行
virsh edit win,打开这个配置记事本。找到对应位置,把上面三块完整粘贴进去。
保存退出编辑器。
如果提示错误:就是粘贴错位置、标签没配对,不会保存,重新改。
⚠️物理显示器:Ubuntu 宿主机插主板视频口;虚拟机的显示器插 RX580 显卡接口。
在 virt-manager 启动虚拟机。
进到 Windows 系统,安装 AMD RX580 驱动。
本地搭建AI及实验平台(1)LXD 轻量私有云(入门首选) IaaS 私有云,
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法