一、简介

在生产环境中我们通常会使用docker、VMware等其他虚拟化技术,这两种技术分别在不同的环境下发挥不同的作用,有些特殊的情况下我们会用到GPU资源,但是GPU资源通常为宿主机可用的,如果说对于docker来使用的话还算比较简单,安装一个nvidia-docker2即可容器直通GPU资源,但是对于虚拟机来说就不太方便了,因此接下来的讲解以及操作就是针对于KVM虚拟来直通GPU

注意:虽然虚拟机直通GPU了,但是这种操作会导致宿主机上失去一块GPU卡。

1. 硬件条件

首先要确定主板和CPU都支持VT-d技术,即Virtualization Technology for Direct I/O(英特尔虚拟技术)。近年的产品应该都支持此技术。 在BIOS里将
还要确定要直通的显卡支持PCI Pass-through。似乎A卡对于直通的支持比N卡好,但N卡性能比A卡好,这个大家都知道。目前市面上的显卡一般都支持直通。我用过的NVIDIA 的M60和GeForce系统960,970,1080系列都支持的。注意做显卡直通需要两块显卡,一块主机用,另一块虚拟机用,主板有集成显卡的可以采用将集成显卡给宿主机,PCI的独立显卡给虚拟机用。

2. 准备工作

在BIOS将VT-d设置成enable(主板BIOS设置项名称不一样,类似于虚拟化技术的项目打开即可)。

如下是我的当前实验环境

# 查看机器系统版本
root@ubuntu:~# cat /proc/version
Linux version 5.4.0-90-generic (buildd@lgw01-amd64-054) (gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)) #101-Ubuntu SMP Fri Oct 15 20:00:55 UTC 2021
# 验证CPU是否支持虚拟化
root@ubuntu:~# cat /proc/cpuinfo | egrep 'vmx|svm'sh
# 查看是否加载kvm
root@ubuntu:~# lsmod | grep kvm
kvm_intel             170086  0
kvm                   566340  1 kvm_intel
irqbypass              13503  1 kvm
# 当前显卡信息
root@ubuntu955:~# nvidia-smi
Tue Nov 23 03:21:02 2021       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 460.91.03    Driver Version: 460.91.03    CUDA Version: 11.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  GeForce GTX 108...  Off  | 00000000:02:00.0 Off |                  N/A |
| 28%   48C    P0    61W / 250W |      0MiB / 11178MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
|   1  GeForce GTX 108...  Off  | 00000000:81:00.0 Off |                  N/A |
| 26%   44C    P8     9W / 250W |    607MiB / 11178MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    1   N/A  N/A     12188      C   python                            605MiB |
+-----------------------------------------------------------------------------+

3. 安装KVM

root@ubuntu:~# apt-get install qemu-kvm libvirt-bin bridge-utils ubuntu-vm-builder virt-manager virtinst
# 启动服务
root@ubuntu:~# systemctl enable libvirtd && systemctl start libvirtd

二、KVM直通GPU

4. 确认内核是否支持iommu

root@ubuntu:~# cat /proc/cmdline | grep iommu

如果没有输出结果,添加intel_iommu=on到grub的启动参数,需要重启

root@ubuntu:~# vim /etc/default/grub

# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
#   info -f grub -n 'Simple configuration'

GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="maybe-ubiquity"sh
# 添加intel_iommu=on
GRUB_CMDLINE_LINUX="intel_iommu=on"

# 更新grub菜单文件
root@ubuntu:~# grub-mkconfig -o /boot/grub/grub.cfg
# 重启机器
root@ubuntu:~# reboot
# 开机后检查一下
root@ubuntu:~# dmesg | grep IOMMU
# 或
root@ubuntu:~# dmesg | grep -e DMAR -e IOMMU
检查VT-d(AMD芯片时是 IOV)是否工作。若没有相应输出,需要重新检查之前的步骤

5. 查看pci设备信息

root@ubuntu:~# lspci -nn | grep NVIDIA
02:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP102 [GeForce GTX 1080 Ti] [10de:1b06] (rev a1)
02:00.1 Audio device [0403]: NVIDIA Corporation GP102 HDMI Audio Controller [10de:10ef] (rev a1)

6. 查看驱动

# 02:00.0指的就是上面grep查看出来的设备信息的开头编号
root@ubuntu:~# lspci -vv -s 02:00.0 | grep driver
	Kernel driver in use: nouveau nouveau            (系统为显卡绑定的默认驱动)
root@ubuntu:~# lspci -vv -s 02:00.1 | grep driver
	Kernel driver in use: snd_hda_intel             (显卡上附带的集成声卡的默认驱动)
# 禁用显卡的默认驱动
root@ubuntu:~# modprobe -r nouveau

7. 将显卡从宿主机解绑定

echo的所有内容都能在上面的第5标题找到,并且标题7 8 的操作仅针对于Ubuntu系统,centos系统和Ubuntu不一样

root@ubuntu:~# modprobe vfio
root@ubuntu:~# vfio-pci
root@ubuntu:~# cd /sys/bus/pci/devices/0000\:02\:00.0
root@ubuntu:~# echo "10de 1b06" > /sys/bus/pci/drivers/vfio-pci/new_id
root@ubuntu:~# echo "0000:02:00.0" > /sys/bus/pci/devices/0000\:02\:00.0/driver/unbind
# 如下两句针对centos系统
# centos7是/sys/bus/pci/drivers/pci-stub/bind
#root@ubuntu:~# echo "0000:02:00.0" > /sys/bus/pci/drivers/pcieport/bind

8. 将显卡上附带的集成声卡的默认驱动接触绑定

root@ubuntu:~# cd /sys/bus/pci/devices/0000\:02\:00.1
root@ubuntu:~# echo "10de 10ef" > /sys/bus/pci/drivers/vfio-pci/new_id
root@ubuntu:~# echo "0000:02:00.1" > /sys/bus/pci/devices/0000\:02\:00.1/driver/unbind
# 如下两句针对centos系统
# centos7是/sys/bus/pci/drivers/pci-stub/bind
#root@ubuntu:~# echo "0000:02:00.1" > /sys/bus/pci/drivers/pcieport/bind

检查预留是否成功

root@ubuntu:~# lspci -nnv | grep -E "(^\S|Kernel driver in use)" | grep "02:00" -A 1
02:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP102 [GeForce GTX 1080 Ti] [10de:1b06] (rev a1) (prog-if 00 [VGA controller])
	Kernel driver in use: vfio-pci
02:00.1 Audio device [0403]: NVIDIA Corporation GP102 HDMI Audio Controller [10de:10ef] (rev a1)
	Kernel driver in use: vfio-pci

三、安装测试虚拟机

9. 新建虚拟机

基础过程略过,直接看硬件信息

注意:安装驱动之前首先禁用掉默认的nVidia驱动(nouveau)
root@ubuntu:~#  touch /etc/modprobe.d/blacklist-nouveau.conf
root@ubuntu:~# cat > /etc/modprobe.d/blacklist-nouveau.conf <<EOF
blacklist nouveau
options nouveau modeset=0
EOF
# 重新生成 kernel initramfs
root@ubuntu:~# update-initramfs -u
root@ubuntu:~# reboot
# 开机后进入manager管理器
root@ubuntu:~# virt-manager

vMVare虚拟化gpu kvm虚拟化gpu_虚拟机


vMVare虚拟化gpu kvm虚拟化gpu_kvm_02


vMVare虚拟化gpu kvm虚拟化gpu_虚拟机_03


vMVare虚拟化gpu kvm虚拟化gpu_vMVare虚拟化gpu_04

10. NVIDIA 驱动的反虚拟机问题

转载:

虚拟机直通GPU之后,安装好NVIDIA驱动之后,执行nvidia-smi会返回报错信息,提示Unable to determine the device handle for GPU 0000:07:00.0: Unknown Error,说是找不到设备信息,其实这是NVIDIA显卡会检查当前系统环境是虚拟机环境还是物理机环境,如果是虚拟机他会自动屏蔽掉,所以会提示这个报错

  • Windows 下安装驱动报 43 错误
  • Linux 安装驱动后,运行 nvidia-smi 无法找到显卡

vMVare虚拟化gpu kvm虚拟化gpu_kvm_05

解决办法如下:

找到虚拟机的xml配置文件,然后对其进行修改

# 首先先关闭虚拟机
root@ubuntu:~# init 0
# 回到KVM宿主机修改配置文件其目的就是为了欺骗NVIDIA的检查
root@ubuntu:~# cd /etc/libvirt/qemu/
root@ubuntu955:/etc/libvirt/qemu# vim apt-mirrors.xml
# 填写如下配置信息,value任意写12位字符

格式有问题,注意和截图中的对应一致

<hyperv>
  <relaxed state="on"/>
  <vapic state="on"/>
  <spinlocks state="on" retries="8191"/>
  <vendor_id state="on" value="123456789123"/>
</hyperv>
<kvm>
  <hidden state="on"/>
</kvm>

vMVare虚拟化gpu kvm虚拟化gpu_虚拟机_06


Windows系统

Windows的xml文件也是同样的修改方式,只不过Windows的xml文件中默认就有一些要后期添加的内容,稍作修改即可。

重启libvirtd服务

root@ubuntu:~# systemctl restart libvirtd

11. 验证虚拟机显卡以及驱动

vMVare虚拟化gpu kvm虚拟化gpu_虚拟机_07


vMVare虚拟化gpu kvm虚拟化gpu_linux_08


vMVare虚拟化gpu kvm虚拟化gpu_虚拟机_09


Windows

win10系统这里没做测试,win7系统安装显卡驱动的时候应该会有报错windows 7 needs to install SHA-2提示缺少补丁文件,这里安装补丁文件可下载一个360安全卫士,然后利用360下载一些补丁即可。

vMVare虚拟化gpu kvm虚拟化gpu_linux_10


vMVare虚拟化gpu kvm虚拟化gpu_虚拟机_11


vMVare虚拟化gpu kvm虚拟化gpu_linux_12

12.系统重启后显卡挂掉问题

如果上面的禁止nouveau驱动方法不管用,可以使用下面的这个systemd

# 脚本解决此问题
root@ubuntu:~# touch /opt/prohibit_nouveau.sh
root@ubuntu:~# cat > /opt/prohibit_nouveau.sh << EOF
#!/bin/bash
modprobe -r nouveau
EOF
root@ubuntu:~# chmod +x /opt/prohibit_nouveau.sh
root@ubuntu:~# cat > /etc/systemd/system/prohibit_nouveau.service << EOF
[Unit]
Description=prohibit_nouveau
After=network.target

[Service]
User=root
Group=root
Type=forking
ExecStart= /opt/prohibit_nouveau.sh
TimeoutSec=0
Restart=on-failure
StandardOutput=journal
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF
# 设置为开机自启动
root@ubuntu:~# systemctl enable prohibit_nouveau.service
# 重启测试
root@ubuntu:~# reboot