KVM虚拟机磁盘镜像修改指南(libguestfs:译+实践)

在维护kvm虚拟机时候,有时候需要修改vm内部文件系统内容,此时需要访问虚拟机磁盘镜像。

本文是对虚拟机镜像修改的一个实践,涉及NBDlibguestfs等开源工具。通过翻译加实践,了解KVM虚拟机磁盘resize的原理和实现,有助于我们理解虚拟化磁盘的底层原理。

RHEL/CentOS 5虚拟机镜像访问

有多种方式可以访问虚拟机磁盘镜像,在RHEL 常用的方法是使用kpartx工具,将虚拟机文件系统作为一个loop设备,这样就可以在物理服务器上访问。kpartx可以从分区表撞见磁盘设备映像,每个虚拟机存储映像有一个分区表和这个文件相关。

yum install kpartx

警告:在物理服务器上修改虚拟机磁盘,一定要在虚拟机offline状态下才可以操作。

RHEL/CentOS 6和7以后,请不要使用kpartx,改为使用guestfish工具

  • 使用kpartx列出分区设备映射到基于存储镜像的文件,以下案例使用的映像文件是guest1.img

kpartx -l /var/lib/libvirt/images/guest1.img

显示输出是

loop0p1 : 0 409600 /dev/loop0 63
loop0p2 : 0 10064717 /dev/loop0 409663

注意:在CentOS7上使用kpartx -l /var/lib/libvirt/images/centos6.img有可能无法工作,显示输出类似loop deleted : /dev/loop2而不是设备映像信息。

  • 添加分区映像到/dev/mapper/下设备

kpartx -a /var/lib/libvirt/images/guest1.img
  • 检查磁盘分区映射

ls /dev/mapper/

可以看到挂载的分区设备

  • 然后就可以使用目录来loop设备,如果需要则创建目录

  • 完成镜像的文件系统修改之后,可以去除分区映射的镜像文件连接:

RHEL/CentOS 6/7 虚拟机镜像访问

RHEL/CentOS 6提供的虚拟机镜像访问方法和 RHEL/CentOS 7是一致的,本文实践是在CentOS 7上完成

访问、修改和创建虚拟机磁盘或磁盘镜像的方式有:

  • 查看或下载位于虚拟机磁盘中的文件

  • 编辑或上传虚拟机磁盘中的文件

  • 读写虚拟机配置

  • 准备新磁盘镜像包含文件、目录、文件系统、分区、逻辑卷和其他

  • 紧急救援或修复guest虚拟机启动故障或其他需要修改启动配置

  • 监控虚拟机的磁盘使用

  • 审计guest虚拟机的符合组织安全标准情况

  • 通过克隆或修改模板来部署guest虚拟机

  • 读取CD/DVD ISO或软盘磁盘镜像

警告:**永远不要**在guest虚拟机运行或磁盘映像连接在运行虚拟机的时候使用工具写入虚拟机磁盘,甚至不要使用读模式打开这样的磁盘镜像。如果错误操作会导致guest虚拟机的磁盘损坏。工具会尝试阻止你这样误操作,然而有可能工具不能覆盖所有场景。

libguestfs和它的工具集文档可参考man手册。API是通过guestfs(3)文档提供。guestfish文档在guestfish(1),虚拟工具则在各自的man手册,例如virt-df(1)。有关troubleshooting,请参考libguestfs Troubleshooting

使用远程连接的注意点

一些RHEL 7的virt命令允许你远程访问libvirt连接,但是在RHEL 7上的libguestfs则不能访问远程libvirt guest的磁盘,并且并且类似使用远程URL的指令都不能工作,例如:

然而,从RHEL 7开始,libguestfs可以通过NBD访问远程磁盘源。也就是能够通过qemu-nbd命令访问远程主机磁盘,并通过nbd:// URL来访问磁盘。不过要注意远程服务器开启防火墙允许访问端口10809

具体操作案例如下(以下是实践经验,补充了原文档中缺少的一些细节(需要指定--format=raw的nbd磁盘格式),详细请参考使用libguestfs+NBD远程访问磁盘镜像

  • 远程系统启动nbd,此时qemu-nbd运行在前台,打开了服务等待客户端连接(不返回桌面)

  • 本地系统(可以在kvm虚拟机中安装libguestfs-tools工具包)先启动libvirtd

  • 本地系统执行如下命令

注意:一定要使用--format=raw - 虽然远程主机上centos6.img实际是qcow2格式,但是qemu-nbd是使用raw方式打开该文件的,所以参数是--format=raw,否则会报告磁盘格式不正确

此时就可以在本地系统看到远程输出的nbd磁盘的详细空间信息输出,例如:

此时就可以使用以下libguestfs命令:

libguestfs概念

  • libguestfs (GUEST FileSystem LIBrary) - 底层C库提供了基本点打开磁盘镜像,读取和写入文件等等基本功能。可以编写C程序来访问API

  • guestfish (GUEST Filesystem Interactive SHell - 交互的shell用于在命令行或者shell脚本使用。guestfish输出了libguestfs API所有的功能。

  • 许多virt工具都基于libguestfs,提供了执行特定单一任务的命令行方法。工具包括virt-dfvirt-rescuevirt-resizevirt-edit

  • augeas是用于编辑Linux配置文件的库,虽然这个库和libguestfs是相互独立的,但是很多libguestfs都结合了这个工具。

  • guestmount是一个结合libguestfsFUSE的接口,主要用于在物理服务器上挂载磁盘镜像的文件系统。这个功能不是必须的,但是非常有用。

安装libguestfs

安装libguestfs,guestfishlibguestfs工具,及guestmount:

要安装libguestfs相关软件包,包括语言绑定,使用如下命令:

guestfish SHELL

guestfish是命令行或者shell脚本中用于访问guest虚拟机文件系统的交互shell。这个shell提供了所有libguestfs API的功能。

以下案例以centos6.img为案例实践

要查看或编辑虚拟机磁盘镜像,输入如下命令:

这里--ro表示以只读方式打开磁盘镜像。这个模式总是安全的但是不允许写入操作。只有在确定guest虚拟机么有运行或磁盘镜像没有连接到运行中的guest虚拟机时才可以省略这个参数。绝不可以使用libguestfs来编辑运行中guest虚拟机,否则会导致不可逆转的虚拟磁盘损坏。

这里磁盘文件路径可以是一个文件,或者物理主机逻辑卷(例如/dev/VG/LV),物理主机设备(/dev/cdrom)或SAN LUN(/dev/sdf3)。

注意

libguestfsguestfish不需要root权限,只需要确保磁盘镜像具有读写权限即可。

上述交互模式启动guestfish会提示

在这个提示符下,输入run命令来初始化库以及连接磁盘镜像。首次运行可能会花费30秒钟时间,后续则完成快很多。

注意

libguestfs使用硬件虚拟化加速,例如KVM(如果有的话)来加速处理进程。

guestfish的提示符是><fs>,后续案例中,这个提示符请不要在命令行输入,只表示该行是输入的命令。

一旦run命令执行完成,其他命令就可以使用。

使用guestfish查看文件系统

手工列出和查看

list-filesystems将列出libguestfs找到的文件系统:

其他有用的命令是list-deviceslist-partitionslvspvsvfs-typefile。可以通过help COMMAND来查看详细的帮助:

要查看一个文件系统的实际内容,该文件系统必须被挂载。

可以使用guestfish命令如lsllcat

注意

guestfish中没有当前工作目录这个概念。和原始的shell不同,不能使用cd命令更改目录。所有路径必须是从顶部开始带有一个/字符的完全路径。可以使用TAB键来补完路径。

要退出guestfish ,可以输入exit或者Ctrl+d

通过guestfish检查(inspection)

除了手工列出和挂载文件系统,可以可以使用guestfish自身检查镜像和挂载文件系统,就像是在guest虚拟机内部操作一样。要实现检查,在命令行添加一个-i参数:

这里和没有-i参数的情况相比,多了以下提示:

此时磁盘镜像已经和guest虚拟机内部一样挂载好了文件系统,可以直接检查/就相当于检查guest虚拟机内部的/文件系统。

由于guestfish需要启动libguestfs后端来执行检查和挂载,所以当使用-i的时候不再需要执行run命令。这个-i参数可以用于大多数常用Linux guest虚拟机。

通过名字访问guest虚拟机

guest虚拟机可以通过指定和libvirt相同虚拟机名字的命令来访问(也就是通过virsh list --all查看的虚拟机名字)。使用-d参数来通过虚拟机名字访问磁盘设备,此时可以使用-i选项也可以不使用。

上述通过指定虚拟机名字方法访问虚拟机磁盘可以直接等同启动虚拟机访问磁盘文件系统。

使用guestfish添加文件

要使用guestfish添加一个文件,需要使用完整的URI。被访问的虚拟机磁盘文件必须是本地文件,或者是一个网络块设备(NBD)或者一个远程块设备(RBD)。

以下是一些URI例子,对于本地文件,使用///

使用guestfish修改文件

要针对一个guest虚拟机修改文件,创建目录或者其他修改,首先必须确保虚拟机是关闭状态的。使用guestfish编辑或修改运行中的磁盘将导致磁盘损坏。当确定了guest虚拟机已经关闭,则可以不使用--ro参数:

此时可以直接使用vi来编辑修改文件,例如

其他guestfish命令

和虚拟机中操作文件系统类似,可以直接格式化文件系统,创建分区,创建和调整LVM逻辑卷,使用名林类似 mkfspart-addlvresizelvcreatevgcreatepvcreate

在Shell脚本中使用guestfish

在熟悉了guestfish交互命令之后,可以按需将其加入shell脚本。一下是一个简单的在guest虚拟机增加新MOTD(message of the day):

Augeas 和 libguestfs 脚本

结合Augeas使用libguestfs可以方便编写操作Linux guest虚拟机配置的脚本。例如,以下脚本使用Augeas来准备guest虚拟机的键盘配置,并且打印输出键盘布局。注意,这个脚本只适合工作在运行Red Hat Enterprise Linux的虚拟机:

Augeas也可以用来修改配置文件,可以用来修改键盘布局:

注意上述连个脚本的3个修改之处:

  • --ro选项在第二个案例中去除,这样就可以写入guest虚拟机

  • aug-get命令被修改成aug-set来修改值而不是获取只。此时新的"gb"值写入。

  • aug-save命令将修改写入磁盘

以下案例创建磁盘镜像:

或者从磁盘镜像复制整个目录

其他命令

以下命令是简化等同于guestfish来查看和修改guest虚拟机磁盘镜像:

  • virt-cat是模拟guestfishdownload命令。该命令下载和显示一个简单的文件。例如:

  • virt-edit是模拟guestfishedit命令,用于和guest虚拟机的单个文件交互。例如,需要修改Linux虚拟机的grub.conf配置

virt-edit还有一个简单的非交互方式修改文件。也就是使用-e参数,例如,以下命令修改(去除)Linux guest虚拟机的root密码:

  • virt-ls是模拟guestfishls命令,ll以及find命令,用于递归显示目录。例如,以下命令将递归列出files和/home目录下目录:

virt-rescue: 救援shell

virt-rescue可以视为类似虚拟机的救援CD。它可以启动虚拟机进入救援shell,这样就可以修复虚拟机错误。

virt-rescueguestfish有部分功能充电。重要的区别是不同的使用方式,virt-rescue是交互方式,ad-hoc修改使用原始的Linux文件系统工具。virt-rescue不能脚本化,主要适用于在guest虚拟机故障时候修复。

运行virt-rescue

这里案例使用centos6

在针对guest虚拟机使用virt-rescue前,确保guest虚拟机没有运行,否则磁盘会发生损坏。在确定guest虚拟机没有运行后,可以输入如下命令:

这里centos6是libvirt识别的虚拟机的名字,作为举例

这里会看到系统启动了一个救援Linux系统,可以使用很多Linux工具,就像启动了一个救援CD一样。注意,这时的根目录是rescue系统,还需要手工挂载虚拟机磁盘到/sysroot目录下处理

可以使用df命令

可以使用fdisk命令显示磁盘

现在我们可以非常方便地将虚拟机磁盘挂载到/sysroot下,进行下一步排查

  • virt-rescure还支持很多命令选项,特别有用的是:

    • --ro - 只读模式操作虚拟机,这样就不会误修改虚拟机,特别是只做检查。当退出时,所有修改都会放弃。

    • --network - 激活rescue shell的网络访问,这样就可以下载或通过网络复制文件。

virt-df: 监视磁盘使用

virt-df命令特别适合在物理服务器上直接检查虚拟机内部的磁盘使用率,这样就不用ssh登录到虚拟机内部就可以检查磁盘使用情况。

-h 选项类似 df 命令的-h选项,表示human-readable模式,方便查看

也可以使用-i参数显示inode

显示输出类似

注意

使用virt-df命令对于运行中的虚拟机也是安全的,因为它是只读访问。不过,对于运行时的虚拟机执行virt-df每次看到的磁盘使用情况会轻微不同。

virt-df是设计用来集成监控工具的。允许系统管理员生成磁盘使用率的报告。并且支持CSV格式输出方便后续集成到程序中分析

virt-resize:离线改变guest虚拟机磁盘大小

virt-resize是一个扩展或收缩guest虚拟机磁盘的工具。这个工具只能在虚拟机offline(关闭)时使用。virt-resize工作时会复制guest虚拟磁盘镜像并保留原始镜像不修改。这样就可以将原始镜像作为备份,不过这样需要平衡占用两倍磁盘空间。

扩展磁盘镜像

这里案例使用centos6虚拟机完成

  • 首先通过virsh dumpxml centos6查看libvirt中guest虚拟机的磁盘位置

输出显示磁盘文件

可以看到磁盘文件是 /var/lib/libvirt/images/centos6.img

  • 检查虚拟磁盘使用情况:使用virt-df -hvirt-filesystems来检查虚拟机磁盘

输出显示

输出显示

扩展磁盘(raw格式)

第一次实践时,使用了truncate命令构建新的虚拟磁盘,则virt-resize之后虚拟机磁盘就不再是qcow2格式,相应还要修改centos6虚拟机定义(virsh edit centos6),否则无法进一步使用guestfish和启动个虚拟机。

第二次实践,改为使用qemu-img命令来扩展虚拟机磁盘镜像,这样新的虚拟磁盘镜像格式不变,依然是qcow2,就没有这个问题。见后文!

  • 先将源磁盘文件镜像重命令

  • 使用truncate命令构建一个新的虚拟磁盘(注意:这个磁盘镜像格式是raw)


  • 使用virt-reize从备份的源镜像centos6.img-old扩展成新镜像centos6.img

输出显示成功完成磁盘扩展(这里我们扩展了虚拟内部LVM卷的/dev/vg_centos6/lv_root)

  • 检查验证磁盘镜像

显示磁盘15G

注意:如果使用了truncate命令构建一个新的虚拟磁盘,会导致新的磁盘镜像是raw格式,就需要修订virsh edit centos6将磁盘类型修改成raw类似

否则会导致启动guestfish -d centos6再次尝试attach磁盘时候报错

再次检查虚拟磁盘是否扩容成15G

输出显示虚拟磁盘内部LVM卷已经扩展成15G

这里有个疑问sda1+sda2=15.5G,大于sda的15G?

实际启动虚拟机后验证,在虚拟机内部通过lvdisplay可以看到/dev/vg_centos6/lv_rootLV Size 13.51 GiB

使用virt-resize指令扩展虚拟机磁盘大小以及

注意

如果是LVM卷作为虚拟机的磁盘,则先创建一个大于现有LVM逻辑卷的LVM卷,然后通过virt-resize将原先的卷复制扩展到新的卷上实现虚拟机磁盘扩展,详细可参考RHEL手册[virt-resize: Resizing Guest Virtual Machines Offline](virt-resize: Resizing Guest Virtual Machines Offline),原理是相同的。

扩展磁盘(qcow2格式)

前述使用truncate命令构建一个新的虚拟磁盘后,导致virt-resize新的磁盘镜像是raw格式。现在改为保留原有qcow2格式再次做磁盘resize。使用命令qemu-img resize命令可以直接调整qcow2磁盘大小。

  • 先将源磁盘文件镜像备份/重命名(这里重新执行扩展操作,假设前一个扩展raw格式磁盘没有操作过,全新开始,所以这里centos6.img还是最初原始的qcow2磁盘),这个备份是要作为后续virt-resize的源数据盘的

  • 使用qemu-img创建一个新的空qcow2磁盘映像文件

输出显示

也可以先从centos6.img-origin复制一个centos6.img出来,然后再使用qemu-img resize调整大小。不过这个复制过程很缓慢。既然virt-resize就是从centos6.img-origin为基础resize到新的磁盘镜像,不如先创建一个空的qcow2磁盘镜像再使用virt-resize

  • 检查验证虚拟磁盘镜像

显示qcow2文件虚拟容量15G,实际目前是空的稀疏文件,所以只占用了196K空间

  • 检查centos6.img-origin磁盘分区,确定我们要扩展的分区(LVM卷)

输出显示

  • 使用virt-resizecentos6.img-origin为基础扩展到新的centos6.img磁盘文件

提示信息

  • 验证扩容后的centos6.img镜像:

验证和原始磁盘镜像centos6.img-origin一致。

virt-inspector: 诊断guest虚拟机

virt-inspector是一个诊断磁盘镜像检查使用的是哪种操作系统。该工具包含在libguestfs-tools软件包中。

运行virt-inspector

virt-inspector可以针对磁盘镜像或者虚拟机

report.xml内容类似

RHEL 7有一个xpath命令行工具(位于perl-XML-XPath.noarch软件包中)可以用来解读xml

输出显示

参考

Last updated

Was this helpful?