使用libguestfs修订KVM镜像

在云计算中,我们会把精心配置的虚拟机制作成模版,然后通过模版复制出大量的虚拟机来构建集群。但是,每个虚拟机内部有一些不得不一一定制的配置,需要有一个统一工具来完成修订。

kpartx工具

早期Red Hat Linux 5发行版都会提供一个 kpartx 工具,可以将虚拟机文件系统作为一个loop设备,这样就可以在物理服务器上访问。

警告

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

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

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

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

显示输出:

loop0p1 : 0 409600 /dev/loop0 63
loop0p2 : 0 10064717 /dev/loop0 409663
  • 添加分区映像到 /dev/mapper/ 下设备:

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

    ls /dev/mapper/
    

可以看到挂载的分区设备:

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

    mkdir /mnt/guest1
    mount /dev/mapper/loop0p1 /mnt/guest1 -o loop,rw
    
  • 完成镜像的文件系统修改之后,可以去除分区映射的镜像文件连接:

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

libguestfs工具

libguestfs 是现代Linux发行版提供的虚拟机镜像访问工具:

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

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

  • 读写虚拟机配置

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

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

  • 监控虚拟机的磁盘使用

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

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

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

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 的接口,主要用于在物理服务器上挂载磁盘镜像的文件系统。这个功能不是必须的,但是非常有用。

安装

Red Hat/CentOS

  • RedHat Linux 安装:

    sudo dnf install libguestfs libguestfs-tools libguestfs-winsupport
    
  • 要安装 libguestfs 相关软件包,包括语言绑定,使用如下命令:

    sudo dnf install "*guestf*"
    

Ubuntu/Debian

  • Debian系发行版安装:

    sudo apt install libguestfs-tools
    

使用

guestfish SHELL

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

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

    guestfish --ro -a /var/lib/libvirt/images/centos6.img
    

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

备注

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

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

Welcome to guestfish, the guest filesystem shell for
editing virtual machine filesystems and disk images.

Type: 'help' for help on commands
      'man' to read the manual
      'quit' to quit the shell

><fs>

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

备注

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

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

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

使用 guestfish 查看文件系统

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

    list-filesystems
    

显示:

/dev/sda1: ext4
/dev/vg_centos6/lv_root: ext4
/dev/vg_centos6/lv_swap: swap

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

><fs> list-devices
/dev/sda

><fs> list-partitions
/dev/sda1
/dev/sda2

><fs> lvs
/dev/vg_centos6/lv_root
/dev/vg_centos6/lv_swap

><fs> pvs
/dev/sda2

><fs> vfs-type /dev/sda1
ext4

><fs> vfs-type /dev/sda2
LVM2_member

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

可以使用 guestfish 命令如 lsllcat

备注

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

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

通过 guestfish 检查(inspection)

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

guestfish –ro -a /var/lib/libvirt/images/centos6.img -i

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

Operating system: CentOS release 6.9 (Final)
/dev/vg_centos6/lv_root mounted on /
/dev/sda1 mounted on /boot

><fs>

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

><fs> ll /
total 114
dr-xr-xr-x. 22 root root  4096 Apr 14 04:07 .
drwxr-xr-x  19 root root  4096 Apr 18 01:59 ..
-rw-r--r--.  1 root root     0 Apr 14 04:07 .autofsck
dr-xr-xr-x.  2 root root  4096 Apr 11 14:00 bin
dr-xr-xr-x.  5 root root  1024 Apr 11 12:59 boot
drwxr-xr-x.  2 root root  4096 Apr 11 12:54 dev
...

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

通过名字访问guest虚拟机

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

guestfish --ro -d centos6 -i

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

使用 guestfish 添加文件

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

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

guestfish -a disk.img
guestfish -a file:///directory/disk.img
guestfish -a nbd://example.com[:port]
guestfish -a nbd://example.com[:port]/exportname
guestfish -a nbd://?socket=/socket
guestfish -a nbd:///exportname?socket=/socket
guestfish -a rbd:///pool/disk
guestfish -a rbd://example.com[:port]/pool/disk

对于 Libvirt集成Ceph RBD ,可以直接使用 libvirt domain ,插入文件 (以下案例可参考,对于不同虚拟机都可以模仿使用)

guestfish --rw -i -d ceph-rbd-win08 -v -x upload /chost/guest/conf/ceph-fs/cloudvminit_full /cloudvminit.bat

使用 guestfish 修改文件

要针对一个guest虚拟机修改文件,创建目录或者其他修改,首先必须确保虚拟机是关闭状态的。

使用 guestfish 编辑或修改运行中的磁盘将导致磁盘损坏。当确定了guest虚拟机已经关闭,则可以不使用 --ro 参数:

guestfish -i -d centos6

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

备注

guestfish -d 会自动分析虚拟机的磁盘并运行一个微型内核虚拟机来挂载虚拟机磁盘,这对修改(修复)虚拟机磁盘问题非常有帮助,也是大规模clone虚拟机的必备手段。

我实践验证, guestfish -d 可以直接对 Libvirt集成Ceph RBD 虚拟机的 Ceph RBD 磁盘进行修订,所以在 Clone使用Ceph RBD的虚拟机 我编写了简单的脚本来处理虚拟机clone。

参考