服务器 KVM 虚拟化 + GPU 直通部署记录
公司新到一批 8 卡 48 GB RTX 4090 服务器,用于深度学习任务的多租户调度。本文记录从系统安装、磁盘分区、GPU 直通到虚拟机克隆全过程中踩过的坑与解决方案,以备后查,也希望能给同样需求的同学一些参考。
1. virt-install
镜像加载报错
初次执行
1 | virt-install ... --boot hd ... |
却收到
1 | ERROR |
原因是仅指定 --boot hd
并不足以告诉 libvirt 安装介质 从何而来。
在命令末尾补一个 “空导入” 即可解决:
1 | --import |
等于告诉 virt-install
:磁盘里已有系统,把它直接拿来启动即可。
2. CUDA 与 Anaconda 环境变量陷阱
最常见的错法是把 PATH 写成硬编码:
1 | export PATH=/usr/local/cuda-12.4/bin:/usr/local/sbin:/usr/bin |
这样一旦 shell 里已有 PATH,会被完全覆盖。推荐写成如下“追加”形式:
1 | echo 'export PATH=/usr/local/cuda-12.4/bin${PATH:+:${PATH}}' >> ~/.bashrc |
再次登录即可生效。
3. 服务器硬件与基础信息
- CPU:2× Intel Xeon 8452Y(共 64C128T)
- RAM:1 TB
- SSD:2× 3.84 TB NVMe
- GPU:8× RTX 4090 48 GB
快速验证:
1 | nproc # ==> 128 |
GPU bus ID:
下面的 GPU 的总线需要记住,通常一张显卡包含两个 ID,一个是本体 ID,另一个是音频口 ID,在直通时都要保证两个 ID 在同一个 IOMMU 组内,以及均未被其他驱动占用。
1 | lspci -nn | grep -i nvidia |
可用 lspci -k -s <bus-id>
查看当前驱动归属防止被占用:
1 | lspci -k -s 23:00.0 |
4. NVMe 分区与挂载
将磁盘格式化为 ext4(why?)后,查看其 uuid,在写入文件表后将它挂载。
1 | parted /dev/nvme0n1 |
5. GPU 直通(VFIO)
-
指定要由 VFIO 接管的设备 ID:
1
echo "options vfio-pci ids=10de:2684,10de:22ba" > /etc/modprobe.d/vfio.conf
- 10de:2684:RTX 4090 显卡
- 10de:22ba:对应的 HD‑Audio 控制器
-
屏蔽宿主机自带驱动:
1
2echo -e "blacklist nouveau\nblacklist nvidia\nblacklist snd_hda_intel" >> /etc/modprobe.d/blacklist.conf
update-initramfs -u -
热插拔示例(以 01:00.0 为例):
1
2
3
4
5
6
7systemctl stop nvidia-persistenced
modprobe -r nvidia_drm nvidia_modeset nvidia_uvm
echo vfio-pci > /sys/bus/pci/devices/0000:01:00.0/driver_override
echo 0000:01:00.0 > /sys/bus/pci/drivers/vfio-pci/bind
# 同理处理 01:00.1 (audio)
其余七张卡循环同样步骤即可。
6. 创建基础虚拟机并批量克隆
安装依赖与镜像:
1 | apt update && apt install -y qemu-kvm libvirt-daemon virtinst bridge-utils virt-manager libguestfs-tools |
创建模板 VM(直通首张显卡):
1 | virt-install --name vmbase \ |
7. 网络与 SSH 隧道配置
1. iptables 端口转发
宿主机公网只有 22 端口,而每台 VM 都需要独立 SSH。做法是把宿主机的非标准端口映射到各 VM:
1 | VM 列表 |
举例:把宿主机的 12223 → 192.168.122.167:22
1 | # DNAT:修改目的地址 |
其余 VM 的端口依次重复。
2. 本地 SSH 隧道测试
1 | # 建立本地 12223 → 宿主机 (125.71.97.167):12223 的隧道 |
8.snd_hda_intel 占用音频接口导致直通失败
RTX 4090
带一条 PCI 子函数 10de:22ba
(HD‑Audio)。若被 snd_hda_intel
抢占,VFIO 绑定会失败。处理步骤:
1 | # 立即卸载 |
如重启后仍有其它模块占用,可再执行一次:
1 | modprobe -r nvidia_drm nvidia_modeset nvidia_uvm nvidia snd_hda_intel |
可用 lspci -k -s <bus-id>
查看当前驱动归属:
1 | lspci -k -s 23:00.0 |
9. 后期磁盘扩容与挂载流程
如果前期对磁盘大小考虑比较保守,或者后期发展出现磁盘不足的情况,都需要对现有虚拟机进行扩容。qemu 对该部分支持比较好,在 host 上扩容后,进入 vm 进行分配即可。
参考:14.10. Re-sizing the Disk Image
-
在宿主机上给虚拟机增加存储空间
1
qemu-img resize filename +50G
-
进入虚拟机后执行
fdisk -l
查看是否有增量存储未分配1
2
3
4
5
6fdisk -l
lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv
resize2fs /dev/ubuntu-vg/ubuntu-lv
# 或者
growpart /dev/vda 3
10.virtiofs 主机 ↔︎ 虚拟机高速共享
nfs 简单但延迟高;内核 ≥ 5.14 + libvirt ≥ 8.0 可直接用 virtiofs,性能接近本机 I/O。
参考文档:Sharing files with Virtiofs
- vm 共享文件需要提前安装好
virtiofsd
:
1 | apt install virtiofsd |
- 修改 VM XML(示例片段):
1 | <domain type='kvm'> |
- 虚拟机内部挂载:
个人更喜欢将共享文件夹作为临时“通道”,所以会将文件拷贝到本地,避免高负载下 Host 的 IO 压力过大。
1 | mount -t virtiofs shared_folder_tag /mnt/shared |
11. 总结
至此,8 卡 RTX 4090 KVM 集群 已完成:
- NVMe 分区与挂载
- VFIO 直通显卡 + HD‑Audio
- Base VM 制作、批量克隆
- iptables 端口映射 + 本地 SSH 隧道
- 驱动占用、磁盘扩容、virtiofs 文件共享等细节优化
过程中遇到的所有坑、完整命令与验证方式均已记录。如有疑问或更优实践,欢迎留言交流。
服务器 KVM 虚拟化 + GPU 直通部署记录
https://zion4h.github.io/2025/04/19/2025-4-19-服务器 KVM 虚拟化 + GPU 直通部署记录/