查看宿主机环境是否支持虚拟化
lscpu | grep -E 'vmx|svm'
如果返回值中又vmx或者svm证明是可以使用宿主机进行虚拟化的
升级内核
如果操作系统是centos7.9以下的建议升级
yum update && yum upgrade
安装虚拟化组件
yum install qemu-kvm qemu-img virt-manager libvirt libvirt-python virt-manager libvirt-client virt-install virt-viewer -y
安装完成后设置虚拟机接口管理组件启动和开机自启
systemctl start libvirtd
systemctl enable libvirtd
关闭selinux
sed -i 's/SELinux=enforcing/SELinux=disabled/' /etc/selinux/config
setenforce 0
关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
配置GPU直通
配置主板支持虚拟化
BIOS打开VT-D和AMD-V
在宿主机中启用iommu
iommu是GPU虚拟机直通的核心,负责把主板上的设备分组,分成一个一个group,每个group都可以单独的启用或者停用,在没启用iommu之前,宿主系统会占用全部的硬件。在启用iommu之后,宿主系统可以有选择的预留一些硬件资源,把这些硬件资源分配给虚拟机
方法一:
编辑/etc/default/grub
文件将intel_iommu=on通过将参数附加到文件中内核行的内核行,在内核中激活 Intel VT-d
GRUB_CMDLINE_LINUX_DEFAULT="... intel_iommu=on ..."
或
GRUB_CMDLINE_LINUX="... intel_iommu=on ..."
重新生成内核
grub2-mkconfig -o /boot/grub2/grub.cfg
重启机器
reboot
验证是否生效
[root@centos ~]# cat /proc/cmdline | grep iommu
BOOT_IMAGE=/vmlinuz-3.10.0-1160.el7.x86_64 root=UUID=46d5848a-0580-47cc-8fcc-da333a56c88f ro intel_iommu=on crashkernel=auto rhgb quiet
[root@centos ~]# dmesg |grep -e DMAR -e IOMMU
[ 0.000000] ACPI: DMAR 0000000069af6000 00348 (v01 ALASKA A M I 00000001 INTL 20091013)
[ 0.000000] DMAR: IOMMU enabled
[ 0.182453] DMAR: Host address width 46
可以看到两个命令输出intel_iommu=on
、IOMMU enabled
则代表已经生效,系统现在支持 PCI 直通
- 注意:如果使用方法一失败,则代表启动时候并没有使用/boot/grub2/grub.cfg,可以使用方法二
方法二:
查询系统grub.cfg文件
[root@centos ~]# find / -name "grub.cfg"
/boot/efi/EFI/centos/grub.cfg
/boot/grub2/grub.cfg
可以看到还有/boot/efi/EFI/centos/grub.cfg
配置文件
打开iommu
对照/boot/grub2/grub.cfg
把intel_iommu=on
添加到/boot/efi/EFI/centos/grub.cfg
相应位置
[root@centos ~]# cat /boot/efi/EFI/centos/grub.cfg | grep intel_iommu=on
linux16 /vmlinuz-3.10.0-1160.el7.x86_64 root=UUID=46d5848a-0580-47cc-8fcc-da333a56c88f ro intel_iommu=on crashkernel=auto rhgb quiet
linux16 /vmlinuz-0-rescue-705f25d4411e49888f865cd230e1105f root=UUID=46d5848a-0580-47cc-8fcc-da333a56c88f ro intel_iommu=on crashkernel=auto rhgb quiet
按照上方格式添加即可,我这里只有关键两行需要更新,有的系统可能有三行需要更新,仅供参考
重启验证
参考方法一
在宿主机中预留iommu group
iommu group是硬件实现上的分组。在Linux的实现中,只认得各个在总线上的硬件,并挨个挨个的启动起来,我们要做的就是阻止Linux内核在启动时初始化某些组里的硬件
这里有一点需要非常注意的是,如果我们需要预留某个iommu组,我们必须完整的预留iommu组里的所有硬件。 如果我们的预留是不完整的,当我们把iommu组分配给虚拟机后,宿主系统会直接IO总线冲突,连重启的机会都没有
加载内核模块vfio-pci
[root@centos ~]# lspci -nn | grep -i nvidia
4f:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2235] (rev a1)
50:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2235] (rev a1)
53:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2235] (rev a1)
57:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2235] (rev a1)
9c:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2235] (rev a1)
9d:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2235] (rev a1)
a0:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2235] (rev a1)
a4:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2235] (rev a1)
可以看到我有八张显卡,因为我只需要直通一张显卡到虚拟机中,所以这里需要记住两个id,4f:00.0和10de:2235
找出iommu group中的所有设备
先找出设备所在的的iommu group
[root@centos ~]# dmesg | grep iommu | grep 4f:00.0
[ 3.573885] iommu: Adding device 0000:4f:00.0 to group 28
可以看到要预留的iommu group是28
这里再次强调,一个iommu group可能带有很多设备,我们只能按照iommu group为单位分配设备给虚拟机
[root@centos ~]# dmesg | grep -e "iommu" | grep -w 28
[ 3.573885] iommu: Adding device 0000:4f:00.0 to group 28
可以看到我这个分组就一个设备,记录左边的值4f:00.0 把这个设备给预留掉
[root@centos ~]# lspci -nn | grep 4f:00.0
4f:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2235] (rev a1)
此时确定我们要预留设备id为10de:2235 如果有多个设备,请逗号分隔
在系统中预留设备
创建文件vfio.conf
[root@centos ~]# cat /etc/modprobe.d/vfio.conf
options vfio-pci ids=10de:2235
创建文件vfio-pci.conf
[root@centos ~]# cat /etc/modules-load.d/vfio-pci.conf
vfio-pci
重启系统
reboot
验证是否加载成功
[root@centos ~]# dmesg | grep -i vfio
[ 32.353304] VFIO - User Level meta-driver version: 0.3
[ 32.543346] vfio_pci: add [10de:2235[ffff:ffff]] class 0x000000/00000000
...
调整网络
配置内核IP转发和过滤器
sysctl -a | grep "\.rp_filter"
把rp_filter = 值
替换成0 ,然后追加到/etc/sysctl.conf
配置文件里 ,同时再加上IP转发和过滤器
[root@centos ~]# cat /etc/sysctl.conf
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.bond0.rp_filter = 0
net.ipv4.conf.bond0/1098.rp_filter = 0
net.ipv4.conf.bond0/1168.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.ens31f0.rp_filter = 0
net.ipv4.conf.ens31f1.rp_filter = 0
net.ipv4.conf.ens42f0.rp_filter = 0
net.ipv4.conf.ens42f1.rp_filter = 0
net.ipv4.conf.lo.rp_filter = 0
net.ipv4.conf.usb0.rp_filter = 0
net.ipv4.ip_forward = 0
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0
重新加载kernel参数
sysctl -p
创建网桥br0
因为创建起来的虚拟机想和宿主机在同一网段中,所以这里我的网络模式选择桥接,接下来需要创建一个网桥设备
[root@centos ~]# cat /etc/sysconfig/network-scripts/ifcfg-br0
TYPE=Bridge
BOOTPROTO=none
DEFROUTE=yes
PEERDNS=yes
PEERROUTES=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=no
NAME=br0
DEVICE=br0
ONBOOT=yes
IPADDR=10.1.98.12
PREFIX=23
GATEWAY=10.1.98.1
DNS1=10.1.98.1
DNS2=114.114.114.114
修改bond0.1098网卡
这个网桥设备是接管宿主机物理网卡的流量,其实就是将物理网卡的IP信息配置在网桥上,在把物理网卡绑定到这个网桥上,接下来修改物理网卡信息(不同机器网卡名不同,根据实际情况修改)
[root@centos ~]# cat /etc/sysconfig/network-scripts/ifcfg-bond0.1098
DEVICE=bond0.1098
VLAN=yes
ONBOOT=yes
BOOTPROTO=static
IPADDR=10.1.98.12
PREFIX=23
GATEWAY=10.1.98.1
DNS1=114.114.114.114
BRIDGE=br0
重启网络
systemctl restart network
查看网桥状态
[root@centos ~]# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.e8ebd301c394 no bond0.1098
vnet0
docker0 8000.02425eb774a7 no
virbr0 8000.5254003c6a11 yes virbr0-nic
可以看见刚刚创建的br0上有个接口是bond0.1098网卡
- vnet0是启动虚拟机后出现的接口,连接虚拟机和网桥
- virbr0网桥是kvm安装后自动创建的用于默认的nat网络
下载virtio驱动
因为kvm安装windows采用的是virtio的形式,主要提供是磁盘和网卡驱动,下载地址:传送门
下载virtio-win-0.1.126_amd64.vfd
创建磁盘
qcow2格式的磁盘也能够动态的分配磁盘空间,只不过,通过virt-manager的图形化界面创建的磁盘默认就是立即分配所有磁盘空间的,如果想要创建一个动态分配磁盘空间的磁盘,需要使用命令提前创建好对应的磁盘,创建磁盘命令如下
qemu-img create -f qcow2 windows-root.qcow2 50G
想要在宿主机中查看这个磁盘最大能够占用多少空间,可以使用qemu-img info命令查看,如下
[root@centos disk]# qemu-img info windows-root.qcow2
image: windows-root.qcow2
file format: qcow2
virtual size: 50G (53687091200 bytes)
disk size: 196K
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
refcount bits: 16
corrupt: false
创建虚拟机
使用命令创建虚拟机,virt-install
命令可以直接在命令行创建虚拟机,iso镜像文件请自行下载,示例如下
virt-install \
--name WindowsTest \
--memory 4096 \
--vcpus sockets=2,cores=2,threads=2 \
--cdrom=/mnt/data/kvm/iso/windows_10_1909_x64_dvd.iso \
--os-type=windows \
--os-variant=auto \
--disk /mnt/data/kvm/disk/windows-root.qcow2,bus=virtio,size=100 \
--disk /mnt/data/kvm/iso/virtio-win-0.1.126_amd64.vfd,device=floppy \
--network bridge=br0,model=virtio \
--host-device 4f:00.0 \
--features kvm_hidden=on \
--graphics vnc,password=123,listen=::,port=5910 \
--hvm \
--virt-type kvm
上述virt-install
命令各个参数含义如下
–name=WindowsTest
表示为创建的虚拟机命名为WindowsTest
–vcpus=2
表示设置虚拟机cpu有2个核心
–memory=4096
表示设置内存为4G
--cdrom
表示使用本地iso镜像安装虚拟机
–disk
表示指定虚拟机的磁盘镜像的路径
--graphics vnc
登录方式为vnc,创建过程vnc远程配置即可
--host-device
显卡的id,建议按组全部添加
--features kvm_hidden=on
//阻止nvidia驱动发现虚拟机
备注:
- 分配给虚拟机的vCPU个数由sockets、cores、threads三个参数的乘积来控制,sockets指代CPU插槽数目,cores指代每个插槽芯片的核心数,threads指代那个核心的超线程,如上所示创建的虚拟机共有8个逻辑cpu
-
listen
指代的是虚拟机的VNC监听接口,默认是localhost,0:0:0:0
指带所有的IPv4接口,::指代所有接口,包括IPv4和IPv6
安装虚拟机
使用vnc来继续完成系统的安装,刚刚创建机器已经指定vnc的端口和密码,ip就是宿主机的,连接上就可进入安装界面了
安装过程中会遇到看不见磁盘的情况是因为没有加载virtio驱动的原因,这时候就轮到virtio-win-0.1.126_amd64.vfd
起作用,virtio驱动是以软盘的形式加载的,这样可以避免虚拟机启动时找不到系统盘镜像
选择“加载驱动”,“浏览”,找到“软盘驱动器”,点开后选择 “Win10”确定,会发现有两个驱动,一个是Ethernet网卡,一个SCSI磁盘,操作两次驱动加载完成后,磁盘就出现了,继续安装即可
加载完驱动就可以看到系统已经识别到磁盘了
后续正常安装即可进入系统,后续配置IP,因为我是桥接模式,正常dhcp默认就会分配和宿主机同网段的IP地址,但是我的网络比较特殊,需要自己配置,就需要找宿主机同一网段未使用的IP地址配置windows中,这里不在详细说明,配置完成后打开远程即可通过IP进行远程连接了
如需要将软盘卸载掉,删除以下内容(编辑前先将虚拟机关机)
[root@centos ~]# cat /etc/libvirt/qemu/WindowsTest.xml
...
<disk type='file' device='floppy'>
<driver name='qemu' type='raw'/>
<source file='/mnt/data/kvm/iso/virtio-win-0.1.126_amd64.vfd'/>
<target dev='fda' bus='fdc'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
...
常用命令
查看所有已经创建的虚拟机
virsh list --all
查看虚拟机的概览信息
virsh dominfo kvm1
查看虚拟机详细信息在/etc/libvirt/qemu
下
[root@centos ~]# cd /etc/libvirt/qemu/
[root@centos qemu]# ls
cirros-test.xml networks kvm1.xml
从上述信息中可以看出,此目录中,有一个以kvm1虚拟机名为前缀的xml文件,这个kvm1.xml中存放的就是kvm1虚拟机的详细配置
上面只是配置的存放位置,不可以用vim直接修改,如果想修改的话需要执行如下命令即可
virsh edit kvm1
如果只是想要查看配置文件的内容,不进行任何修改,其实也没有必要使用virsh edit命令,也不用进入/etc/libvirt/qemu/目录查看对应的配置文件,直接使用virsh dumpxml命令,加上虚拟机名,即可直接将配置文件的内容输出到终端中
virsh dumpxml kvm1
在通过KVM创建虚拟机时,如果没有指定磁盘镜像,那么磁盘镜像默认存放在/var/lib/libvirt/images/目录中,磁盘镜像名以虚拟机名为前缀,以qcow2为后缀,qcow2是KVM默认使用的磁盘镜像格式,它既是虚拟机的磁盘,又是虚拟机的镜像,我们可以通过qcow2文件快速的实现虚拟机的迁移
[root@centos ~]# ll -h /var/lib/libvirt/images/kvm1.qcow2
-rw------- 1 qemu qemu 21G Oct 9 13:03 /var/lib/libvirt/images/kvm1.qcow2
虚拟机关机
virsh shutdown --domain WindowsTest
虚拟机开机
virsh start --domain WindowsTest
虚拟机挂起
virsh suspend --domain WindowsTest
虚拟机删除
virsh undefine --domain WindowsTest
参考网站
https://blog.51cto.com/huanghai/4749617
https://www.jianshu.com/p/035287ba9acb
https://mechanical-consciousness.com/2020/03/20/kvm-gpu-passthrough.html
https://blog.acesheep.com/index.php/archives/720/