CentOS 7 KVM 搭建并设置 PCI 直通 Nvidia 显卡

KVM 和 QEMU 关系及显卡直通

KVM

KVM (Kernel-based Virtual Machine, 即内核级虚拟机) 是一个开源的系统虚拟化模块, 基于 Linux 内核的调度器进行管理, 相对于 Xen, 它的核心代码较少。KVM 已成为学术界主流的虚拟机监控器 (VMM) 之一。KVM 包含一个为处理器提供底层虚拟化支持的可加载核心模块 kvm.ko (Intel 使用 kvm-intel.ko, AMD 使用 kvm-amd.ko)。此外, KVM 还需要一个修改过的 QEMU 软件 (qemu-kvm) 来提供虚拟机的上层控制和界面。

KVM 的虚拟化要求硬件支持, 如 Intel 的 VT 技术或 AMD 的 SVM 技术, 因此它是基于硬件的完全虚拟化方案。KVM 允许在多个虚拟机中运行与主机系统相同的镜像, 例如 Windows 和 macOS, 每个虚拟机都会拥有独立的虚拟硬件资源, 如网卡、硬盘和图形适配器等。

KVM 和 QEMU 的关系

QEMU 是一个独立的虚拟化解决方案, 从某种角度来说, 它并不依赖 KVM。而 KVM 是另一套虚拟化解决方案, 实际上它仅提供对处理器 (如 Intel VT 或 AMD SVM) 的虚拟化特性支持。KVM 本身不包含设备虚拟化及用户空间的虚拟机管理工具, 因此它借用了 QEMU 的代码, 并与 KVM 配合使用, 形成了完整的虚拟化解决方案: KVM + QEMU

通过 VFIO、KVM 和 QEMU 实现 GPU 直通

我一直希望使用 CentOS 7 作为主要的操作系统, 但又想使用 Nvidia 显卡玩游戏, 就需要一个 Windows 系统。

可以通过 VFIO (Virtual Function I/O) 、KVM 和 QEMU 这三种开源技术实现 GPU 的直通。这种方法可以让虚拟机使用主机上的显卡, 从而达到接近原生性能的效果。具体来说, 通过 VFIO 技术, 能够将物理显卡从主机系统中 “直通” 给虚拟机, 使得虚拟机能够直接访问该显卡, 运行图形密集型应用或游戏。

准备工作

硬件

  1. CPU Intel i7-8700K 需要支持 VT-d (Intel Virtualization Technology for Directed I/O) 以及VT-x
  2. 内存 40G RAM (目前是 8G + 48G)
  3. 显卡 ASUS ROG-STRIX-RTX2080TI-O11G-GAMING 虚拟机使用 (显卡需要 UEFI 支持) 新显卡都支持, 可以在 这里查询
  4. 主板 ASUS Strix Z370-F

软件

  1. CentOS 7.6
  2. KVM 套件
  3. qemu-kvm 需要 2.9.0 以上版本
  4. Windows 10 1809 版本 (RTX 显卡需要最新的 win 10)

软件配置

  1. 从内核中禁用 nouveau 驱动
  2. PCI 直通 (VFIO/IOMMU)
  3. KVM 网桥
  4. qemu-kvm: could not open disk image ' ': Permission denied 权限问题
  5. 虚拟机 CPU 分配 (虚拟物理核心和虚拟线程的设置)
  6. 下载 VFIO 驱动程序
  7. 虚拟机中 N 卡驱动 43 错误代码 (N 卡检测到在虚拟机中运行会出现这个错误)
  8. 添加物理磁盘到虚拟机

配置流程

  1. 检查硬件是否满足要求
  2. 准备系统环境 安装 KVM 套件
  3. 检查是否正确加载 kvm 模块
  4. 禁用 nouveau 驱动
  5. 开启 IOMMU 支持
  6. 设置 vfio-pci 设备 (IOMMU)
  7. 设置网桥
  8. 更新 qemu-kvm 到 2.9.0 以上版本
  9. 分配虚拟机磁盘
  10. 配置 qemu-kvm 权限
  11. 安装虚拟机
  12. 设置虚拟机 CPU 核心
  13. 分配鼠标键盘给虚拟机
  14. 虚拟机 win VFIO 驱动程序安装
  15. 给虚拟机添加显卡
  16. 解决显卡 43 错误代码
  17. 给虚拟机添加物理磁盘

1. 检查硬件是否满足要求

验证 CPU 是否支持 KVM

如果结果中有 vmx (Intel VT 虚拟化技术) 或 svm (SVM 安全虚拟化技术的 AMD 处理器, 也可以叫 AMD-V) 字样, 就说明 CPU 的支持的。如果没配置过可以在 BIOS 中启用。如果还没有任何的输出, 说明你的 cpu 不支持, 将无法使用 KVM 虚拟机。

egrep '(vmx|svm)' /proc/cpuinfo

flags       : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms xsaveopt
flags       : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms xsaveopt
flags       : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm arat epb pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms xsaveopt

2. 准备系统环境 安装 KVM 套件

安装基础工具

yum install net-tools vim wget kernel-devel epel-release
yum update
yum install htop

安装 KVM 套件

yum install virt-manager qemu-img qemu-kvm qemu-kvm-tools libvirt virt-install bridge-utils

添加 virtio-win 源并安装 virtio-win

wget https://fedorapeople.org/groups/virt/virtio-win/virtio-win.repo -O /etc/yum.repos.d/virtio-win.repo
yum install virtio-win

kvm 相关安装包及其作用

qemu-kvm          主要的 KVM 程序包
python-virtinst   创建虚拟机所需要的命令行工具和程序库
virt-manager      GUI 虚拟机管理工具
virt-top          虚拟机统计命令
virt-viewer       GUI 连接程序, 连接到已配置好的虚拟机
libvirt           C 语言工具包, 提供 libvirt 服务
libvirt-client    虚拟客户机提供的 C 语言工具包
virt-install      基于 libvirt 服务的虚拟机创建命令
bridge-utils      创建和管理桥接设备的工具

3. 检查是否正确加载 kvm 模块

一共会输出三条, 三条都必须满足

[root@corehadoop31 ~]# lsmod |grep kvm
kvm_intel             170181  3
kvm                   554609  1 kvm_intel
irqbypass              13503  1 kvm

4. 禁用 nouveau 驱动

CentOS 7 文件路径在 /usr/lib/modprobe.d/dist-blacklist.conf/lib/modprobe.d/dist-blacklist.conf 是同一个文件, 修改其中一个即可。

其他路径如 /etc/modprobe.d/blacklist.conf 也可以使用, 下面是禁用相关驱动的命令

echo "blacklist radeon" >> /etc/modprobe.d/blacklist.conf
echo "blacklist nouveau" >> /etc/modprobe.d/blacklist.conf
echo "blacklist nvidia" >> /etc/modprobe.d/blacklist.conf

本段文章教程 两篇文章结合使用

centos 7禁用nouveau及安装NVIDIA显卡驱动
CentOS中禁用nouveau驱动

在配置文件中禁用 nouveau

编辑文件禁用 nouveau

vim /usr/lib/modprobe.d/dist-blacklist.conf

在文件最后添加以下内容

blacklist nouveau
options nouveau modeset=0

备份并重建 initramfs 镜像

# 备份镜像
mv /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r).img.bak

# 重建镜像
dracut -v /boot/initramfs-$(uname -r).img $(uname -r)

重启并检查是否禁用成功

reboot

# 重启之后检查是否禁用成功, 应该返回空
lsmod | grep nouveau

扩展阅读

禁用 Nvidia 的 libGL 驱动。Using integrated graphics card for display and Nvidia card for GPU

注释掉 /etc/ld.so.conf.d/nvidia.conf 文件中的内容

# /etc/ld.so.conf.d/nvidia.conf provided by http://elrepo.org
/usr/lib64/nvidia
/usr/lib64/vdpau
/usr/lib/nvidia
/usr/lib/vdpau

5. 开启 IOMMU 支持

CentOS7 minimal kvm iommu 辅助虚拟化 vt-x (用于pci透传)

根据 CPU 类型, 启用 IOMMU 支持:

  • Intel CPU: intel_iommu=on
  • AMD CPU: amd_iommu=on

方法一

我用方法一失败了, 很多文章都是方法一

编辑 GRUB 配置文件

vim /etc/default/grub

GRUB_CMDLINE_LINUX_DEFAULTGRUB_CMDLINE_LINUX 中添加 intel_iommu=on

GRUB_CMDLINE_LINUX_DEFAULT="... intel_iommu=on ..."
或
GRUB_CMDLINE_LINUX="... intel_iommu=on ..."

更新 GRUB 配置

grub2-mkconfig -o /boot/grub2/grub.cfg

重启系统

reboot

验证是否成功启用 IOMMU

cat /proc/cmdline | grep intel_iommu=on

Snipaste_2019-03-19_09-44-07.png

查看系统日志, 确认 IOMMU 是否启用

dmesg | grep -E "DMAR|IOMMU"

Snipaste_2019-03-19_09-46-51.png

如果方法一 失败, 应该是启动的时候并没有使用 /boot/grub2/grub.cfg, 可以用方法二

方法二

查找 grub.cfg 文件

find / -name "grub.cfg"

Snipaste_2019-03-19_09-55-23.png

发现还有 /boot/efi/EFI/centos/grub.cfg 这个文件, 继续执行以下操作。

编辑该 grub.cfg 文件

vim /boot/efi/EFI/centos/grub.cfg

对照 /boot/grub2/grub.cfgintel_iommu=on 添加到相应位置

文件里 linuxefi 出现了 3 次, 在每个 linuxefi 行添加 intel_iommu=on, 然后保存退出

Snipaste_2019-03-19_09-58-59.png

重启系统并验证配置是否生效

6. 设置 vfio-pci 设备 (IOMMU)

配置 VFIO-PCI

查找设备的 PCI 信息

lspci -nn | grep -i nvidia
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU102 [GeForce RTX 2080 Ti Rev. A] [10de:1e07] (rev a1)
01:00.1 Audio device [0403]: NVIDIA Corporation Device [10de:10f7] (rev a1)
01:00.2 USB controller [0c03]: NVIDIA Corporation Device [10de:1ad6] (rev a1)
01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device [10de:1ad7] (rev a1)

配置 VFIO 设备

编辑 vim /etc/modprobe.d/vfio.conf 文件, 添加以下内容 (根据你的设备的 vendor-ID 和 device-ID)

# create new: for [ids=***], specify [vendor-ID:device-ID] 没有 ACS 的需要把整组都放入
options vfio-pci ids=10de:1e07,10de:10f7,10de:1ad6,10de:1ad7

创建配置文件以加载 VFIO 模块

echo 'vfio-pci' > /etc/modules-load.d/vfio-pci.conf

重启系统

reboot

验证 VFIO 是否成功加载

使用 dmesg 查看日志, 确认 VFIO 设备是否已加载

dmesg | grep -i vfio
   >># dmesg | grep -i vfio
[    1.423654] VFIO - User Level meta-driver version: 0.3
[    1.435816] vfio_pci: add [10de:1e07[ffff:ffff]] class 0x000000/00000000
[    1.447858] vfio_pci: add [10de:10f7[ffff:ffff]] class 0x000000/00000000

扩展阅读!!! 注意事项

Pci passthrough #Verify IOMMU isolation

验证 IOMMU 是否正确隔离

要让 PCI passthrough 正常工作, 确保每个 PCI 设备都在独立的 IOMMU 组内。使用以下命令查看 IOMMU 组信息

find /sys/kernel/iommu_groups/ -type l

/sys/kernel/iommu_groups/0/devices/0000:00:00.0
/sys/kernel/iommu_groups/1/devices/0000:00:01.0
/sys/kernel/iommu_groups/1/devices/0000:01:00.0
/sys/kernel/iommu_groups/1/devices/0000:01:00.1
/sys/kernel/iommu_groups/2/devices/0000:00:02.0
/sys/kernel/iommu_groups/3/devices/0000:00:16.0
/sys/kernel/iommu_groups/4/devices/0000:00:1a.0
/sys/kernel/iommu_groups/5/devices/0000:00:1b.0
/sys/kernel/iommu_groups/6/devices/0000:00:1c.0
/sys/kernel/iommu_groups/7/devices/0000:00:1c.5
/sys/kernel/iommu_groups/8/devices/0000:00:1c.6
/sys/kernel/iommu_groups/9/devices/0000:00:1c.7
/sys/kernel/iommu_groups/9/devices/0000:05:00.0
/sys/kernel/iommu_groups/10/devices/0000:00:1d.0
/sys/kernel/iommu_groups/11/devices/0000:00:1f.0
/sys/kernel/iommu_groups/11/devices/0000:00:1f.2
/sys/kernel/iommu_groups/11/devices/0000:00:1f.3
/sys/kernel/iommu_groups/12/devices/0000:02:00.0
/sys/kernel/iommu_groups/12/devices/0000:02:00.1
/sys/kernel/iommu_groups/13/devices/0000:03:00.0
/sys/kernel/iommu_groups/14/devices/0000:04:00.0

IOMMU 支持 ACS

要确保 PCI 设备能正常进行 passthrough, 每个设备需要提供专用的 IOMMU 组。为此, 你的处理器必须支持 ACS (Access Control Services)

支持 ACS 的处理器 (Xeon、Core 系列)

  • Intel Xeon 处理器 (E3、E5 系列) 大多支持 ACS, 但某些型号 (如 Xeon E3-1200) 不支持。
  • Intel Core 处理器: 只有一些型号支持 ACS, 常见的支持型号包括
Haswell-E (LGA2011-v3)
i7-5960X (8-core, 3/3.5GHz)
i7-5930K (6-core, 3.2/3.8GHz)
i7-5820K (6-core, 3.3/3.6GHz)

Ivy Bridge-E (LGA2011)
i7-4960X (6-core, 3.6/4GHz)
i7-4930K (6-core, 3.4/3.6GHz)
i7-4820K (4-core, 3.7/3.9GHz)

Sandy Bridge-E (LGA2011)
i7-3960X (6-core, 3.3/3.9GHz)
i7-3970X (6-core, 3.5/4GHz)
i7-3930K (6-core, 3.2/3.8GHz)
i7-3820 (4-core, 3.6/3.8GHz)

7. 设置网桥

配置宿主机网络

Bridge 模式配置

Bridge 模式即虚拟网桥, 允许虚拟机与宿主机和网络中的其他设备进行通信, 使虚拟机获得独立的 IP 地址。

桥接网络 (也叫物理设备共享) 被用作把一个物理设备复制到一台虚拟机。网桥多用作高级设置, 特别是主机多个网络接口的情况。

┌─────────────────────────┐      ┌─────────────────┐
│          HOST           │      │Virtual Machine 1│
│ ┌──────┐      ┌───────┐ │      │    ┌──────┐     │
│ │ br0  │──┬───│ vnet0 │─│─ ─ ─ │    │ br0  │     │
│ └──────┘  │   └───────┘ │      │    └──────┘     │
│     │     │             │      └─────────────────┘
│     │     │   ┌───────┐ │      ┌─────────────────┐
│ ┌──────┐  └───│ vnet1 │─│─     │Virtual Machine 2│
│ │ eno0 │      └───────┘ │ │    │    ┌──────┐     │
│ └──────┘                │  ─ ─ │    │ br0  │     │
│ ┌──────┐                │      │    └──────┘     │
│ │ eno1 │                │      └─────────────────┘
│ └──────┘                │
└─────────────────────────┘

修改网卡配置文件

修改前一定要备份!!!

你需要修改宿主机的物理网卡配置文件, 通常位于 /etc/sysconfig/network-scripts/ 目录下, 如 ifcfg-eno1 宿主机的物理网卡配置文件

# cat ifcfg-eno1
TYPE="Ethernet"
PROXY_METHOD="none"
BROWSER_ONLY="no"
BOOTPROTO="dhcp"
DEFROUTE="yes"
IPV4_FAILURE_FATAL="no"
IPV6INIT="yes"
IPV6_AUTOCONF="yes"
IPV6_DEFROUTE="yes"
IPV6_FAILURE_FATAL="no"
IPV6_ADDR_GEN_MODE="stable-privacy"
NAME="eno1"
UUID="242b3d4d-37a5-4f46-b072-55554c185ecf"
DEVICE="eno1"
ONBOOT="yes"
ZONE=nas

BRIDGE="br0" # 指定桥接网卡的名称

配置桥接网卡

在同一目录下创建或修改桥接网卡配置文件 ifcfg-br0。确保配置宿主机的 IP 和路由器的网关

# cat ifcfg-br0
BOOTPROTO=static
DEFROUTE=yes
PEERDNS=yes
PEERROUTES=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
IPV6_FAILURE_FATAL=no
NAME=br0
UUID=242b3d4d-37a5-4f46-b072-55554c185ecf
DEVICE=br0
ONBOOT=yes
IPV6_PRIVACY=rfc3041
TYPE=bridge             # 将制定为桥接类型
IPADDR=192.168.188.133  # 设置IP地址
PREFIX=24               # 设置子网掩码
GATEWAY=192.168.188.1   # 设置网关

激活网卡和桥接网卡

使用 ifup 激活网卡

ifup eno1  # 激活物理网卡
ifup br0   # 激活桥接网卡

重启网络服务

两种重启网络的方法

systemctl restart network.service
service network restart

检查网桥配置

使用 brctl show 命令检查网桥设置

brctl show

bridge name   bridge id           STP enabled   interfaces
br0           8000.3863bb44cf6c   no             vnet0
virbr0        8000.525400193f0f   yes            virbr0-nic

8. 更新 qemu-kvm 到 2.9.0 以上版本

Update QEMU: CentOS 7 : KVM : GPU Passthrough : Server World

查看当前 QEMU 版本

[root@dlp ~]# /usr/libexec/qemu-kvm -version
QEMU emulator version 1.5.3 (qemu-kvm-1.5.3-141.el7_4.6), Copyright (c) 2003-2008 Fabrice Bellard

安装 QEMU EV 版本

[root@dlp ~]# yum -y install centos-release-qemu-ev

禁用默认的 QEMU 仓库

# disable usually
[root@dlp ~]# sed -i -e "s/enabled=1/enabled=0/g" /etc/yum.repos.d/CentOS-QEMU-EV.repo

安装 qemu-kvm-ev 包

# for this installing, [qemu-kvm] package is replaced to [qemu-kvm-ev] package
[root@dlp ~]# yum --enablerepo=centos-qemu-ev -y install qemu-kvm-ev

重启 libvirtd 服务

[root@dlp ~]# systemctl restart libvirtd

确认 QEMU 版本更新成功

[root@dlp ~]# /usr/libexec/qemu-kvm -version
QEMU emulator version 2.9.0(qemu-kvm-ev-2.9.0-16.el7_4.13.1)
Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers

验证支持的机器列表

查看是否包含 q35

# verify q35 is included like follows
[root@dlp ~]# /usr/libexec/qemu-kvm -machine help
Supported machines are:
pc                   RHEL 7.4.0 PC (i440FX + PIIX, 1996) (alias of pc-i440fx-rhel7.4.0)
pc-i440fx-rhel7.4.0  RHEL 7.4.0 PC (i440FX + PIIX, 1996) (default)
pc-i440fx-rhel7.3.0  RHEL 7.3.0 PC (i440FX + PIIX, 1996)
pc-i440fx-rhel7.2.0  RHEL 7.2.0 PC (i440FX + PIIX, 1996)
pc-i440fx-rhel7.1.0  RHEL 7.1.0 PC (i440FX + PIIX, 1996)
pc-i440fx-rhel7.0.0  RHEL 7.0.0 PC (i440FX + PIIX, 1996)
rhel6.6.0            RHEL 6.6.0 PC
rhel6.5.0            RHEL 6.5.0 PC
rhel6.4.0            RHEL 6.4.0 PC
rhel6.3.0            RHEL 6.3.0 PC
rhel6.2.0            RHEL 6.2.0 PC
rhel6.1.0            RHEL 6.1.0 PC
rhel6.0.0            RHEL 6.0.0 PC
q35                  RHEL-7.4.0 PC (Q35 + ICH9, 2009) (alias of pc-q35-rhel7.4.0)
pc-q35-rhel7.4.0     RHEL-7.4.0 PC (Q35 + ICH9, 2009)
pc-q35-rhel7.3.0     RHEL-7.3.0 PC (Q35 + ICH9, 2009)
none                 empty machine

9. 分配虚拟机磁盘

创建虚拟磁盘

指定磁盘格式为 raw, 50G 为虚拟大小, 并不实际占用物理空间。

qemu-img create -f raw /root/kvm/win10.raw 50G

查看磁盘信息

qemu-img info /root/kvm/win10.raw

image: /root/kvm/win10.raw
file format: raw
virtual size: 50G (53687091200 bytes)
disk size: 0
  • virtual size 是虚拟磁盘的总大小
  • disk size 表示实际已占用的空间

10. 配置 qemu-kvm 权限

在使用 QEMU-KVM 时, 可能会遇到 qemu-kvm: could not open disk image ' ': Permission denied 的错误。由于 libvirtd 对权限管理较严格, 可以通过以下两种方法解决此问题。

qemu-kvm: could not open disk image ’ ‘: Permission denied

方法一: 修改 QEMU 配置文件

我使用方法一, 但不推荐

注意: 这种方法可能会带来安全隐患, 不推荐用于生产环境。

编辑 /etc/libvirt/qemu.conf 文件, 将 usergroup 设置为 root 用户

# The user for QEMU processes run by the system instance. It can be
# specified as a user name or as a user id. The qemu driver will try to
# parse this value first as a name and then, if the name doesn't exist,
# as a user id.
#
# Since a sequence of digits is a valid user name, a leading plus sign
# can be used to ensure that a user id will not be interpreted as a user
# name.
#
# Some examples of valid values are:
#
#       user = "qemu"   # A user named "qemu"
#       user = "+0"     # Super user (uid=0)
#       user = "100"    # A user named "100" or a user with uid=100
#
user = "root"

# The group for QEMU processes run by the system instance. It can be
# specified in a similar way to user.
group = "root"

# Whether libvirt should dynamically change file ownership
# to match the configured user/group above. Defaults to 1.
# Set to 0 to disable file ownership changes.
#dynamic_ownership = 1

重启 libvirtd 服务

[root@dev1 ~]# service libvirtd restart
Stopping libvirtd daemon:                                  [  OK  ]
Starting libvirtd daemon:                                  [  OK  ]

方法二: 设置 ACL 权限

使用 getfacl 检查文件夹当前的 ACL 权限

murlock@asus:~/kubernet $ sudo getfacl -e /home/murlock
getfacl: Removing leading '/' from absolute path names
# file: home/murlock
# owner: murlock
# group: murlock
user::rwx
user:libvirt-qemu:--x       # effective:---
group::---                  # effective:---
mask::---
other::---

libvirt-qemu 用户添加执行权限

murlock@asus:~/kubernet $ sudo setfacl -m u:libvirt-qemu:rx /home/murlock

验证权限设置是否生效

应看到类似以下内容 user:libvirt-qemu:r-x

murlock@asus:~/kubernet $ sudo getfacl -e /home/murlock
getfacl: Removing leading '/' from absolute path names
# file: home/murlock
# owner: murlock
# group: murlock
user::rwx
user:libvirt-qemu:r-x       # effective:r-x
group::---                  # effective:---
mask::r-x
other::---

11. 安装虚拟机

虚拟机先创建一个可以正常运行的之后再为它添加 PCI 直通设备

特别需要注意的参数 --machine q35--features kvm_hidden=on, 这有助于更好地支持 PCI 直通。

virt-install \
--name Win10 \
--memory 16384 \
--cpu host \
--vcpus 8 \
--disk path=/root/kvm/win10.raw \
--network bridge=br0,model='e1000' \
--cdrom=/root/kvm/win10.iso \
--boot cdrom \
--virt-type kvm \
--vnc \
--vncport=5902 \
--vnclisten=0.0.0.0 \
--os-type=windows \
--features kvm_hidden=on \
--machine q35

参数含义

  • --name Win10: 虚拟机名称为 Win10
  • --memory 16384: 分配 16 GB 内存
  • --cpu host: 使用宿主机的 CPU 配置
  • --vcpus 8: 分配 8 个虚拟 CPU (八路)
  • --disk path=/root/kvm/win10.raw: 指定虚拟机磁盘文件
  • --network bridge=br0,model='e1000': 网络桥接方式, br0 为桥接网络接口
  • --cdrom=/root/kvm/win10.iso: 指定安装光盘镜像 (Windows 10 安装 ISO)
  • --boot cdrom: 启动虚拟机时从光盘启动
  • --virt-type kvm: 使用 KVM 虚拟化
  • --vnc: 启用 VNC 连接
  • --vncport=5902: 指定 VNC 端口为 5902
  • --vnclisten=0.0.0.0: 允许任何主机连接 VNC
  • --os-type=windows: 操作系统类型为 Windows
  • --features kvm_hidden=on: 隐藏 KVM 特征, 防止被虚拟机探测
  • --machine q35: 使用 q35 架构来更好支持 PCI 直通

临时开放 VNC 端口

临时开放 VNC 端口 5902, 以便通过 VNC 客户端连接虚拟机

firewall-cmd --add-port=5902/tcp

安装操作系统

创建虚拟机后, 可以通过 VNC 客户端 (例如 VNC Viewer) 连接到 192.168.x.xxx:5902 来开始安装 Windows 10

virsh 基础命令

virsh list --all           # 查看所有运行和没有运行的虚拟机
virsh list                 # 查看在运行的虚拟机
virsh dumpxml vm-name      # 查看kvm虚拟机配置文件
virsh start vm-name        # 启动kvm虚拟机
virsh shutdown vm-name     # 正常关机

virsh destroy vm-name      # 非正常关机, 强制关闭虚拟机 (相当于物理机直接拔掉电源)
virsh undefine vm-name     # 删除vm的配置文件

ls /etc/libvirt/qemu
# 查看删除结果, Centos-6.6的配置文件被删除, 但磁盘文件不会被删除

virsh define file-name.xml # 根据配置文件定义虚拟机
virsh suspend vm-name      # 挂起, 终止
virsh resumed vm-name      # 恢复被挂起的虚拟机
virsh autostart vm-name    # 开机自启动vm
virsh console <虚拟机名称>   # 连接虚拟机

virsh start centos72     # 虚拟机开启 (启动)
virsh reboot centos72    # 虚拟机重新启动
virsh shutdown centos72  # 虚拟机关机
virsh destroy centos72   # 强制关机 (强制断电)
virsh suspend centos72   # 暂停 (挂起) KVM 虚拟机
virsh resume centos72    # 恢复被挂起的 KVM 虚拟机
virsh undefine centos72  # 该方法只删除配置文件, 磁盘文件未删除
virsh autostart centos72 # 随物理机启动而启动 (开机启动)
virsh autostart --disable centos72 # 取消标记为自动开始 (取消开机启动)

12. 设置虚拟机 CPU 核心

Why does my Windows 7 VM running under Linux’ KVM not use all the virtual processors?

在使用 KVM 创建虚拟机时, 默认的 CPU 核心配置可能不完全满足需求, 特别是对于多核虚拟机。

KVM 默认将 vcpus 设置为多路单核单线程的方式, 上一个步骤的 --vcpus 8 含义为分配 8 个虚拟 CPU (8 个处理器, 每个处理器单核单线程), 但我们预期的是单路四核心双线程或者是单路八核心单线程

而普通版本系统最多支持双路 CPU 的配置, 多于的 CPU 识别不出来。就算识别出来了, 在多任务调度上 8 个处理器也没有 8 核心的效率高

修改 CPU 拓扑结构, 设置为单路处理器 8 核心单线程, 这样可以解决问题

查看主机的 CPU 拓扑结构

在 libvirt 0.8.3 以上, 通过 virsh capabilities 命令, 可以查看主机 CPU 拓扑结构。

virsh capabilities | grep topology

这将列出主机的 CPU 核心和线程拓扑。例如

<topology sockets='1' cores='8' threads='1'/>

这些数字指的是处理器数 (sockets)、每个处理器核心数 (cores) 和每核心线程数 (threads)。

修改虚拟机的 CPU 配置

要让虚拟机使用更多的 CPU 核心和线程, 可以修改虚拟机的 XML 配置文件。以下是如何修改虚拟机 CPU 配置的方法。

打开虚拟机的 XML 文件, 路径为 /etc/libvirt/qemu/ 下的虚拟机配置文件 (例如: Win10.xml), 修改 vcpucpu 部分。

<vcpu placement='static'>8</vcpu>
<cpu mode='host-model' check='partial'>
    <model fallback='allow'/>
    <topology sockets='1' cores='8' threads='1'/>
</cpu>
  • vcpu: 设置虚拟 CPU 数量为 8
  • topology sockets='1' cores='8' threads='1': 设置虚拟机使用 1 个处理器, 每个处理器有 8 个核心, 且每个核心为单线程

直通模式

我使用此方法

如果你需要使用 CPU 直通模式, 可以配置为

<cpu mode='host-passthrough'>
  <topology sockets='1' cores='4' threads='2'/>
  <feature policy='disable' name='hypervisor'/>
</cpu>

应用配置

修改完 XML 文件后, 使用以下命令重新定义虚拟机配置

virsh define Win10.xml

这会使新的 CPU 配置生效

13. 分配鼠标键盘给虚拟机

Adding USB Device Pass-through

在 KVM 中, 可以通过 USB 设备直通 (USB pass-through) 将鼠标、键盘等设备分配给虚拟机。此操作通常需要使用 USB 2.0 或更低版本的协议。

获取设备的供应商 ID 和产品 ID

首先, 使用 lsusb 命令列出所有的 USB 设备, 并找到鼠标和键盘对应的供应商 ID 和产品 ID。例如

$ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 005 Device 012: ID 0a5c:2110 Broadcom Corp. Bluetooth Controller
Bus 005 Device 003: ID 0483:2016 SGS Thomson Microelectronics Fingerprint Reader
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

如果想要选择 Broadcom 公司提供的蓝牙控制器, 供应商 ID 为 0a5c, 产品 ID 为 2110

添加 USB 设备直通

有两种方式可以将 USB 设备添加到虚拟机中: 动态添加 (Hot Add)静态添加 (Static Add)

动态添加

首先, 创建一个只包含设备信息的 XML 文件, 内容如下

<hostdev mode='subsystem' type='usb' managed='yes'>
    <source>
        <vendor id='0x0a5c'/>
        <product id='0x2110'/>
    </source>
</hostdev>

然后, 通过 virsh 命令动态添加设备到虚拟机中

virsh attach-device <guestname> <our-device-xml-file>

要分离设备, 可以使用以下命令

# work with it in the guest
virsh detach-device <guestname> <our-device-xml-file>

静态添加

将设备信息直接写入虚拟机的 XML 配置文件中。打开虚拟机的 XML 文件 (例如: Win10.xml), 并在 <devices> 部分中添加 USB 设备

<domain type='kvm'>
  <name>Win10</name>
  ...
  <devices>
    ...
    <hostdev mode='subsystem' type='usb' managed='yes'>
      <source>
        <vendor id='0x046d'/>
        <product id='0xc534'/>
      </source>
      <address type='usb' bus='0' port='2'/>
    </hostdev>
  </devices>
</domain>

修改完成后, 重新定义虚拟机配置以使更改生效 virsh define Win10.xml

注意事项

  • USB 设备直通时, 确保设备的协议版本是 USB 2.0 或更低
  • 在虚拟机配置中使用 hostdev 元素时, 设备 ID 必须正确无误

14. 虚拟机 win VFIO 驱动程序安装

在虚拟机里下载驱动程序并安装

https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso

之前用 yum install virtio-win 下载的文件在 /usr/share/virtio-win/

15. 给虚拟机添加显卡

Virtual Machine configuration

为了给虚拟机添加显卡, 可以使用 PCI 直通 (PCI Passthrough) 技术, 将主机的显卡设备直通到虚拟机

获取显卡的 PCI 设备 ID

首先, 使用 lspci -nn 命令查找系统中所有的 PCI 设备, 筛选出显卡相关信息

lspci -nn | grep -i nvidia

01:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU102 [GeForce RTX 2080 Ti Rev. A] [10de:1e07] (rev a1)
01:00.1 Audio device [0403]: NVIDIA Corporation Device [10de:10f7] (rev a1)
01:00.2 USB controller [0c03]: NVIDIA Corporation Device [10de:1ad6] (rev a1)
01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device [10de:1ad7] (rev a1)

这里列出的 PCI 设备序号 01:00.0 01:00.1 01:00.2 01:00.3

修改虚拟机的 XML 配置文件

在虚拟机的 XML 配置文件中添加显卡直通配置, 首先找到虚拟机的 XML 配置文件, 路径通常在 /etc/libvirt/qemu/

01:00.0 这里需要对应配置文件的 <source> 节点里面 <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>

<hostdev> 里面是直通一个 PCI 设备, 例如我这里有 4 个需要穿透到里面, 就要有 4 个<hostdev>

<hostdev mode='subsystem' type='pci' managed='yes'>
  <driver name='vfio'/>
  <source>
    <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
  </source>
  <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</hostdev>

完整的显卡和相关设备直通配置

<domain type='kvm'>
  <name>Win10</name>
  ...
  <devices>
    ...
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <driver name='vfio'/>
      <source>
        <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
      </source>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </hostdev>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <driver name='vfio'/>
      <source>
        <address domain='0x0000' bus='0x01' slot='0x00' function='0x1'/>
      </source>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </hostdev>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <driver name='vfio'/>
      <source>
        <address domain='0x0000' bus='0x01' slot='0x00' function='0x2'/>
      </source>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </hostdev>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <driver name='vfio'/>
      <source>
        <address domain='0x0000' bus='0x01' slot='0x00' function='0x3'/>
      </source>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
    </hostdev>
  </devices>
</domain>

修改完需要重新定义虚拟机 virsh define Win10.xml

启动虚拟机

虚拟机现在应该已经能够使用物理显卡。将显示器视频输出线连接到独立显卡

可以通过安装相应的驱动程序 (例如 NVIDIA 驱动程序) 来在虚拟机内使用显卡。

virsh start Win10

16. 解决显卡 43 错误代码

Fighting error 43 – how to use Nvidia GPU in a virtual machine.

在安装了 NVIDIA 显卡驱动后, 如果在 Windows 设备管理器中看到 错误代码 43, 这是因为从 NVIDIA 驱动程序版本 337.88 开始, NVIDIA 会检测虚拟机管理程序 (如 KVM) 并禁用驱动, 导致该错误。

为了解决这个问题, 可以通过修改虚拟机的 XML 配置文件来隐藏虚拟化特性, 使其不被 NVIDIA 驱动检测到

修改 <domain> 标签

修改虚拟机 XML 配置, 路径通常在 /etc/libvirt/qemu/

找到第一行

<domain type='kvm'>

改为

<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>

启用隐藏 KVM

找到 <features> 标签, 添加 <kvm><hidden state='on'/></kvm> 来隐藏 KVM 特性

<features>
  ...
  <kvm>
    <hidden state='on'/>
  </kvm>
</features>

修改 CPU 配置

<devices> 标签的末尾, 添加以下 qemu:commandline 配置, 以禁用虚拟化扩展并隐藏虚拟机特征

  </devices>
  <qemu:commandline>
    <qemu:arg value='-cpu'/>
    <qemu:arg value='host,hv_time,kvm=off,hv_vendor_id=null'/>
  </qemu:commandline>
</domain>

这些设置对我有用 kira~(’· w < ` )

修改完需要重新定义虚拟机 virsh define Win10.xml

17. 给虚拟机添加物理磁盘

2012/10/14: Adding a Physical Disk to a Guest with Libvirt / KVM

通过手动修改虚拟机的 XML 配置文件, 可以将物理磁盘添加到虚拟机中。virt-manager 本身无法直接将物理磁盘添加到虚拟机, 但通过编辑 XML 文件, 你可以实现这一功能。

<devices> 标签中添加磁盘配置

/etc/libvirt/qemu/<your-vm>.xml 在编辑器中打开

在 XML 配置文件中的 <devices> 标签下, 添加 <disk> 配置, 指定要添加的物理磁盘路径。

<devices>
  ...
  <disk type='block' device='disk'>
    <driver name='qemu' type='raw'/>
    <source dev='/dev/md/storage'/>
    <target dev='vdb' bus='virtio'/>
    <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
  </disk>
  ...
</devices>
  • <source dev='/dev/md/storage'/>: 这里指定了物理磁盘的设备路径, /dev/md/storage 是一个示例路径, 你需要根据实际的磁盘路径进行调整
  • <target dev='vdb' bus='virtio'/>: 这是虚拟机中的虚拟磁盘名称 (vdb), 并指定了使用 virtio 总线进行连接。这是推荐的方式, 以提高磁盘性能
  • <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>: 为磁盘指定一个 PCI 地址, 这通常用于管理多个磁盘的设备。我的配置文件加入了这部分

修改完需要重新定义虚拟机 virsh define Win10.xml


本文参考文献

KVM : GPU Passthrough ★★★★★
VGA Passthrough on virtual machines in CentOS 7 ★★★★★
centos 7禁用nouveau及安装NVIDIA显卡驱动 ★★★★★
CentOS7 minimal kvm iommu 辅助虚拟化 vt-x (用于pci透传) ★★★★★
配置宿主机网络 Bridge模式配置 ★★★★★
Why does my Windows 7 VM running under Linux’ KVM not use all the virtual processors? ★★★★★
Fighting error 43 - how to use Nvidia GPU in a virtual machine. ★★★★★
Adding_USB_Device_Pass-through ★★★★★
Adding a Physical Disk to a Guest with Libvirt / KVM ★★★★★
Ubuntu 18.04 - KVM/QEMU Windows 10 GPU Passthrough ★★★★☆
CentOS7.2上用KVM安装虚拟机windows10踩过的坑 ★★★★☆
vga-passthrough/3_BASIC_SETUP.md ★★★☆☆
“Error 43: Driver failed to load” on Nvidia GPUs passed to Windows VMs ★★☆☆☆
Centos7.4安装kvm虚拟机(使用virt-manager管理) ★☆☆☆☆

未使用到的资料 SR-IOV 直通设置 万兆网卡

16.2. PCI DEVICE ASSIGNMENT WITH SR-IOV DEVICES
Frequently Asked Questions for SR-IOV on Intel® Ethernet Server Adapters
QEMU’s new -nic command line option
10G NIC performance: VFIO vs virtio - KVM
libvirt: Domain XML format KVM xml 格式
CentOS 7でKVM + libvirt + Open vSwitchな仮想化環境のつくり方
KVM Virtualization 10gbe virtual ethernet

最后更新于 2022-02-05
使用 Hugo 构建
主题 StackJimmy 设计