如果你手里正好有一台物理服务器或者一台配置还不错的PC,想在上面搭一套KVM虚拟化平台,Rocky Linux 9.6是个非常稳的选择。这套组合我在测试环境和内部基础设施里反复用过,KVM本身是Linux内核自带的虚拟化方案,QEMU负责设备模拟,libvirt管上层生命周期,三者配合起来稳定性和性能都相当能打。这篇东西不是照抄官方文档,是我把从裸机到第一台虚拟机跑起来的完整过程、踩过的坑、以及每个关键步骤背后的逻辑都整理了一遍,适合第一次接触服务器虚拟化的新手,也适合想在自己工作环境里快速复现KVM平台的运维同学。
1. 为什么我在这台宿主机上选了Rocky Linux 9.6 + KVM
很多人上来就问,虚拟化不是有VMware、有OpenStack,为什么还要自己在物理机上装KVM?我的答案很简单:在纯Linux环境里,KVM是最贴合内核的一套方案,不需要额外买商业授权,性能损耗非常低,而且Rocky Linux这种长期支持的企业级发行版,九年内能持续收到安全更新,比那些装完就没人维护的社区版本省心得多。
1.1 KVM、QEMU、libvirt到底各管什么
先说清楚这三个东西的关系,不然很多人装完还是一团浆糊。
KVM是内核模块,它把CPU的硬件虚拟化能力暴露给用户态,虚拟机里的CPU指令可以直接跑在物理CPU上。QEMU是一个用户态程序,负责模拟出硬盘、网卡、USB、显卡这些外围设备,让虚拟机认为自己跑在一台完整的主机上。libvirt则是中间管理层的API和守护进程,virsh、virt-manager这些工具最终都是通过libvirt去和QEMU打交道。
用生活化的类比来说:KVM像是打通了CPU和虚拟机之间的专用通道,QEMU负责把虚拟机的"家电"都摆出来,libvirt是那个拿遥控器的人。所以安装时这三类包缺一不可。
1.2 企业级场景里Rocky 9.6的几个明显优势
- 继承自RHEL的稳定基线和严格的兼容性测试,不容易出现"今天升级明天跑崩"的情况。
- 9.x系的内核默认对KVM模块、cgroup v2这些虚拟化依赖项支持得很完整,不像某些桌面向发行版还得自己折腾内核参数。
- 官方仓库里就有最新的qemu-kvm、libvirt、virt-install包,版本不会像Debian那样长期停在老版本。
另外,如果以后要对接更上层的私有云或自动化平台,基于KVM的libvirt接口基本是标准配置。像国内一些服务器厂商的虚拟化平台,底层也经常能看到QEMU/KVM的影子,所以先掌握这套东西,后面迁移和理解其他平台都会顺手很多。
2. 装之前先把硬件和系统状态盘明白
我见过太多人装到一半发现虚拟机启动时报"此平台不支持虚拟化的AMD-V"或者"KVM不可用",原因是CPU虚拟化没开,或者系统状态不对。所以第一步先把底盘摸清楚,别急着敲安装命令。
2.1 检查CPU是否支持硬件虚拟化
在Rocky 9.6终端里执行:
grep -E -c '(vmx|svm)' /proc/cpuinfo lscpu | grep -E 'Virtualization|Hypervisor|CPU\(s\)'如果第一行输出的数字大于0,说明CPU有虚拟化指令集。其中Intel的标记是vmx,AMD的标记是svm。注意如果用lscpu看到"Hypervisor vendor: KVM"之类的内容,说明当前这台机器本身就是虚拟机,里面再装KVM属于嵌套虚拟化,后面需要额外配置,这个坑我留到第9章细说。
如果grep结果为0,先别急着去装KVM,大概率是BIOS里关闭了VT-x或AMD-V,重启进BIOS找CPU Configuration,把Intel Virtualization Technology或SVM Mode打开。
2.2 BIOS里的两个隐藏设置
除了CPU的虚拟化开关,还有两个设置在服务器上特别容易被忽略。
第一个是Secure Boot。Rocky 9.6默认内核是签了名的,开启Secure Boot后引导没问题,但第三方KVM模块如果签名链不完整,加载时就可能被拦。我的建议是:如果这台机器是纯内网虚拟化服务器,干脆进BIOS把Secure Boot关掉,省得后面加载nvidia驱动、vhost模块时出现各种奇怪的Operation not permitted。
第二个是VT-d/IOMMU。如果以后想把物理网卡、GPU直通给某台虚拟机,必须在BIOS里开启VT-d,同时在内核启动参数里加上intel_iommu=on或amd_iommu=on。这次只做普通虚拟化可以不配IOMMU,但既然装机,顺手确认一下它支持即可,一劳永逸。
2.3 确认系统版本和仓库状态
cat /etc/redhat-release uname -r dnf repolist正常情况应该看到Rocky Linux release 9.6,内核版本在5.14.x左右。如果dnf repolist输出为空,先执行dnf makecache重新构建缓存。另外确认当前用户有sudo权限,或者直接用root操作,因为后续所有命令都用root身份执行最省事。
还有个容易踩的点:装服务器版的时候别用最小化安装还取消了"Standard"开发工具组,不然编译内核模块或装机器时会缺一堆基础依赖。如果已经装成最小化了,执行下面命令补一下:
dnf group install -y "Development Tools"2.4 磁盘和内存规划
创建虚拟机的镜像、ISO文件都存放在宿主机上,所以建议给系统盘留至少100GB空间,并把/var/lib/libvirt分区挂载到一个独立的大分区。内存方面,宿主机本身建议不低于8GB,每台虚拟机预留1-4GB,这个按自己场景来。我这次宿主机是32GB内存、8核CPU、500GB SSD,跑四五台中小型虚拟机完全没有压力。
3. 安装KVM组件:一条命令入场,但每个包都要心里有数
在Rocky 9.6上安装KVM最让人安心的就是不用像Arch那样手动拼模块,官方仓库已经把该有的包都准备好了。执行这条命令:
dnf install -y qemu-kvm qemu-kvm-tools libvirt libvirt-client virt-install virt-viewer edk2-ovmf如果你还想要图形管理界面,再加一个包:
dnf install -y virt-manager很多人问为什么不装qemu-kvm-core,因为qemu-kvm已经依赖并包含了核心部分,直接装这个能满足绝大多数使用需求。下面这张表列一下每个包到底是干嘛的,方便你后期排查问题:
| 包名 | 作用 | 是否必须 |
|---|---|---|
| qemu-kvm | QEMU机器模拟器,负责虚拟机设备模拟 | 是 |
| libvirt | libvirtd守护进程和运行时库 | 是 |
| virt-install | 命令行创建虚拟机的神器,支持自定义完整参数 | 是 |
| virt-viewer | VNC/SPICE图形显示客户端,安装时看界面用 | 推荐 |
| libvirt-client | 提供virsh命令行管理工具 | 推荐 |
| virt-manager | 图形化管理虚拟机 | 可选 |
| edk2-ovmf | UEFI固件文件,支持虚拟机以UEFI方式启动 | 推荐 |
安装完成后,确认一下版本:
qemu-kvm --version libvirtd --version virsh --version我的输出分别为QEMU emulator version 8.2.0、libvirtd (libvirt) 10.3.0、10.3.0,都比较新,说明仓库版本很牢靠。
这里多说一句:不要同时装qemu-system-x86_64和旧版kvm,Rocky 9.6里这两个东西可能冲突。一切以官方仓库的qemu-kvm为准,别再去找什么第三方源,企业环境最怕源混乱。
4. 启动libvirtd后的能力体检:virt-host-validate结果怎么读
装完包之后,第一件事是启动服务并设置开机自启:
systemctl enable --now libvirtd systemctl status libvirtd这里有个细节,libvirt从新版本开始默认开启了socket激活机制,所以libvirtd服务状态检查有时会看到active (running),有时候master进程没常驻但socket在监听。只要systemctl status libvirtd不出现failed,一般不用惊慌。
接着运行下面的命令检查当前主机是否满足运行KVM的要求:
virt-host-validate qemu输出会包含一堆PASS、WARN、FAIL项。多数情况下,你看到的是类似这样的内容:
QEMU: Checking for hardware virtualization : PASS QEMU: Checking for device /dev/kvm : PASS QEMU: Checking for secure guest support : WARNPASS说明CPU虚拟化和/dev/kvm设备都已经就绪,可以正常创建虚拟机了。WARN里面有些是特性层面的检测不过,比如secure guest support要求AMD SEV或Intel TME,不支持也不影响日常使用。
看到FAIL才需要紧张。最常见的一个FAIL是:
QEMU: Checking for host CPU frequency scaling : FAIL这个通常发生在虚拟机嵌套环境中,提示权限不允许访问CPU频率信息。解决办法是在宿主机的启动参数里加kvm.ignore_msrs=1,或者不用管它,因为它阻塞不了虚拟机运行,只是会影响性能监控类工具。另一个常见FAIL和cgroup权限有关,出现时检查当前用户是否在libvirt组里,或者用root身份运行。
为了让普通用户也能用virsh,记得把账号加入libvirt组:
usermod -aG libvirt <你的用户名>之后退出重登即可。如果不想切用户,直接用root执行管理命令也行,只是个人习惯上建议用组权限来做隔离。
在这之后,跑一下virsh list --all确保命令能正常连接libvirtd。如果提示连接失败,检查/run/libvirt/libvirt-sock是否存在,以及有没有selinux拦截,Rocky默认强制SELinux,但libvirt的配置文件已经放行了常规操作,一般不会出错。
5. 网络是虚拟化最容易翻车的地方:桥接与网卡配置
我一直觉得网络配置是KVM从"装好"到"能用"之间最大的坎。默认安装完libvirt后,它会创建一个NAT模式的虚拟网桥virbr0,虚拟机通过这个网桥上网,宿主机进行地址转换。简单测试用NAT没问题,但如果你想虚拟机像局域网内一台独立主机一样被别人直接访问,就必须走桥接网络。
5.1 NAT和桥接怎么选
NAT模式就好比你住在集体宿舍,宿舍大门只有一个IP,大家共用这个IP上网,外面的人想单独进你的房间找你是找不到的。桥接模式则是给虚拟机单独分配一个真实的局域网IP,它和宿主机在同一个网段里,外面可以直接SSH进虚拟机。
对于部署企业内部服务、数据库、网关这些场景,我强烈建议一开始就配成桥接。因为KVM网络配好之后再改桥接,要把已有虚拟机停掉、重建虚拟网卡,麻烦得很。不如装机时一次到位。
5.2 查看当前网卡和网桥状态
先确认宿主机网卡名称和现有桥接关系:
ip addr show nmcli device statusRocky 9.6用的是NetworkManager管理网络,所以强烈建议所有网络修改都通过nmcli做,别直接改文件然后重启网络服务,容易产生配置漂移。我见过太多人手动改了ifcfg-*文件之后,NetworkManager再启动时又把它覆盖回原来的状态,原因就是两者信息不同步。
5.3 创建Linux Bridge的nmcli完整流程
假设宿主机网卡叫ens3,原本通过DHCP自动获取IP。现在要把这块物理网卡加入桥接设备br0,并让br0获得之前ens3的IP:
nmcli con add type bridge ifname br0 con-name br0 nmcli con modify br0 ipv4.method auto nmcli con add type bridge-slave ifname ens3 master br0这样操作之后,br0就继承了ens3的物理链路。执行:
nmcli con up br0 nmcli con up bridge-slave-ens3再看一下ip addr show br0,如果br0拿到了IP,说明桥接成功。
别现在就急着把原ens3的autoconnect关掉,等一切稳定后再执行:
nmcli con modify "Wired connection 1" connection.autoconnect no这里面有个易错点:连接名并不等于接口名。Rocky里的有连接名和接口名两套概念,nmcli device status看到的是设备名,而nmcli con show看到的连接名可能叫System ens3或者Wired connection 1,操作时务必用连接名。为了避免搞混,我在配桥接前会先把旧连接的连接名改成符合规范的:
nmcli con modify "Wired connection 1" con-name ens3改完连接名之后,后续所有nmcli con都以ens3为准。
6. 静态IP和网卡配置文件的完整落地过程
桥接网络基础上,宿主机和虚拟机都建议使用静态IP。因为虚拟化平台里,每台虚拟机都对应着不同服务,IP一变,服务发现、数据库连接串、SSH配置全部跟着崩。在Rocky 9.6上配置静态IP,我一般优先用nmcli,但它底层还是落在/etc/NetworkManager/system-connections/ens3.nmconnection这个文件里。
6.1 用nmcli快速配置静态IP
以把br0配成静态IP192.168.1.200/24、网关192.168.1.1、DNS192.168.1.1为例:
nmcli con modify br0 ipv4.method manual \ ipv4.addresses 192.168.1.200/24 \ ipv4.gateway 192.168.1.1 \ ipv4.dns "192.168.1.1 8.8.8.8" \ ipv4.never-default no nmcli con up br0注意ipv4.method必须显式修改为manual,否则配置不生效。never-default no的意思是允许把这个网卡设为默认路由,别误配成yes。
6.2 手动编写网卡文件时,Rocky 9.6和7/8的区别
如果你习惯了CentOS 7时代直接改/etc/sysconfig/network-scripts/ifcfg-*的方式,在Rocky 9.6上请务必留心:NetworkManager默认不再读取/etc/sysconfig/network-scripts里的旧式ifcfg文件了。新配置文件在/etc/NetworkManager/system-connections/下面,格式是INI风格,扩展名.nmconnection。
我们打开刚才生成的/etc/NetworkManager/system-connections/br0.nmconnection,会看到类似内容:
[connection] id=br0 type=bridge interface-name=br0 autoconnect=true [ipv4] method=manual address1=192.168.1.200/24 gateway=192.168.1.1 dns=192.168.1.1;8.8.8.8; [bridge] stp=false如果要复制到其他机器,需要设置权限为600:
chmod 600 /etc/NetworkManager/system-connections/br0.nmconnection之后重载配置:
nmcli con reload nmcli dev reapply br0如果你就是喜欢用老式ifcfg方式,Rocky 9.6也还留了个兼容口子,但需要安装network-scripts包,官方已经标记为deprecated,我不建议在生产环境里走这条路。既然新的方案成熟稳定,就不要再守着旧习惯了。
6.3 同一个网卡文件里多IP的写法
有时宿主机除了管理IP,还需要给虚拟化流量单独配一个IP。在nmcli里添加多个地址的写法是:
nmcli con modify br0 +ipv4.addresses 10.10.0.5/24如果用配置文件方式,则对应:
[ipv4] address1=192.168.1.200/24 address2=10.10.0.5/24重启网络后两个IP都能正常使用。这种多IP在KVM平台里很有用,一个网段走管理面,另一个网段专门给虚拟机业务流量。
7. 用virt-install创建第一台虚拟机并完成安装
网络配好之后,终于可以创建虚拟机了。创建虚拟机有两种主流方式,一种是命令行virt-install,功能全面且方便脚本化;另一种是图形工具virt-manager,适合不想记参数的人。我推荐所有新手至少先学会virt-install,因为你在排查问题和自动化部署时迟早要回到命令行。
7.1 准备ISO镜像文件
把系统镜像上传到宿主机,规范做法是放到libvirt的默认镜像目录:
mkdir -p /var/lib/libvirt/boot cp /path/to/Rocky-9.6-x86_64.iso /var/lib/libvirt/boot/注意目录权限,如果libvirt用的用户是qemu,但镜像文件权限为root,可能在安装时出现"Permission denied"。稳妥起见执行:
chown qemu:qemu /var/lib/libvirt/boot/*.iso7.2 virt-install核心参数解读
下面这条命令是我在一个内网环境里实际用过的完整示例,创建一台名为vm-dev的Rocky Linux 9.6虚拟机:
virt-install \ --name vm-dev \ --memory 4096 \ --vcpus 4 \ --disk path=/var/lib/libvirt/images/vm-dev.qcow2,size=50,format=qcow2,bus=virtio \ --cdrom /var/lib/libvirt/boot/Rocky-9.6-x86_64.iso \ --network bridge=br0,model=virtio \ --os-variant detect=on,name=rocky9.6 \ --graphics vnc,listen=0.0.0.0 \ --video virtio \ --boot uefi \ --autostart逐项解释:
--memory 4096:内存4GB,单位是MiB,别理解成字节。--vcpus 4:4个vCPU。--disk path=... size=50 format=qcow2 bus=virtio:创建一个50GB的qcow2磁盘,走virtio总线,性能比模拟IDE高很多。--cdrom:挂载安装ISO。--network bridge=br0,model=virtio:使用刚才创建的桥接网络,网卡模型也是virtio。--os-variant detect=on,name=rocky9.6:让libvirt自动适配操作系统的virtio驱动、时钟参数等。--graphics vnc,listen=0.0.0.0:开启VNC远程显示,这样可以通过局域网内任何一台机器连上去安装。
如果--os-variant detect=on识别失败,先执行osinfo-query os | grep -i "rocky"查看支持列表,选一个最接近的名称。
7.3 在客户端连接VNC完成系统安装
命令执行后,终端会停住等待安装完成。此时在另一台电脑上用VNC客户端连接宿主机的IP,默认端口是5900,如果是第二台虚拟机则可能是5901,可以通过virsh vncdisplay vm-dev查询。
安装过程跟普通物理机装Rocky完全一样,选择语言、磁盘分区、安装源。唯一需要留意的步骤是分区之后要勾选让安装器生成UEFI引导,因为我们指定了--boot uefi。如果忘记这个,装完系统会无法引导。
7.4 安装完成后看到的几种状态
安装步骤走完、系统自动重启后,回到宿主机执行:
virsh list --all应该能看到vm-dev的状态为shut off,如果不是自动启动,手动执行:
virsh start vm-dev再执行一次virsh list,状态变为running,说明这台虚拟机的生命周期已经完全交给libvirt管理了。
之后可以通过SSH直接登录虚拟机,不用再依赖VNC:
ssh root@192.168.1.2018. 虚拟机创建之后的常用加固和自启动设置
很多教程到虚拟机开机就算结束了,但实际用起来还有几个设置必须做,否则重启一次宿主机你就要手动启动一堆虚拟机。
8.1 开机自动启动
如果刚才创建时漏加了--autostart,可以补上:
virsh autostart vm-dev查看是否启用:
virsh dominfo vm-dev | grep Autostart输出Autostart enable说明开机就会自动拉起这台虚拟机。如果有多台虚拟机,建议先启动依赖服务,再启动被依赖的服务,可以通过virsh autostart --disable vm-b来调整顺序。
8.2 存储性能细节
创建磁盘时,qcow2格式支持精简配置,且写时复制效率不错,适合开发测试。如果虚拟机跑数据库或高IO业务,建议磁盘总线选virtio,缓存模式用writeback或none,不要用默认的writethrough,那个写性能差一截。对于已有虚拟机,可以通过virsh edit vm-dev修改磁盘的cache属性,然后重启虚拟机生效。
另外,给虚拟机打快照时,qcow2相比raw有天然优势:
virsh snapshot-create-as vm-dev snap-before-update "before package update" virsh snapshot-list vm-dev快照别保留太长时间,占用的空间会随写入量增大,时间久了反而拖累宿主机磁盘。
8.3 CPU和内存的host-passthrough模式
虚拟机的CPU模式默认可能是custom或qemu64,这会导致虚拟机看不到宿主机的完整CPU特性,一些依赖AVX512或特定指令集的程序可能跑不起来。改成直通模式:
virsh edit vm-dev把CPU段修改为:
<cpu mode='host-passthrough' check='partial'/>保存后重启虚拟机。这种模式让虚拟机直接暴露宿主机全部CPU特性,性能损失最小,代价是虚拟机跨宿主机热迁移时兼容性变差。如果是单机环境,我无脑推荐host-passthrough。
8.4 磁盘空间配额和使用监控
我习惯给每台虚拟机设磁盘上限,qcow2默认用多少扩多少,但没有上限,有时候日志一膨胀就把宿主机磁盘撑爆了。查看各虚拟机磁盘占用:
du -sh /var/lib/libvirt/images/*.qcow2如果宿主机磁盘紧张,先找哪些快照可以删除,再考虑压缩qcow2。压缩前必须先关闭虚拟机:
virsh shutdown vm-dev qemu-img convert -O qcow2 vm-dev.qcow2 vm-dev-compact.qcow2这个命令把实际占用空间重新写入一个新镜像,能回收不少空闲空间。
9. 实操中遇到的几个坑及排查思路
最后把我这次安装过程中真实遇到过的报错和解决路径写下来,这些内容比安装步骤本身更有参考价值。
9.1 报错:/dev/kvm No such file or directory
这是新手最常碰到的。先查模块:
lsmod | grep kvm modprobe kvm_intel如果modprobe报错"Operation not permitted",基本就是BIOS里没开VT-x,或者当前就在虚拟机里。确认物理机设置后,再执行:
grep -E -c '(vmx|svm)' /proc/cpuinfo里面是0,那就没跑,回BIOS开户再启动。这个坑在服务器上尤其烦人,有的服务器BIOS里默认关闭虚拟化,品牌机型设置路径还不太一样,比如某些服务器固件要在"Advanced > Processor Configuration"里才找得到,搜"SVM"关键字效率更高。
9.2 嵌套虚拟化:虚拟机里再装KVM
如果像我一样在VMware/KVM虚拟机里跑Rocky 9.6做测试,默认/dev/kvm不存在。此时需要让宿主机暴露虚拟化功能:
cat /etc/modprobe.d/kvm.conf options kvm_intel nested=1修改后重启宿主机再验证。如果宿主机是VMware Workstation,还要在虚拟机设置里勾选"虚拟化Intel VT-x/EPT或AMD-V/RVI"。跑virt-host-validate qemu能通过大部分项,但性能频率检测通常还是WARN,不影响使用。
9.3 virsh net-start default报错的解决
有时默认NAT网络起不来:
virsh net-list --all如果default显示不活跃,手动启动:
virsh net-start default virsh net-autostart default这个网络依赖virbr0网桥,如果之前你配置静态IP时不小心把virbr0删了,也会导致失败。用ip addr show virbr0确认桥在不在,不在就执行:
nmcli con delete virbr0 systemctl restart libvirtdlibvirtd会自动重建virbr0。
9.4 VNC连接不上的三个排查方向
首先确认virsh vncdisplay vm-dev有输出,如果为空说明虚拟机没启用VNC。其次防火墙放行端口:
firewall-cmd --permanent --add-port=5900/tcp firewall-cmd --reload最后确认virt-install里用了--graphics vnc,listen=0.0.0.0,如果只写了--graphics vnc,默认只监听127.0.0.1,外部连接自然是堵死的。这是因为libvirt为了安全会优先绑定本地回环,远程管理必须显式放宽监听地址。我在内网环境里操作时会把listen设为0.0.0.0,但要注意:监听所有地址意味着局域网内只要知道VNC端口就能尝试连入,生产环境一定要通过防火墙限制来源IP。
9.5 桥接模式下虚拟机没有网络
创建时指定了bridge=br0,但虚拟机启动后拿不到IP。先从宿主机角度排查桥接是否正常,看一下br0是否持有物理网卡的IP,再确认STP是否导致网桥延迟,我在/etc/NetworkManager/system-connections/br0.nmconnection里把stp=false,减少桥接收敛时间。
虚拟机内部再执行ip addr show,确认网卡是up状态且有地址。如果是静态IP,检查子网和网关是否和宿主机在同一网段;如果是DHCP,确认物理路由器上有足够地址池。这个问题其实一大半是物理交换机端口没配置成trunk或access模式,导致虚拟机的VLAN流量直接被丢弃,排查时先看看宿主机和物理网络是否连通,别一开始就怀疑KVM。
最后补一句踩过几次坑之后的个人体会
如果你只是想在本地验证KVM功能,按第3章的安装命令跑完,然后直接用默认NAT创建一台虚拟机就够了,不用折腾桥接。但只要你打算拿这套平台长期跑服务,静态IP、桥接网络、autostart、host-passthrough这些配置一个都不能省,不然每次宿主重启之后,等待你的就是一台一台手动开机和改配置的重复劳动。我在实际运维中吃过"忘了设autostart导致业务虚拟机没起来"的亏,也见过同事因为网卡配置文件和NetworkManager不一致,网络彻底断连只能去机房处理的情况。KVM本身稳定性不用怀疑,但周遭的规划和细节,才是虚拟化平台真正让人省心还是让人糟心的分界线。