基于Proxmox VE的KVM虚拟化实战
Proxmox VE是一个既可以运行虚拟机也可以运行容器的虚拟化平台。Proxmox VE基于Debian Linux 开发,而且完全开源。处于灵活性的考虑,Proxmox VE同时支持两种虚拟化技术:KVM虚拟机和LXC容器。以下操作基于KVM虚拟机。
任务背景:实验室有一台闲置的服务器,配置是64GB内存,10GB NVIDIA RTX 2080 Ti 显卡,i9-10900K 20核CPU。组内有师姐需要跑深度学习代码,而师兄的项目需要在服务器上运行数据库。为了实现数据隔离(生产环境不影响开发环境),考虑了一下两种方案:
1.Docker方案。服务器装ubuntu系统,每个任务运行一个docker
容器。优点是运行任务简单,直接docker pull
相应的容器即可。缺点对于不熟悉docker运维的人来说,维护相对复杂,有些任务需要持久化,需要将不同容器的不同目录映射到ubuntu下的目录。这样无法实现数据隔离,违背了初衷,而且无法实现ip直接访问,需要设置端口映射。遂放弃。
2.PVE-KVM方案。宿主机安装基于debian的Proxmox VE操作系统,不同的任务创建不同的客户机,根据VM ID和ip区分客户机。缺点是配置复杂。不过生命在于折腾,生命不止,折腾不息。
准备工作
检查CPU是否支持VT-d : https://ark.intel.com/content/www/cn/zh/ark.html

设置国内源
修改PVE Debian 源
1 | sed -i 's|^deb http://ftp.debian.org|deb https://mirrors.ustc.edu.cn|g' /etc/apt/sources.list |
添加 Proxmox 社区源
1 | source /etc/os-release |
删除 Proxmox 企业源
1 | source /etc/os-release |
删除订阅弹窗
1 | # 执行完成后,浏览器Ctrl+F5强制刷新缓存 |
修改节点名称
修改
/etc/hostname、/etc/hosts、/etc/postfix/mail.cf里的主机名称,保存复制
/etc/pve/nodes/旧节点名称/所有文件 至/etc/pve/nodes/新节点名称/目录。直接cp或者mv的话,这一步可能会报错
cannot create regular file ‘/etc/pve/nodes/新节点名称/qemu-server/***.conf’: File exists
如果报错:
- 将旧节点
/etc/pve/nodes/旧节点名称/qemu-server/目录下的所有 .conf 文件转移到其他地方,比如下载到本地 - 删除旧节点目录
/etc/pve/nodes/旧节点名称/ - 将备份的 .conf 文件转移回
/etc/pve/nodes/新节点名称/qemu-server/目录
- 将旧节点
重启PVE,在WEB端可以看到节点名称已更改,且旧节点已删除
修改节点名称后,可能需要修改一下附加的存储、NFS目录等
添加多块硬盘
方法一
选择对应节点---->磁盘----->需要添加的磁盘,选择擦除磁盘
![]()
勾选存储目录选项,等待擦除完毕
![]()
检查是否添加成功:依次点击数据中心---->存储
![]()
方法二
- 分区
1 | fdisk /dev/sde1 |
- 格式化
1 | mkfs -t ext4 /dev/sde1 |
- 创建目录
1 | mkdir -p /mnt/sde1 |
- 挂载
1 | mount -t ext4 /dev/sde1 /mnt/sde1 |
- 写入启动项
1 | echo /dev/sde1 /mnt/sde1 ext4 defaults 0 2 >> /etc/fstab |
启用内存ballooning
简单理解就是宿主机会收集和客户机未使用的内存,以免内存会浪费。
但启用内存ballooning也有缺点,如:
- Ballooning需要客户机操作系统加载virtio_balloon驱动,然而并非每个客户机系统都有该驱动(如windows需要自己安装该驱动)
- 如果有大量内存从客户机系统中回收,Ballooning可能会降低客户机操作系统运行的性能。一方面,内存的减少,可能会让客户机中作为磁盘数据缓存的内存被放到气球中,从而客户机中的磁盘I/O访问会增加;另一方面,如果处理机制不够好,也可能让客户机中正在运行的进程由于内存不足而执行失败。
- 目前没有比较方便的、自动化的机制来管理ballooning,一般都是采用在QEMU monitor中执行balloon命令来实现ballooning的。没有对客户机的有效监控,没有自动化的ballooning机制,这可能会让生产环境中实现大规模自动化部署并不很方便。
- 内存的动态增加或减少,可能会使内存被过度碎片化,从而降低内存使用时的性能。
在PVE中可以简单的开启内存ballooning
创建虚拟机时,在内存选项勾选Ballooning设备
![]()
查看是否启用成功
进入客户机,输入以下命令
1
lspci | grep "Red Hat"
![]()
如看到 Red Hat, Inc. Virtio memory balloon 说明启用成功
查看宿主机回收了多少内存
登录宿主机,如这里要查看编号为102客户机的内存回收情况,输入一下命令:
1
2qm monitor 102 # 进入qm shell
qm>info balloon![]()
这里的free_mem就是宿主机从客户机回收的内存大小,可以看到,总共分配了8G,这里回收了大概7G多。在客户机负载比较低的时候还是很有用的。
创建虚拟机
千万注意不要设置自启动!!

选择自己上传的系统镜像,这里以Ubuntu 2004为例。

设置系统选项,注意使用EFI模式

选择CPU时,请根据你的CPU核心数选择。类别选择host。此种模式下客户机下可以看到当前CPU的型号,同时尽量保证虚拟机内的CPU指令集和宿主机内一致。

网络选择:一般情况下选择默认即可。默认是网桥接入。网桥相当于一个软件实现的物理交换机。所有虚拟机共享一个网桥。网桥接入模式下,可以在上一级网关设备查看当前客户机的IP地址。

确认设置,先不要开启虚拟机。

配置显卡直通
首先编辑GRUB配置文件:
1 | nano /etc/default/grub |
开启开启IOMMU支持:
1 | GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on video=efifb:off" |
如果是AMD的CPU:
1 | GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on video=efifb:off" |
我是Intel的CPU,因此修改为:

更新GRUB:
1 | update-grub |
添加所需的系统模块(驱动):
1 | echo "vfio" >> /etc/modules |
接着添加模块(驱动)黑名单,即让GPU设备在下次系统启动之后不使用这些驱动,把设备腾出来给vfio驱动用:
N卡/A卡:
1 | echo "blacklist nouveau" >> /etc/modprobe.d/pve-blacklist.conf |
如果是N卡还需要加入下面的配置到kvm.conf(据老外说是避免一些莫名其妙的错误):
1 | echo "options vfio_iommu_type1 allow_unsafe_interrupts=1" > /etc/modprobe.d/iommu_unsafe_interrupts.conf |
更新内核:
1 | update-initramfs -u |
重启机器:
1 | reboot |
重启上来之后检查模块是否正常加载:
1 | lsmod | grep vfio |
成功的话有类似回显:

查看GPU设备ID:
1 | lspci -nn | grep VGA |
会有类似的回显:

再执行下面的命令(01:00.0请替换成你的显卡ID):
1 | lspci -vvv -s 01:00.0 |
会有类似的回显:


现在把需要直通给虚拟机的设备ID写到vfio.conf内,注意这次这里的ID不是01:00.0而是自己查看自己设备的ID,ID查看在上面回显里:

1 | echo "options vfio-pci ids=10de:1e07" >> /etc/modprobe.d/vfio.conf |
然后应用更改:
1 | update-grub |
更改虚拟机主机类型
其中100 是VM ID
1 | qm set 100 -machine pc-q35-3.1 |
添加显卡
添加PCI设备,注意ID要选择你的电脑对应的显卡ID。注意不要添加成其他设备,如Audio device等。


安装操作系统
此过程略
伪装CPU
由于NVIDIA官方限制在虚拟机中使用显卡,通过修改CPU类型,可以达到欺骗NVIDIA显卡驱动的目的。
1 | nano /etc/pve/qemu-server/<你的虚拟机的ID>.conf |
找到CPU那一行,删掉,然后改为:
1 | cpu: host,hidden=1,flags=+pcid |
如下图:

安装显卡驱动
以下操作是在客户机上完成的,根据显卡选择合适的驱动安装。

安装完毕,重启客户机。执行一下命令查看驱动是否安装成功:
1 | nvidia-smi |
有下图所示回显说明安装成功:

安装qemu-guest-agent
客户机安装qemu-guest-agent,可以在宿主机直接关闭客户机而不需要客户机确认
1 | sudo apt install qemu-guest-agent -y |
PVE配置WiFi
如果你的pve宿主机有无线网卡,可以按照如下步骤配置无线连接。
安装必要的软件
1 | sudo apt update |
设置网络接口
1 | nano /etc/network/interfaces |
1 | auto lo |
PVE的四种网络模式
基于网桥的默认配置
网桥相当于一个软件实现的物理交换机。所有虚拟机共享一个网桥,在多个域的网络环境中, 也可以创建多个网桥以分别对应不同网络域。理论上,每个Proxmox VE 最多可以支持4094个网桥。
Proxmox VE 安装程序会创建一个名为vmbr0 的网桥,并和检测到的服务器第一块网卡桥接。
配置文件/etc/network/interfaces
中的对应配置信息如下:
1 | auto lo |
在基于网桥的默认配置下,虚拟机看起来就和直接接入物理网络一样。尽管所有虚拟机共享 一根网线接入网络,但每台虚拟机都使用自己独立的MAC 地址访问网络。
注意:这种模式在当前是通过无线网卡连接外网的状态下可能无法正常工作!
路由配置
处于网络安全的考虑,大部分网络服务托管商一旦发现网络接口上有多个mac地址出现,托管商有可能立刻禁用相关网络接口。
也许有些网络服务托管商也允许你注册多个mac地址,这样就可以避免上面提到的问题,但这样就需要注册每一个虚拟机的mac地址,实际操作会很麻烦。
可以采用路由的方式让多个虚拟机共享一个网络端口,这样就可以避免上面提到的问题。这种方式可以确保所有的对外网络通信都使用同一个MAC地址。
常见的应用场景是吗,你有一个可以和外部网络通信的IP地址,假定为(192.51.100.5),还有一个供虚拟机使用的IP地址段(203.0.113.16/29)。针对该场景,推荐使用以下配置:
1 | auto lo |
路由模式下,需要在PVE内部搭建DHCP服务器,以便在启动虚拟机时,动态获取网络配置(IP,网关等),该模式下无法直接访问PVE内部虚拟机。如果像直接访问,可以通过代理或者端口转发方式。
基于iptables的网络地址转换配置(NAT)
利用地址转换技术,所有虚拟机可以使用内部私有IP 地址,并通过Proxmox VE 服务器的IP来访问外部网络。Iptables 将改写虚拟机和外部网络通信数据包,对于虚拟机向外部网络发出的数据包,将源IP 地址替换成服务器IP 地址,对于外部网络返回数据包,将目的地址替换为对应虚拟机IP 地址。
1 | auto lo |
LVC容器网络配置
在宿主机的网络配置是通过iptables进行NAT的基础下,设置容器的网络地址为静态配置,从而容器可以正常上网。
安装必要软件
1 | apt install proxmox-ve postfix open-iscsi -y |
下载、导入模板
创建LVC容器
注意勾选无特权的容器

配置网络
桥接vmbr0,设置网关和服务器的IP

设置嵌套虚拟化
如果需要在LVC容器中安装docker需要设置此项






