简介:面向虚拟化实施与运维人员的经验型资料包,聚焦 VMware 与 Citrix 两类虚拟化环境,围绕项目落地过程中遇到的问题及常见故障整理解决思路,适合系统运维、实施工程师以及刚接触虚拟化、需要积累排错经验的技术人员参考。内容以实际实施场景中的问题处理为主,既包含个人在虚拟化部署与维护中踩坑后的解决办法,也对常见问题进行了归纳,便于读者按现象查找排查方向,理解处理逻辑而非只记步骤。压缩包为 zip 格式,体积约 15.45MB;上游未提供文件总数与类型明细,具体构成以实际包内为准。目前已有 502 人学习,说明该主题在实施群体中有一定参考需求。读者可从中获得 VMware、Citrix 虚拟化问题的应对思路与经验沉淀,在遇到类似报错、配置异常或运行故障时减少重复试错,也可作为日常运维和项目实施中的排错参考。
1. 虚拟化实施出现问题的原因:CPU 虚拟化开关没打开
虚拟化实施翻车,十次里有六次不是出在 XML 配置上,而是机器根本没把 CPU 的虚拟化开关打开。我接手过一台二手服务器,KVM 相关包装得干干净净,virsh 也能连上,virt-install 一跑就卡在 Starting install 那一行,等十分钟和等一小时没区别,日志里只有一句 KVM acceleration can not be used。同一个问题在物理机、云主机、开发本上都能遇到:云主机多半是嵌套虚拟化没开,开发本则是 BIOS 里的 VT-x 默认关着。这篇笔记按一台空白机器的顺序走一遍:版本怎么选、包怎么装、网络和存储怎么配、出问题后怎么查、最后怎么确认真的跑通。适合第一次搭 KVM/libvirt 的人,也适合搭过但被“能装不能用”折腾过的人。
2. 版本选型:KVM、QEMU、libvirt 装哪一代,8.x/9.x 怎么取舍
装虚拟化最容易犯的错,是把“能装”当成“能用”。apt install qemu-kvm libvirt-daemon-system这两条命令在任何一台 Linux 上几乎都不会报错,但装出来的东西能不能开硬件加速、能不能热迁移、快照能不能回滚,取决于三个组件版本是不是互相对得上。这一章先把三件套的职责分工拆开,再说什么时候该用发行版仓库、什么时候值得手动升级,最后落到装之前的物理检查。
2.1 三个组件各管什么,版本不要混在一起看
KVM 是内核里的模块,负责把 CPU 的硬件虚拟化能力暴露成/dev/kvm设备,它没有独立版本号,跟内核版本绑定;QEMU 是跑在用户态的进程,负责模拟主板、磁盘控制器、网卡、显卡这些设备,一台虚拟机的“硬件”其实是它画出来的;libvirt 是一层管理 API 和守护进程,virsh、virt-install、virt-manager 都是它的客户端,它自己不管模拟,只负责把 XML 翻译成 QEMU 的命令行、管理生命周期、管网络和存储池。
这三个组件的版本互相有兼容矩阵,但日常最需要盯的是 libvirt 和 QEMU 的搭配。发行版仓库里的包本来就是成对打过补丁的,一般不用操心;真正会出问题的是“libvirt 用仓库的、QEMU 自己编译”的组合,表现是 virsh define 能过,virsh start 报internal error: process exited while connecting to monitor或者unsupported configuration: ...。
| 组件 | 作用 | 建议版本下限 | 检查命令 |
|---|---|---|---|
| KVM 内核模块 | 提供硬件加速 | 内核 5.10 以上 | lsmod | grep kvm |
| QEMU | 设备模拟与虚拟机进程 | 6.2 以上 | qemu-system-x86_64 --version |
| libvirt | 管理 API、守护进程 | 8.0 以上 | virsh --version |
| virt-install | 命令行创建虚拟机 | 4.0 以上 | virt-install --version |
| bridge-utils / iproute2 | 网桥管理 | 随发行版 | bridge -V |
libvirt 8.x 与 9.x 这一代的主要差别在 q35 机型的默认设备、virtio-blk 的多队列支持、以及 cgroup v2 环境下的资源限制方式。如果你用的是 Ubuntu 22.04(仓库 libvirt 8.0)或 Debian 12(仓库 libvirt 9.0),这些能力都已经具备,不需要为了版本号去折腾第三方源。
2.2 发行版仓库还是自己编:先看内核,再看 libvirt
我一般的判断顺序是:内核能不能满足,仓库版本够不够用,最后才考虑自编译。内核决定了 KVM 的能力上限,如果内核版本偏老,光升级 QEMU 没有意义;仓库里的 libvirt 只要不低于 8.0,绝大多数生产场景(快照、热插拔、在线迁移、virtio 多队列)都能覆盖。
真正需要手动升级的典型场景只有两种:一是要用到新版本才有的机型或设备特性,比如某些 virtio 设备的特性位;二是宿主机需要跨大版本在线迁移,而两端 libvirt 的 XML 方言对不上。这两种情况下,我更倾向整机升级发行版,而不是单独编译一个 QEMU 塞进系统——编译出来的 QEMU 缺少发行版的 SELinux/AppArmor 策略适配,虚拟机磁盘路径稍微偏一点就会被安全模块拦住,排查成本远高于升级收益。
还有一类容易被忽略的差异是固件。UEFI 启动的虚拟机需要 OVMF 固件包(Debian 系叫ovmf,RHEL 系在edk2-ovmf里),如果不装,virt-install 加--boot uefi会直接报找不到 firmware。装之前先想清楚要不要 UEFI 和安全启动,比装完再补要省事。
2.3 装之前先做四项系统检查
包管理器不会替你检查硬件,这一步必须手动做。下面四条命令加起来不到十秒,能挡掉后面一半的求助。
# 1. 确认 CPU 是否支持硬件虚拟化,返回数字大于 0 才算有 egrep -c '(vmx|svm)' /proc/cpuinfo # 2. 看内核模块有没有加载,kvm_intel 或 kvm_amd 二选一 lsmod | grep -E 'kvm_intel|kvm_amd' # 3. 确认 /dev/kvm 设备存在且有读写权限 ls -l /dev/kvm # 4. 看内核日志里 KVM 的初始化信息,有没有被固件关掉 dmesg | grep -i -E 'kvm|virtualization'第一条返回 0 就别往下装了,先去 BIOS 里找 Intel Virtualization Technology(VT-x)或 AMD-V(SVM Mode)打开,顺带把 VT-d / IOMMU 也一起开,后面做设备直通会用到。第二条如果只看到kvm而没有kvm_intel/kvm_amd,说明 CPU 特性没被识别,通常是嵌套虚拟化环境;云主机上需要确认实例类型是否支持嵌套,物理机上则回到 BIOS 检查。
第三条的权限位很关键,正常是crw-rw---- root kvm。如果/dev/kvm不存在,后面所有虚拟机都只能跑纯软件模拟,速度会慢一个数量级,而且 CPU 占用会直接占到 100%——这种“装好了但巨慢”的现象最容易让人怀疑是磁盘或网络问题。
第四条能看到kvm: ... VMX enabled这类字样就说明硬件加速已经就绪。如果看到kvm: disabled by bios,那就是固件层面关掉了,软件层面无解。
另外顺手看一眼内存和磁盘余量:free -g里可用内存要能容下第一台虚拟机的分配量,df -h /var/lib/libvirt/images要留出至少两倍磁盘容量的空间,因为 qcow2 快照和安装过程的临时文件都会额外占用。存储池默认落在/var/lib/libvirt/images,如果根分区只有几十 G,最好一开始就把存储池指到独立的数据盘上,等虚拟机跑起来再迁,成本会高很多。
3. 安装与初始化:从装包到 virsh 能连上
硬件检查通过之后才进入真正的安装环节。这一章的每一步都有个明确的“验收点”:装完包要能看到服务起来,改完配置要能以普通用户连上 qemu:///system,启动默认网络要能 dhcp 拿到地址。中间任何一步没通过就停在原地排查,比全部装完再回头找问题要快得多。
3.1 两条装包命令线:Debian 系与 RHEL 系
包名在两大发行版家族里完全不同,不要照抄。Debian/Ubuntu 上qemu-kvm是个过渡包,实际会拉进qemu-system-x86;RHEL 系则用组的方式一次性装齐。
# Debian / Ubuntu 系 apt update apt install -y \ qemu-kvm \ # KVM 相关的 QEMU 组件 qemu-system-x86 \ # x86 架构的系统模拟器 libvirt-daemon-system \ # libvirtd 守护进程与默认配置 libvirt-clients \ # virsh、virt-host-validate 等客户端 virtinst \ # virt-install / virt-clone 命令 bridge-utils \ # brctl,排查网桥时还会用到 ovmf # UEFI 固件,不装则无法 UEFI 启动 # RHEL / CentOS Stream / 兼容发行版 dnf install -y @virtualization dnf install -y edk2-ovmf装完之后立刻用virt-host-validate做一次自检,它会把硬件虚拟化、IOMMU、cgroup、设备节点权限逐项列出来,输出里出现FAIL的行就是下一步要处理的点。这个命令比翻日志直观得多,建议固化成习惯。
qemu-kvm这种过渡包在新版本里可能被标记为废弃,装的时候会提示“由 qemu-system-x86 提供”,不用管,只要qemu-system-x86_64 --version有输出就行。RHEL 系的@virtualization组里不含 UEFI 固件,需要单独补edk2-ovmf,这一点和 Debian 系不一样,跨发行版写脚本时容易漏。
3.2 服务与权限:libvirtd 的 socket、用户组和 polkit
装完包后 libvirtd 一般不会自动跑起来,或者跑起来了但你用普通用户连不上。这里有两套机制在起作用:一是 systemd 的 socket 激活,二是用户组与 polkit 授权。
# 开机自启并立即启动(两种单元名都列出来,按发行版实际情况选) systemctl enable --now libvirtd.service systemctl enable --now libvirtd.socket # 把当前用户加进 libvirt 和 kvm 组,避免每次都 sudo usermod -aG libvirt,kvm "$USER" # 让组成员关系立即生效,省得重新登录 newgrp libvirt # 验收:以普通用户身份连系统级 hypervisor virsh -c qemu:///system list --all这里有个关键区别:qemu:///system是系统级实例,虚拟机进程以 root 身份运行,网络和存储池都在这一侧;qemu:///session是用户级实例,权限受限于当前用户,默认网络不可用,很多教程里说的“看不到 default 网络”就是连到了 session 上。生产环境一律用 system 实例,命令里显式写-c qemu:///system能省掉大量误判。
newgrp只是给当前 shell 换了个组上下文,如果用 IDE 或别的终端还是会话老旧,最稳妥的做法是注销重登。加组之后如果还是Permission denied,检查一下 polkit:某些发行版会在/etc/polkit-1/rules.d/里限制 libvirt 的访问,桌面环境下的 virt-manager 提示“无法连接”多半是这个原因,服务端场景直接确认用户组就够了。
socket和service两种单元同时 enable 会不会冲突?不会。socket 激活是懒启动,有连接进来才拉起 libvirtd,适合按需使用的开发机;常驻虚拟机的宿主机建议直接 enable service,避免第一次 virsh 调用等待一两秒。
3.3 libvirtd.conf 里值得改的四个参数
默认配置能跑,但有四个参数我在每台机器上都会确认一遍,它们直接决定日志够不够看、连不连得上、出了问题有没有线索。
# /etc/libvirt/libvirtd.conf # 允许访问 unix socket 的组,和 3.2 里的用户组保持一致 unix_sock_group = "libvirt" # socket 文件权限,0770 表示组内可读写 unix_sock_rw_perms = "0770" # 日志级别:1=debug 2=info 3=warning 4=error,排障期用 2 log_level = 2 # 日志落到独立文件,默认走 journald,混在系统日志里很难捞 log_outputs = "1:file:/var/log/libvirt/libvirtd.log" # 并发客户端上限,批量脚本容易被默认值卡住 max_clients = 500log_level = 2在排障期是必须的,它会把每次 virsh start 展开的 QEMU 命令行、网络配置、存储挂载都记下来。很多人查process exited while connecting to monitor查不出结果,就是因为日志停在 warning,看不到 QEMU 到底用什么参数启动、在哪一步退出的。
改完配置要systemctl restart libvirtd,并且确认/var/log/libvirt/目录存在且有写权限,否则日志会静默丢失——这个坑很隐蔽,表现出来就是“配了日志但文件是空的”。
3.4 默认 NAT 网络的初始化
libvirt 装完会定义一个叫default的网络,但不一定处于激活状态,也不一定开机自启。
# 查看所有网络,包括未激活的 virsh net-list --all # 激活并设为开机自启 virsh net-start default virsh net-autostart default # 看它到底长什么样:网段、DHCP 范围、转发模式 virsh net-dumpxml defaultnet-dumpxml的输出里重点看三处:<forward mode='nat'/>表示走 NAT 转发,虚拟机能出网但外面进不来;<ip address='192.168.122.1'/>是宿主机在这个网络里的网关地址;<dhcp><range .../></dhcp>是自动分配的地址池。如果 192.168.122.0/24 和你内网网段冲突,改这里或者干脆新建一个网络,别硬上。
默认网络起来之后宿主机上会多一个virbr0虚拟网桥,ip addr show virbr0能看到 192.168.122.1。看不到就说明网络没激活,虚拟机启动后会报“找不到 network default”,这个报错和磁盘、ISO 都没关系,纯粹是网络没起来。
4. 网络与存储配置:br0、NAT 和存储池怎么落地
到这一章,libvirt 已经能连上了,但虚拟机还是“能创建、不能用”的状态。虚拟化实施里真正花时间的部分在这里:网桥配错会把宿主机自己的 SSH 弄断,存储池配错会让磁盘性能只有几十兆,而这两种问题的表象都是“虚拟机卡”。先把网络做对,再把存储做对,最后才谈创建虚拟机。
4.1 桥接网络:把 IP 从物理网卡挪到 br0
桥接的目的是让虚拟机和宿主机处在同一个二层网络里,各自拿一个内网 IP,外部设备能直接访问。配置的关键只有一句话:IP 地址要配在网桥上,物理网卡只做桥的成员,不能自己留地址。
# /etc/netplan/01-netcfg.yaml(Ubuntu 系) network: version: 2 renderer: networkd ethernets: eno1: dhcp4: no # 物理口不配地址,只当桥的成员 dhcp6: no optional: true # 允许启动时该口未就绪,避免卡在等待 bridges: br0: interfaces: [eno1] addresses: [192.168.10.20/24] # IP 落在桥上 routes: - to: default via: 192.168.10.1 nameservers: addresses: [192.168.10.1] parameters: stp: false # 单口桥不需要生成树,开了会增加转发延迟 forward-delay: 0 # 单口桥无需监听学习期,设为 0 收敛更快这份配置里有三个点最容易写错。第一,eno1上的dhcp4必须是no,如果保留自动获取,系统会同时给物理口和桥配地址,路由表出现两条默认路由,表现是“时通时不通”。第二,addresses和routes都写在bridges下面,写到ethernets下面等于没桥接,虚拟机会被孤立在一个没有出口的网络里。第三,stp: false和forward-delay: 0是单网口桥的常规做法,如果宿主机真的接了两台交换机做冗余,这两个值要反过来。
应用配置时不要直接netplan apply,一旦远程改错就再也连不上。用netplan try,它会在应用后等 120 秒,期间不确认就自动回滚,这是配置网络时唯一有效的恢复手段。
# 先校验语法,再带超时应用 netplan generate netplan try --timeout 120 # 验收:桥上有 IP,物理口是 UP 但没有 IP ip addr show br0 ip addr show eno1 # 确认桥的成员口 bridge link showRHEL 系如果用的是 NetworkManager,对应的做法是nmcli con add type bridge ifname br0,再用nmcli con add type bridge-slave ifname eno1 master br0把物理口挂上去,最后nmcli con up br0。逻辑完全一致,只是命令形态不同,别两套混用——NetworkManager 和 networkd 同时管一块网卡是断网的经典原因。
4.2 NAT 与端口转发:没有独立 IP 时怎么让外面连进来
桥接需要额外的内网 IP,在只有一根网线、一个地址的环境里就得用 NAT。默认网络本身就是 NAT,虚拟机可以访问外网,但外部要访问虚拟机的 SSH 或 Web 服务,需要手工做端口转发。
# 1. 确认内核转发生效 sysctl -w net.ipv4.ip_forward=1 echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-virt.conf # 2. 把宿主机的 2222 端口转发到虚拟机的 22 端口 iptables -t nat -A PREROUTING -p tcp --dport 2222 \ -j DNAT --to-destination 192.168.122.10:22 # 3. 让内网段能正常回包 iptables -t nat -A POSTROUTING -s 192.168.122.0/24 -j MASQUERADE # 4. FORWARD 链默认策略如果是 DROP,需要放行 iptables -I FORWARD -i virbr0 -j ACCEPT iptables -I FORWARD -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT前两条是 NAT 转发的基础,第二条决定了外网进来的包能不能被改写目标地址。第三条容易漏,表现是“连上了但立刻断”,因为回包没有做源地址转换。第四条是很多发行版默认防火墙策略带来的坑,iptables -L FORWARD如果看到 DROP,虚拟机明明有网也 ping 不通外面。
这些规则默认重启即失效。用iptables-save或nft list ruleset导出后写到开机脚本里;systemd 环境更推荐用iptables-persistent或直接写 nft 规则文件,别把规则塞进/etc/rc.local,那个文件在很多发行版上已经不执行了。
虚拟机的 IP 建议在 libvirt 的 DHCP 里做静态绑定,否则重启后 IP 一变,转发规则就指向了别的机器:
<!-- virsh net-edit default 里加一段 host 绑定 --> <dhcp> <range start='192.168.122.100' end='192.168.122.200'/> <host mac='52:54:00:aa:bb:cc' name='test01' ip='192.168.122.10'/> </dhcp>把 DHCP 动态范围收窄到 100 以后,1 到 99 留给静态绑定的机器,两者不重叠,日后加机器不用改规则。改完virsh net-destroy default && virsh net-start default生效,注意这会短暂中断该网络内所有虚拟机的连接。
4.3 存储池与磁盘格式:qcow2、预分配和 cache 模式
默认存储池指向/var/lib/libvirt/images,在小根分区上很快会撑满。定义一个独立存储池只要四步,之后所有虚拟机磁盘都走数据盘。
# 定义一个目录型存储池,指向独立数据盘 virsh pool-define-as vmpool dir --target /data/vms # 建目录、启动、设开机自启 virsh pool-build vmpool virsh pool-start vmpool virsh pool-autostart vmpool # 验收 virsh pool-list --all virsh pool-info vmpool磁盘格式上,qcow2 支持快照、精简置备、压缩,代价是多一层地址映射,写性能比 raw 低一截;raw 性能好但不支持快照,预分配后占满空间。我一般的取舍是:需要快照和克隆的开发测试机用 qcow2,数据库这类对 IO 敏感的用 raw 加预分配。
# qcow2 建盘,preallocation=metadata 只预分配元数据,速度快且减少碎片 qemu-img create -f qcow2 \ -o preallocation=metadata \ /data/vms/test01.qcow2 40G # 查看实际占用与虚拟大小,两者不等是正常的精简置备 qemu-img info /data/vms/test01.qcow2 # raw 建盘并真正写满,适合数据库盘 qemu-img create -f raw -o preallocation=full /data/vms/data01.raw 200Gpreallocation=metadata的意义在于一次性把元数据块分配好,避免虚拟机跑起来之后边写边扩导致的卡顿,同时不会真的占掉 40G。preallocation=full会立刻写入实际空间,创建慢但运行期没有扩展开销。生产环境的数据库盘我倾向后者,创建时多等几分钟,换来的是稳定的写入延迟曲线。
cache 模式是另一个影响很大的参数:cache=none让 IO 直接落到宿主机页缓存之外的路径,是生产推荐值;cache=writeback性能数字好看,但宿主机异常断电时可能丢数据;cache=directsync最安全也最慢。没事别用默认值,刻意思考一次比事后怀疑磁盘有问题要省时间。
4.4 第一条 virt-install 命令的参数拆解
把前面几节的东西拼起来,就是一条完整的创建命令。下面这条我用了很久,参数是逐项验证过的。
virt-install \ --name test01 \ --memory 4096 \ --vcpus 4 \ --cpu host-passthrough \ # 透传宿主机 CPU 特性,性能最好 --machine q35 \ # 新的芯片组模型,支持 PCIe --disk path=/data/vms/test01.qcow2,format=qcow2,bus=virtio,cache=none \ --network bridge=br0,model=virtio \ --graphics vnc,listen=127.0.0.1 \ --cdrom /data/iso/system.iso \ --os-variant detect=on \ --noautoconsole--cpu host-passthrough让虚拟机看到和宿主机一致的 CPU 特性,是性能最优解,代价是这台虚拟机不能迁移到 CPU 型号不同的宿主机上;如果要做集群迁移,改成--cpu host-model。
--machine q35选的是较新的芯片组,支持 PCIe 设备和更大的内存映射,配套要用 UEFI 固件;老系统或需要兼容 32 位 guest 时再退回默认的 i440fx。
bus=virtio和model=virtio是性能关键,virtio 是半虚拟化驱动,吞吐比模拟的 IDE 和 e1000 高一个档次。但 Windows 系统装完默认没有 virtio 驱动,安装时会找不到磁盘,这时候要么挂载 virtio 驱动 ISO,要么临时把 bus 改成 sata 装完再切回来。
--os-variant detect=on让工具自己识别 ISO 类型来优化默认参数,比手写--os-variant generic准确。--noautoconsole表示不自动打开控制台,脚本化部署时必须有,否则命令会挂在控制台上不返回。
5. 实施避坑:五类排查记录,从现象倒推到原因
下面五条都是我在真实环境里遇到过的,写法统一成“看到什么现象、根因在哪、怎么解决”。虚拟化的问题有个共同点:报错信息基本都在日志里,但日志默认级别不够,看到的只是一句笼统的失败。所以排查顺序永远是先开日志、再看现场数据、最后动配置。
5.1 起不来的那一类:加速与 CPU 特性
现象:virt-install卡在Starting install...之后没有下文,virsh start报unsupported configuration: Domain requires KVM, but it is not available或KVM acceleration can not be used,虚拟机进程短暂出现又消失。
原因:两种可能。一是/dev/kvm不存在,通常是 BIOS 里 VT-x/AMD-V 没开,或者云主机上的嵌套虚拟化未启用;二是 libvirt 找不到可用的 KVM,比如在容器里跑 KVM 但没挂/dev/kvm设备。
解决:先跑egrep -c '(vmx|svm)' /proc/cpuinfo和ls -l /dev/kvm定位是哪一种。物理机回 BIOS 打开开关;模块没加载就modprobe kvm_intel(AMD 平台换成kvm_amd),并写进/etc/modules-load.d/;云主机上确认实例是否支持嵌套虚拟化,这个开关在实例规格或控制台层面,开机后软件层面改不了。容器里跑 KVM 必须把/dev/kvm以设备形式映射进去,权限也要对上。
5.2 连不上与配置丢失:权限、服务与自启动
现象:普通用户执行virsh list报Failed to connect to the hypervisor或authentication unavailable,加sudo就正常;或者宿主机重启后虚拟机全部消失,virsh list --all里状态是shut off。
原因:前者是用户没进 libvirt 组,或者连到了qemu:///session而不是qemu:///system;后者是 libvirtd 服务本身没设开机自启,或者虚拟机的 autostart 标记没打上——两者必须同时满足,只做一半的话重启依旧起不来。
解决:usermod -aG libvirt,kvm $USER之后必须重新登录,newgrp只对当前 shell 有效,IDE 里的终端要单独处理。命令里显式加-c qemu:///system防止连错实例。自启动用systemctl enable --now libvirtd加上virsh autostart test01,两个都做完后执行virsh list --autostart能看到这台机器才算配好。这个坑我踩过不止一次,后来干脆在装机脚本里加了这两行,属于必须留的预防措施。
5.3 网络与磁盘:通了但慢、断了不通
现象一:桥接配好后宿主机 SSH 立刻断开,重新登录不上,只能走带外控制台。原因是在 netplan 里把 IP 留在物理网卡上、又把它挂进了桥,或者直接用netplan apply应用了有语法错误的配置。解决办法是 IP 只配在 br0 上、物理口只做成员,应用一律用netplan try带超时回滚。已经断网的情况走控制台,把配置改回去再netplan apply。
现象二:虚拟机内部能 ping 通网关,但访问外网丢包,或者宿主机iptables -L FORWARD显示 DROP 策略。原因是默认网络用了 NAT,但都没有放行转发链;另外rp_filter严格模式也会在双网卡场景下丢包。解决是补上 FORWARD 的放行规则、确认net.ipv4.ip_forward=1,必要时把net.ipv4.conf.all.rp_filter调整为 2(宽松模式)。
现象三:虚拟机磁盘写入只有几十 MB/s,iostat看到%util不高但延迟很大。原因通常是磁盘总线用了 IDE 或 SATA、cache 用了默认的 writeback 叠加未预分配的 qcow2,导致每次写都要做一次元数据分配。解决是把总线换成 virtio-blk 或 virtio-scsi、cache 改成 none、建盘时加preallocation=metadata,改完在虚拟机里用fio做一次顺序写对比,能看到数量级的差别。这一条属于典型的“不对比就以为是磁盘坏了”。
6. 验收:通过六项检查才算完成上线
虚拟机启动成功、SSH 能登录,只能算“跑起来了”,离“能上线”还有距离。我习惯用下面这张表逐项过一遍,全部通过才算交付。
| 检查项 | 命令 | 通过标准 |
|---|---|---|
| 硬件加速 | ls -l /dev/kvm | 设备存在,属组为 kvm |
| 服务可用 | virsh -c qemu:///system nodeinfo | 返回 CPU 与内存信息,无报错 |
| 自启动 | virsh list --autostart | 目标虚拟机在列表里 |
| 网络类型 | virsh domiflist test01 | 显示bridge=br0或预期网络 |
| 磁盘总线 | virsh dumpxml test01 | grep target | 目标是 vda/vdb,不是 hda |
| 日志留存 | ls -l /var/log/libvirt/ | libvirtd.log 存在且有内容 |
前三项是“能不能用”,后三项是“坏了能不能查”。把这几条串起来跑,一条命令就能给出结论:
#!/usr/bin/env bash # 交付前自检脚本,任一项失败即退出 set -e # 1. 硬件加速必须可用,否则一切免谈 [ -e /dev/kvm ] || { echo "FAIL: /dev/kvm 缺失,检查 BIOS 或嵌套虚拟化"; exit 1; } # 2. libvirt 必须能以 system 实例连接 virsh -c qemu:///system nodeinfo >/dev/null || { echo "FAIL: libvirtd 不可用"; exit 1; } # 3. 目标虚拟机必须开机自启 virsh -c qemu:///system list --autostart --name | grep -qx "$1" \ || { echo "FAIL: $1 未设置 autostart"; exit 1; } # 4. 虚拟机网卡必须挂在预期网桥上 virsh -c qemu:///system domiflist "$1" | grep -q "$2" \ || { echo "FAIL: $1 未使用 $2 网络"; exit 1; } echo "OK: $1 通过基础验收"脚本里的$1是虚拟机名,$2是期望的网络或网桥名,把这两个参数化之后可以放进 CI 或者部署流水线里。set -e保证任何一条命令失败立刻中断,避免出现“一半通过还显示绿灯”的假象。
最后还有一个我坚持了很多年的习惯:每台新宿主机交付前,故意把宿主机重启一次,看着虚拟机自己起来、网络自己连上、静态 DHCP 绑定依然有效,才算真正验收完成。手动起一次不算数,能不能在无人值守的情况下自己恢复,才是虚拟化实施里最不容易翻车的地方。这个动作花十分钟,省下的是半夜被电话叫醒去virsh start的时间。希望帮到你。
本文还有配套的精品资源,点击获取