KVM虚拟机突然打不开,数据不会因此消失,绝大多数情况下都能恢复,关键在于先别慌,按正确顺序排查,千万别乱动磁盘镜像文件。
很多人在KVM宿主机上跑着业务,突然发现虚拟机启动不了,第一反应是数据全没了,其实这个担心是多余的,KVM虚拟机的数据存储在磁盘镜像文件里(默认是qcow2或raw格式),就像一块硬盘被封装成一个文件,只要这个文件没被覆盖或损坏,里面的数据就一直在,真正要做的是搞清楚虚拟机是系统层坏了,还是宿主机层面出了问题。
KVM虚拟机无法启动怎么办?先判断是真故障还是假死
用virsh命令看虚拟机当前状态
登录到宿主机上,打开终端执行:
virsh list --all
这个命令会把宿主机上所有虚拟机列出来,包括正在运行的和关闭的,如果虚拟机在列表里显示为running,但是用户连不上、控制台黑屏,那是系统内部的问题;如果显示shut off,那是虚拟机没有运行,需要手动启动。
virsh start 虚拟机名称
如果执行完提示error: Failed to start domain,说明启动失败,这时候要看具体的报错信息,常见的报错有:
- cannot access storage file:磁盘镜像文件路径不对,或者文件被移动、删除了
- No boot device is available:虚拟机引导配置损坏,找不到启动盘
- internal error: process exited while connecting to monitor:QEMU进程崩溃,可能是资源冲突或配置错误
看宿主机资源是不是被掏空了
KVM虚拟机本质上是宿主机上的几个进程,宿主机内存耗尽、磁盘写满、CPU负载过高,都会导致虚拟机直接卡死或自动关闭,执行下面这几个命令快速确认:
free -h # 看内存和swap用量 df -h # 看磁盘空间是否满了 ps aux --sort=-%cpu | head -10 # 看CPU占用最高的进程
行业共识认为,宿主机内存长期跑在90%以上,会让KVM虚拟机内核触发OOM Killer,直接把占用内存最大的虚拟机进程杀掉,如果是这种情况,清理掉一些无用进程释放内存,再执行virsh start成功率很高。
KVM虚拟机数据恢复:镜像文件完好就有救
先确认磁盘镜像文件还在不在
大多数情况下,虚拟机“挂了”并不代表数据没了,KVM虚拟机的“硬盘”就是一个文件,在宿主机上找一下它的存放位置:
virsh dumpxml 虚拟机名称 | grep source
这会输出一行类似<source file='/var/lib/libvirt/images/xxx.qcow2'/>,能看到镜像文件的绝对路径,然后确认文件是否存在、大小是否正常:
ls -lh /var/lib/libvirt/images/xxx.qcow2 qemu-img info /var/lib/libvirt/images/xxx.qcow2
如果文件还在,而且大小和崩溃前差不多,数据恢复的成功率相当高,注意:这一步先别急着找专业数据恢复公司,很多情况自己能处理好,花钱是小,等待时间才是大问题。
尝试直接重新启动虚拟机
先做一次干净的重启,很多时候系统内核崩溃只是临时的:
virsh destroy 虚拟机名称 # 强制关闭,相当于断电 virsh start 虚拟机名称 # 重新上电
如果启动卡住不动,或者启动后又自动退出,看下QEMU的错误日志:
tail -n 100 /var/log/libvirt/qemu/虚拟机名称.log
日志里通常会直接写明启动失败的原因,比如磁盘镜像格式错误、快照文件找不到、内存配置超了宿主机上限等,根据报错去修改配置,用virsh edit 虚拟机名称打开配置文件修正后再启动。
用qemu-img工具检查磁盘完整性
镜像文件本身有可能因为宿主机异常断电而损坏,尤其是raw格式的镜像更容易出问题,qcow2格式因为有写时拷贝机制,理论上比raw更抗断电损坏。
qemu-img check /var/lib/libvirt/images/xxx.qcow2
输出结果里有Leaked clusters和Corruptions两个关键指标,如果Corruptions显示为0,说明镜像结构完好,不用担心;如果显示有损坏块,也别灰心,Linux下可以尝试修复:
qemu-img check -r all /var/lib/libvirt/images/xxx.qcow2
这个命令会尝试自动修复镜像内部的损坏结构。修复前务必备份原文件,防止二次损伤,拷贝一下镜像文件再操作,成本很低,但能规避最坏的情况。
KVM虚拟机打不开但数据要拷出来?用挂载方式救数据
离线挂载qcow2镜像法
虚拟机系统无论如何都启动不了,但你就想拿到里面的数据库文件、网站源码或者配置文件,离线挂载是最高效的路径,宿主机上安装
libguestfs-tools:
sudo apt install libguestfs-tools # Debian/Ubuntu系 sudo yum install libguestfs-tools # CentOS/RHEL系
然后一条命令把虚拟机磁盘挂载为宿主机的目录:
guestmount -a /var/lib/libvirt/images/xxx.qcow2 -i /mnt/vmdata
/mnt/vmdata就相当于虚拟机的C盘(根分区),直接用cp命令拷贝数据出来,拷贝完执行guestunmount /mnt/vmdata安全卸载,这种方式不需要虚拟机启动,不需要知道登录密码,直接像访问普通文件夹一样把数据搬出来,在行业内的虚拟机数据恢复场景中应用相当广泛。
单用户模式修复启动配置
如果镜像挂载成功,数据拷出来了,你还想让虚拟机复活,可以用挂载进去改配置的方式修复启动问题,比如虚拟机的fstab里挂载了一个不存在的分区,导致系统启动卡死,挂载后编辑该文件把坏条目删掉就行。
chroot /mnt/vmdata # 把/mnt/vmdata当作根目录 vi /etc/fstab # 删除或注释掉有问题的挂载项 exit # 退出chroot guestunmount /mnt/vmdata
再回到宿主机执行virsh start,大概率能正常启动,这个方法能处理相当一部分KVM虚拟机断电后无法启动的情况,不需要重装系统,数据也不会丢。
KVM虚拟机突然死机后的操作顺序很重要
牢记“先只读后写入”的原则
当KVM虚拟机挂了,宿主机上最容易做错的动作是:反复强制启动、重新创建虚拟机并挂载原磁盘、对镜像文件执行格式化,尤其是重新创建虚拟机挂载原镜像,会写新的引导信息到磁盘前部,可能覆盖原有数据。
操作顺序建议:
- 先用
qemu-img info查看镜像文件元数据,确认格式和大小 - 用
qemu-img check检查镜像完整性,只读操作,不改动文件 - 有坏块时备份原文件,再执行修复命令
- 修复无效时,用
guestmount以只读方式挂载导出数据 - 最后再考虑重装虚拟机系统,把旧磁盘作为第二块硬盘挂上去访问
宿主机本身被踢挂的情况
还有一种场景是整个宿主机物理机宕了,不是KVM虚拟机挂了,这事情更大,开机后如果宿主机系统正常,但libvirtd服务起不来,手动启动:
systemctl start libvirtd
virsh在物理机重启后如果不能自动恢复所有虚拟机,可以开启自动启动:
virsh autostart 虚拟机名称
这样宿主机每次开机时都会自动拉起这台虚拟机,不过不建议所有业务虚拟机都设置成自动启动,同时拉起太多虚拟机可能把宿主机内存打爆,反而造成二次雪崩。
怎么避免KVM虚拟机频繁掉线
虚拟机内部优化
不少KVM虚拟机卡死是因为内核没有安装virtio驱动,或者版本不匹配导致磁盘I/O陷入长时间等待,安装完整版qemu-guest-agent,可以让宿主机和虚拟机之间建立心跳通信,主机侧能识别出虚拟机是否无响应,减少误判。
宿主机例行检查
定期检查宿主机磁盘剩余空间尤其重要,当宿主机根分区剩余空间低于10%时,虚拟机在写入数据的过程中会突然卡死,这是实践中发生率较高的故障原因,给宿主机做一个磁盘空间监控脚本:
#!/bin/bash
if [ $(df / | awk '{print $5}' | sed -n '2p' | tr -d '%') -gt 85 ]; then
echo "宿主机磁盘空间不足!" | mail -s "KVM宿主机告警" admin@example.com
fi
通过crontab定时执行,防患于未然。
常见问题快速解答
KVM虚拟机挂了和宿主机挂了是一回事吗?
不是,虚拟机挂了通常指guest OS崩溃或QEMU进程异常退出,宿主机本身还能正常SSH登录;宿主机挂了是物理层面宕机,所有虚拟机都会同时不可用,排查时先确认宿主机能否登录,再逐层往下查。
KVM虚拟机磁盘镜像损坏后必须重新搭建系统吗?
不必,优先通过qemu-img check -r all修复镜像结构,然后离线挂载导出数据,绝大多数场景即使驱动不了原系统,数据文件依然完好,copy出来放到新的虚拟机上直接用即可。
KVM虚拟机里跑了数据库,数据恢复难度大吗?
数据库类的恢复难度相对大,因为数据文件始终处于写入状态,断电瞬间可能造成表空间不一致或事务日志中断,这种情况下先备份整个镜像文件,再离线挂载,优先从binlog或WAL日志中提取最近的数据变更,据业内专家指出,日志文件是数据库故障恢复的第一数据源,比扫描数据文件更可靠、更完整,只要日志文件在,数据基本都能找回。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/643184.html





