我们用的虚拟机有时候用着用着就启动不起来了,可能是操作系统启动扇区出了问题或者硬盘数据损坏。如果还有重要的数据文件在虚拟机里面,不要慌,一般只是操作系统的问题,硬盘里面的文件一般是不会丢失损坏的,即使磁盘有损坏也是可以被修复的。
要拿回我们的重要数据,我们可以有两个种思路,一种是用一个新的操作系统,把旧的硬盘挂载到新的操作系统上,然后读取里面的数据。第二种思路是,其实都不用那么麻烦,虚拟硬盘本身就是一个文件,是不是有工具可以直接读取这个文件,然后把我们的文件提取出来。这两种想法都是正确的
就最近我遇到的虚拟硬盘数据恢复做一些总结,以后再遇到这样的问题就轻车熟路了。我遇到的问题其实很简单,就是用了好几年的centos7虚拟机启动不起来了,操作系统急救模式也进不去,切换内核也没有用,后来尝试了一些方法也无济于事,干脆就换个虚拟机好了。但是要紧的是用了那么多年,里面有很多重要的文件数据不能就没了。于是就打算自己恢复虚拟硬盘数据。
经验总结
首先给自己做了难么多尝试后总结一些经验,可能让很多对硬盘分区,文件系统不熟悉的读者遇到类似的问题时少走很多弯路。
(1)很多磁盘恢复、磁盘分区工具是可以直接读取虚拟机使用的虚拟磁盘文件(包括vdi,vmdk,vhd等格式的虚拟磁盘文件)的。比如windows下的diskgenius磁盘恢复工具,就可以直接打开这些虚拟磁盘文件,但是diskgenius并不支持所有的文件系统类型,比如Linux下常用的LVM文件系统类型,diakgenius就只能显示出虚拟磁盘文件里面的分区信息,无法读取分区里面的数据。
(2)vmware的虚拟磁盘映射功能,也和diskgenius一样,不支持LVM文件系统类型,只能识别出虚拟磁盘文件里面的分区信息,无法通过虚拟磁盘映射读取到分区里面的文件。
(3)如果虚拟磁盘文件使用的文件系统类型是ext4(一般是linux使用)、NTFS(一般是windows使用)这样的类型,可以直接使用diskgenius或者vmware的虚拟磁盘映射功能读取分区数据,然后就像访问本地文件夹那样,把需要的文件复制出来就可以了。
(4)由此看来,恢复磁盘数据的一个关键点是确定使用的文件系统类型,需要对症下药,并不是某个工具就能读取所有文件系统类型的数据。
(5)如果虚拟磁盘使用的文件系统是Linux LVM,就是我目前采用的方式:将虚拟磁盘文件挂载到一个新的虚拟机上然后做修复读取等操作
(6)virtualbox和vmware虚拟机本身就是可以挂载多块虚拟磁盘的,找到虚拟机-存储然后按步骤添加上另一块磁盘就可以了,虚拟机启动的时候就会给你挂载上去。刚开始的时候我还用共享文件夹的方式将windows下的vmdk文件共享给linux系统,其实没有这个必要。
Linux LVM简介
Linux LVM(Logical Volume Manager,逻辑卷管理)文件系统类型,有兴趣的可以自己去了解一下,这里只介绍几个要点:
(1)首先需要了解一下LVM中三个重要的名词
PV(physical volume):物理卷在逻辑卷管理系统最底层,可为整个物理硬盘或实际物理硬盘上的分区。它只是在物理分区中划出了一个特殊的区域,用于记载与LVM相关的管理参数。
VG(volume group):卷组建立在物理卷上,一卷组中至少要包括一物理卷,卷组建立后可动态的添加卷到卷组中,一个逻辑卷管理系统工程中可有多个卷组。
LV(logical volume):逻辑卷建立在卷组基础上,卷组中未分配空间可用于建立新的逻辑卷,逻辑卷建立后可以动态扩展和缩小空间。
(2)然后了解一下LVM的模型
LVM的模型如上图,首先是实际的物理磁盘及其划分的分区和其上的物理卷(PV)。一个或多个物理卷可以用来创建卷组(VG)。然后基于卷组可以创建逻辑卷(LV)。只要在卷组中有可用空间,就可以随心所欲的创建逻辑卷。文件系统就是在逻辑卷上创建的,然后可以在操作系统挂载和访问
(3)linux挂载的是逻辑卷(LV),而不是卷组(VG)和物理卷(PV)
我用的是virtualbox虚拟机,磁盘文件是vdi的文件,但是网上搜了一下,很多都是说用diskgenius恢复vmdk格式的虚拟磁盘文件,于是先尝试这条看似工作量不大的方式。
尝试一:用diskgenius读取vmdk格式文件
(1)好在virtualbox本身就能将vdi格式的文件转换成vmdk格式的文件,下面是转换命令
"C:\D-disk\software\virtualbox\VBoxManage.exe" clonehd "C:\Users\user1\VirtualBox VMs\vm\CentOS_64-bit-disk1.vdi" "C:\Users\user1\VirtualBox VMs\vm\CentOS_64-bit-disk1.vmdk" --format vmdk
VBoxManage.exe是virtualbox的安装路径下的一个工具,可以在自己电脑查找一下,记得所有完整的路径都要用双引号包围起来,有的路径如果包含空格命令识别会出错。格式转换其实很多工具都能做,包括vmware或者diskgenius都能做,看自己有哪些现成的工具就用哪种。
(2)下载diskgenius安装
从这里下载:DiskGenius – 正式版下载|免费下载
(3)用diskgenius打开vmdk虚拟磁盘文件
启动diskgenius,然后 点击 磁盘->打开虚拟磁盘文件 菜单项,选择vmdk后缀的虚拟磁盘文件打开。如果一切顺利,在diskgenius左侧栏就能看到你的磁盘分区和各个分区下的树形目录结构。就像下面的图片:
此时你只要找到你自己需要的文件,右键菜单复制出来就可以了
然而事情总不会如你想象般顺利。我打开后显示是这样的:
嗯,分区信息是有了,但是文件呢? 点击左侧的分区,也没见列出分区里面的文件呀。也没见有什么报错信息。于是就去各种尝试这个软件的使用,各种菜单按钮去尝试,无果。根据各种尝试和现象判断,像是没识别分区信息。文件系统类型未识别。看来此路可能不通,再做其他尝试,反正磁盘数据不会丢,总会找到解决办法。
虽然这个方法没解决问题,但是总不是没有收获,那就是让我看到了这个分区的文件系统类型,那就是Linux LVM
尝试二:用VMware 的虚拟磁盘映射功能
在安装了vmware的机器上,选中vmdk文件,右键菜单会有一个映射虚拟磁盘的选项,点击后如下所示:
映射后就能在 "此电脑"里面看到新映射的Z盘,如下图:
映射的z盘没有显示已用和可用大小,双击后会弹出格式化的提示。此时就不要继续下去了,否则你的数据就被格式化没了。看来这种方式也是此路不通。映射是成功的,但是为什么就是读不到里面的数据?此时我对“文件系统”的概念还不是很清晰,但是大概怀疑的方向还是倾向于文件格式的识别问题
然后就想这个虚拟磁盘文件原本是用在linux 上的,是不是要用Linux去挂载才能读取?于是开始尝试用linux挂载虚拟磁盘的方法
尝试三:linux挂载虚拟磁盘(vmdk格式文件)
在这一步尝试中也遇到了很多问题,因为不是很懂,都是一步一个坑试出来的。
刚开始是将windows上的vmdk文件通过网络共享的方式挂载到了虚拟机上,使得虚拟机能访问到这个vmdk文件,然后再通过比如loseup命令挂载到linux上,但是没成功,这个方法可能也是可行的,只是没时间研究。
通过网络共享的方式把vmdk文件挂载到linux操作步骤如下:
(1)首先把存放vmdk的windows文件夹设置成共享
(2)然后linux下执行下面的挂载命令:
mkdir /mnt/centos7
sudo mount -t cifs -o username=Administrator,password=xxxx,uid=1000,gid=1000 //192.168.58.1/centos7 /mnt/centos7/
其中 //192.168.58.1/centos7是windows共享文件夹的路径,/mnt/centos7/是linux下的挂载点
如果挂载成功,执行 ll /mnt/centos7 命令就能看到目录里面的内容
网络共享这个是题外话,我实际用的是直接在虚拟机软件上给新的虚拟机增加那块旧的磁盘的方式。虚拟机其实就像我们真实的电脑,电脑是可以装多块硬盘的,比如我们有的电脑就有机械硬盘和固态硬盘一起用的。但是要指定好操作系统所在的硬盘和分区,否则系统会启动失败。实际上如果操作系统起不来,如果操作系统和其他数据分区分开的话,是不会影响其他分区的数据的,你只要把硬盘挂载到其他系统,然后去读取其他分区的数据就可以了。按这个思路,好像现在用固态硬盘的电脑也有必要分多个区,把操作系统分区和数据分区分开,避免操作系统挂了之后我们的数据也无法读取?这个有时间可以研究一下,很多时候数据恢复还是很有必要的。
vmware上给虚拟机添加新硬盘
在想要添加硬盘的虚拟机上右键->设置->硬件 然后右下角点击添加,选硬盘
磁盘类型应该可以随便选,然后点击下一步
虚拟磁盘就选你需要添加的vmdk或者vdi或者vhd文件。点击确定后可能需要你转换格式,选择保持现有格式就行了。
virtualbox一样可以添加多块虚拟磁盘,可以自行尝试,这里就不赘述了。
挂载上虚拟磁盘后,就可以启动虚拟机,然后查看挂载的情况。我们把虚拟磁盘通过以上方式添加到linux上之后,其实还没完成任务,系统启动之后我们还是看不到新添加的磁盘的数据,需要进一步做挂载。
linux上挂载LVM文件系统的磁盘
添加上新的虚拟硬盘,系统启动后,就可以按以下步骤来进行分区挂载和磁盘修复。
1、使用fdisk -l查看硬盘信息
[root@localhost mnt]# fdisk -l
磁盘 /dev/sda:8589 MB, 8589934592 字节,16777216 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0x000aeedd
设备 Boot Start End Blocks Id System
/dev/sda1 * 2048 2099199 1048576 83 Linux
/dev/sda2 2099200 16777215 7339008 8e Linux LVM
磁盘 /dev/sdb:107.4 GB, 107374182400 字节,209715200 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0x0001d0d4
设备 Boot Start End Blocks Id System
/dev/sdb1 * 2048 2099199 1048576 83 Linux
/dev/sdb2 2099200 10485759 4193280 8e Linux LVM
/dev/sdb3 10485760 20971519 5242880 8e Linux LVM
/dev/sdb4 20971520 209715199 94371840 8e Linux LVM
磁盘 /dev/mapper/centos-root:6652 MB, 6652166144 字节,12992512 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘 /dev/mapper/centos-swap:859 MB, 859832320 字节,1679360 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘 /dev/mapper/cl-swap:536 MB, 536870912 字节,1048576 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘 /dev/mapper/cl-root:105.8 GB, 105750986752 字节,206544896 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
注意看/dev/sdb是我们新加的磁盘,/dev/sda是原来的磁盘
2、vgscan 查看可用的卷组
[root@localhost mnt]# vgscan
Reading volume groups from cache.
Found volume group "centos" using metadata type lvm2
Found volume group "cl" using metadata type lvm2
以上就是有cl和centos两个卷组。cl就是我新加的磁盘的里面的卷组名。这里有一个需要避的坑是避免原磁盘的卷组名称和新添加的磁盘的卷组名称不能一样,否则会冲突,导致你新添加的磁盘的逻辑卷无法挂载。如果真的冲突了,可以参考这篇文章给卷组重命名:如何挂载另一个lvm硬盘 - Jessica程序猿 - 博客园 (cnblogs.com)
但是这个难度会高一些,有更便捷的做法是可以装不同发行版的虚拟机,去挂载这个新磁盘,这样基本避免卷组名冲突的问题。
3、lvscan 查找可用的逻辑卷
最终我们只是挂载逻辑卷,不是卷组
[root@localhost mnt]# lvscan
ACTIVE '/dev/centos/swap' [820.00 MiB] inherit
ACTIVE '/dev/centos/root' [<6.20 GiB] inherit
ACTIVE '/dev/cl/swap' [512.00 MiB] inherit
ACTIVE '/dev/cl/root' [<98.49 GiB] inherit
如上可以看到,cl和centos两个卷组的逻辑卷都已经激活,如果没有差错,就可以直接挂载,/dev/cl/root就是我新加磁盘里面的逻辑卷
如果以后有没有激活的逻辑卷,需要用命令:vgchange -ay 激活逻辑卷,激活后再lvscan查看一下
4、尝试挂载逻辑卷
mkdir /mnt/cl-root
mount /dev/cl/root /mnt/cl-root
如果报错:
[root@localhost mnt]# mount /dev/cl/root /mnt/cl-root
mount: /dev/mapper/cl-root:不能读超级块
或者挂载后还是无法读取数据
说明磁盘有损坏了,需要执行修复
5、修复磁盘(确保在执行修复前,逻辑卷是未被挂载状态)
如果刚才挂载成功了没有读取到数据,需要执行:umount /dev/mapper/cl-root
然后尝试修复
尝试一:
fsck /dev/mapper/cl-root
报错:
[root@localhost mnt]# fsck /dev/mapper/cl-root
fsck,来自 util-linux 2.23.2
If you wish to check the consistency of an XFS filesystem or
repair a damaged filesystem, see xfs_repair(8).
由于我的文件系统是 XFS 类型,fsck 工具并不适用于 XFS 文件系统。需要使用 xfs_repair 工具来检查和修复 XFS 文件系统
尝试二:
xfs_repair /dev/mapper/cl-root
还是无法修复,但是提示可以用-L参数强制修复,这会清除日志,但可能会导致数据丢失。于是再次尝试:
xfs_repair -L /dev/mapper/cl-root
这次修复成功!
然后再次尝试挂载:
mount /dev/cl/root /mnt/cl-root
挂载成功,进入cd /mnt/cl-root目录,可以看到目录及文件都显示出来了,至此数据恢复完成
这里细心的读者可能发现,我挂载的逻辑卷是/dev/cl/root,但是报错的时候显示的是/dev/mapper/cl-root,这两个是同一个卷吗?答案是肯定的,问了copilot是如下的回答:
这是一个很好的问题!在 LVM 中,逻辑卷的路径可以有多个表示方式:
/dev/VolumeGroup/LogicalVolume: 这是逻辑卷的标准路径格式。例如,/dev/cl/root。
/dev/mapper/VolumeGroup-LogicalVolume: 这是逻辑卷的设备映射路径格式。例如,/dev/mapper/cl-root。
这两种路径实际上指向同一个逻辑卷设备。/dev/mapper 路径是由设备映射器(Device Mapper)创建的,它提供了对逻辑卷的访问。你可以使用任意一种路径来挂载逻辑卷,效果是一样的。
所以,当你看到 /dev/cl/root 和 /dev/mapper/cl-root 时,不用担心,它们都是指向同一个逻辑卷的不同表示方式