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/

可以看到挂载的分区设备

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

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

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

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的指令都不能工作,例如:

virt-df -c qemu://remote/system -d Guest

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

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

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

qemu-nbd -t /var/lib/libvirt/images/centos6.img
  • 本地系统(可以在kvm虚拟机中安装libguestfs-tools工具包)先启动libvirtd

systemctl start libvirtd
  • 本地系统执行如下命令

virt-df --format=raw -a nbd://192.168.122.1

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

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

192.168.122.1:/dev/vg_centos6/lv_root
                                       8649736    2475860    5711440   29%

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

guestfish
guestmount
virt-alignment-scan
virt-cat
virt-copy-in
virt-copy-out
virt-df
virt-edit
virt-filesystems
virt-inspector
virt-ls
virt-rescue
virt-sysprep
virt-tar-in
virt-tar-out
virt-win-reg

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:

yum install libguestfs libguestfs-tools libguestfs-winsupport

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

yum install "*guestf*"

guestfish SHELL

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

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

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

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

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

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

注意

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找到的文件系统:

><fs> 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)。

以下是一些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 

使用guestfish修改文件

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

guestfish -d centos6 -i

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

><fs> ls /boot/grub/menu.lst

其他guestfish命令

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

在Shell脚本中使用guestfish

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

#!/bin/bash -
set -e
guestname="$1"

guestfish -d "$guestname" -i <<'EOF'
  write /etc/motd "Welcome to Acme Incorporated."
  chmod 0644 /etc/motd
EOF

Augeas 和 libguestfs 脚本

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

#!/bin/bash -
 set -e
 guestname="$1"

 guestfish -d "$1" -i --ro <<'EOF'
   aug-init / 0
   aug-get /files/etc/sysconfig/keyboard/LAYOUT
 EOF

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

#!/bin/bash -
 set -e
 guestname="$1"

 guestfish -d "$1" -i <<'EOF'
   aug-init / 0
   aug-set /files/etc/sysconfig/keyboard/LAYOUT '"gb"'
   aug-save
 EOF

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

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

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

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

以下案例创建磁盘镜像:

guestfish -N fs

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

><fs> copy-out /home /tmp/home

其他命令

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

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

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

virt-edit LinuxGuest /boot/grub/grub.conf

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

virt-edit LinuxGuest /etc/passwd -e 's/^root:.*?:/root::/'
  • virt-ls是模拟guestfishls命令,ll以及find命令,用于递归显示目录。例如,以下命令将递归列出files和/home目录下目录:

virt-ls -R LinuxGuest /home/ | less

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虚拟机没有运行后,可以输入如下命令:

virt-rescue -d centos6

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

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

virt-rescue: warning: virt-rescue doesn't work with the libvirt backend
at the moment.  As a workaround, forcing backend = 'direct'.
supermin: mounting /proc
supermin: ext2 mini initrd starting up: 5.1.16 glibc
Starting /init script ...
starting version 219
specified group 'input' unknown
[    0.796109] intel_rapl: no valid rapl domains found in package 0
Cannot find device "eth0"
Cannot find device "eth0"
RTNETLINK answers: Network is unreachable
mdadm: No arrays found in config file or automatically
  WARNING: Failed to connect to lvmetad. Falling back to device scanning.
  2 logical volume(s) in volume group "vg_centos6" now active
/init: line 136: ldmtool: command not found

------------------------------------------------------------

Welcome to virt-rescue, the libguestfs rescue shell.

Note: The contents of / are the rescue appliance.
You have to mount the guest's partitions under /sysroot
before you can examine them.

><rescue>

可以使用df命令

><rescue> df -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs            96M  116K   96M   1% /run
/dev            236M     0  236M   0% /dev

可以使用fdisk命令显示磁盘

><rescue> fdisk -l

Disk /dev/sda: 10.7 GB, 10737418240 bytes, 20971520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x0007a2ab

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048     1026047      512000   83  Linux
/dev/sda2         1026048    20971519     9972736   8e  Linux LVM

Disk /dev/sdb: 4294 MB, 4294967296 bytes, 8388608 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mapper/vg_centos6-lv_root: 9135 MB, 9135194112 bytes, 17842176 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/mapper/vg_centos6-lv_swap: 1073 MB, 1073741824 bytes, 2097152 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

><rescue>

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

><rescue> mount /dev/mapper/vg_centos6-lv_root /sysroot/

><rescue> df -h
Filesystem                      Size  Used Avail Use% Mounted on
tmpfs                            96M  116K   96M   1% /run
/dev                            236M     0  236M   0% /dev
/dev/mapper/vg_centos6-lv_root  8.3G  2.4G  5.5G  31% /sysroot
  • virt-rescure还支持很多命令选项,特别有用的是:

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

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

virt-df: 监视磁盘使用

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

virt-df -h -a /var/lib/libvirt/images/centos6.img

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

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

显示输出类似

Filesystem                                Size       Used  Available  Use%
centos6.img:/dev/sda1                     476M        39M       408M    9%
centos6.img:/dev/vg_centos6/lv_root       8.2G       2.4G       5.4G   29%

注意

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

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

virt-df --csv -d centos6

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

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

扩展磁盘镜像

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

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

virsh dumpxml centos6

输出显示磁盘文件

    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/var/lib/libvirt/images/centos6.img'/>
      <target dev='hda' bus='ide'/>
      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
    </disk>

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

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

virt-df -h -a /var/lib/libvirt/images/centos6.img

输出显示

Filesystem                                Size       Used  Available  Use%
centos6.img:/dev/sda1                     476M        39M       408M    9%
centos6.img:/dev/vg_centos6/lv_root       8.2G       2.4G       5.4G   29%
virt-filesystems -a /var/lib/libvirt/images/centos6.img --all --long -h

输出显示

Name                    Type       VFS  Label MBR Size Parent
/dev/sda1               filesystem ext4 -     -   500M -
/dev/vg_centos6/lv_root filesystem ext4 -     -   8.5G -
/dev/vg_centos6/lv_swap filesystem swap -     -   1.0G -
/dev/vg_centos6/lv_root lv         -    -     -   8.5G /dev/vg_centos6
/dev/vg_centos6/lv_swap lv         -    -     -   1.0G /dev/vg_centos6
/dev/vg_centos6         vg         -    -     -   9.5G /dev/sda2
/dev/sda2               pv         -    -     -   9.5G -
/dev/sda1               partition  -    -     83  500M /dev/sda
/dev/sda2               partition  -    -     8e  9.5G /dev/sda
/dev/sda                device     -    -     -   10G  -

扩展磁盘(raw格式)

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

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

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

mv /var/lib/libvirt/images/centos6.img /var/lib/libvirt/images/centos6.img-origin
  • 使用truncate命令构建一个新的虚拟磁盘(注意:这个磁盘镜像格式是raw)


truncate -s 15G /var/lib/libvirt/images/centos6.img
  • 使用virt-reize从备份的源镜像centos6.img-old扩展成新镜像centos6.img

virt-resize /var/lib/libvirt/images/centos6.img-origin /var/lib/libvirt/images/centos6.img --expand /dev/sda2 --LV-expand /dev/vg_centos6/lv_root

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

[   0.0] Examining /var/lib/libvirt/images/centos6.img-old
**********

Summary of changes:

/dev/sda1: This partition will be left alone.

/dev/sda2: This partition will be resized from 9.5G to 14.5G.  The LVM PV
on /dev/sda2 will be expanded using the 'pvresize' method.

/dev/vg_centos6/lv_root: This logical volume will be expanded to maximum
size.  The filesystem ext4 on /dev/vg_centos6/lv_root will be expanded
using the 'resize2fs' method.

**********
[   3.0] Setting up initial partition table on /var/lib/libvirt/images/centos6.img
[   3.3] Copying /dev/sda1
 100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ 00:00
[   8.6] Copying /dev/sda2
 100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ 00:00
[  55.6] Expanding /dev/sda2 using the 'pvresize' method
[  55.6] Expanding /dev/vg_centos6/lv_root using the 'resize2fs' method

Resize operation completed with no errors.  Before deleting the old disk,
carefully check that the resized disk boots and works correctly.
  • 检查验证磁盘镜像

qemu-img info /var/lib/libvirt/images/centos6.img

显示磁盘15G

image: /var/lib/libvirt/images/centos6.img
file format: raw
virtual size: 15G (16106127360 bytes)
disk size: 2.5G

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

    <disk type='file' device='disk'>
      <driver name='qemu' type='raw'/>
      <source file='/var/lib/libvirt/images/centos6.img'/>
      <target dev='hda' bus='ide'/>
      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
    </disk>

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

libguestfs: error: could not create appliance through libvirt.

Try running qemu directly without libvirt using this environment variable:
export LIBGUESTFS_BACKEND=direct

Original error from libvirt: internal error: process exited while connecting to monitor: 2017-04-19T08:07:53.468712Z qemu-kvm: -drive file=/var/lib/libvirt/images/centos6.img,format=qcow2,if=none,id=drive-scsi0-0-0-0,cache=writeback: could not open disk image /var/lib/libvirt/images/centos6.img: Image is not in qcow2 format [code=1 int1=-1]

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

virt-filesystems -a /var/lib/libvirt/images/centos6.img --all --long -h

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

Name                    Type       VFS  Label MBR Size Parent
/dev/sda1               filesystem ext4 -     -   500M -
/dev/vg_centos6/lv_root filesystem ext4 -     -   14G  -
/dev/vg_centos6/lv_swap filesystem swap -     -   1.0G -
/dev/vg_centos6/lv_root lv         -    -     -   14G  /dev/vg_centos6
/dev/vg_centos6/lv_swap lv         -    -     -   1.0G /dev/vg_centos6
/dev/vg_centos6         vg         -    -     -   15G  /dev/sda2
/dev/sda2               pv         -    -     -   15G  -
/dev/sda1               partition  -    -     83  500M /dev/sda
/dev/sda2               partition  -    -     8e  15G  /dev/sda
/dev/sda                device     -    -     -   15G  -

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

dev/sda1               partition  -    -     83  500M /dev/sda
/dev/sda2               partition  -    -     8e  15G  /dev/sda
/dev/sda                device     -    -     -   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的源数据盘的

mv /var/lib/libvirt/images/centos6.img /var/lib/libvirt/images/centos6.img-origin
  • 使用qemu-img创建一个新的空qcow2磁盘映像文件

qemu-img create -f qcow2 /var/lib/libvirt/images/centos6.img 15G

输出显示

Formatting '/var/lib/libvirt/images/centos6.img', fmt=qcow2 size=16106127360 encryption=off cluster_size=65536 lazy_refcounts=off

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

  • 检查验证虚拟磁盘镜像

qemu-img info /var/lib/libvirt/images/centos6.img

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

image: /var/lib/libvirt/images/centos6.img
file format: qcow2
virtual size: 15G (16106127360 bytes)
disk size: 196K
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: false
  • 检查centos6.img-origin磁盘分区,确定我们要扩展的分区(LVM卷)

virt-filesystems -a /var/lib/libvirt/images/centos6.img-origin --all --long -h

输出显示

Name                    Type       VFS  Label MBR Size Parent
/dev/sda1               filesystem ext4 -     -   500M -
/dev/vg_centos6/lv_root filesystem ext4 -     -   8.5G -
/dev/vg_centos6/lv_swap filesystem swap -     -   1.0G -
/dev/vg_centos6/lv_root lv         -    -     -   8.5G /dev/vg_centos6
/dev/vg_centos6/lv_swap lv         -    -     -   1.0G /dev/vg_centos6
/dev/vg_centos6         vg         -    -     -   9.5G /dev/sda2
/dev/sda2               pv         -    -     -   9.5G -
/dev/sda1               partition  -    -     83  500M /dev/sda
/dev/sda2               partition  -    -     8e  9.5G /dev/sda
/dev/sda                device     -    -     -   10G  -
  • 使用virt-resizecentos6.img-origin为基础扩展到新的centos6.img磁盘文件

virt-resize /var/lib/libvirt/images/centos6.img-origin /var/lib/libvirt/images/centos6.img --expand /dev/sda2 --LV-expand /dev/vg_centos6/lv_root

提示信息

[   0.0] Examining /var/lib/libvirt/images/centos6.img-origin
**********

Summary of changes:

/dev/sda1: This partition will be left alone.

/dev/sda2: This partition will be resized from 9.5G to 14.5G.  The LVM PV
on /dev/sda2 will be expanded using the 'pvresize' method.

/dev/vg_centos6/lv_root: This logical volume will be expanded to maximum
size.  The filesystem ext4 on /dev/vg_centos6/lv_root will be expanded
using the 'resize2fs' method.

**********
[   2.8] Setting up initial partition table on /var/lib/libvirt/images/centos6.img
[   3.0] Copying /dev/sda1
 100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ 00:00
[   8.2] Copying /dev/sda2
 100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ 00:00
[  44.0] Expanding /dev/sda2 using the 'pvresize' method
[  44.0] Expanding /dev/vg_centos6/lv_root using the 'resize2fs' method

Resize operation completed with no errors.  Before deleting the old disk,
carefully check that the resized disk boots and works correctly.
  • 验证扩容后的centos6.img镜像:

qemu-img info /var/lib/libvirt/images/centos6.img

virt-filesystems -a /var/lib/libvirt/images/centos6.img --all --long -h

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

virt-inspector: 诊断guest虚拟机

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

运行virt-inspector

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

virt-inspector -a /var/lib/libvirt/images/centos6.img > report.xml

virt-inspector -d centos6 > report.xml

report.xml内容类似

<?xml version="1.0"?>
<operatingsystems>
  <operatingsystem>
    <root>/dev/vg_centos6/lv_root</root>
    <name>linux</name>
    <arch>x86_64</arch>
    <distro>centos</distro>
    <product_name>CentOS release 6.9 (Final)</product_name>
    <major_version>6</major_version>
    <minor_version>9</minor_version>
    <package_format>rpm</package_format>
    <package_management>yum</package_management>
    <hostname>centos6</hostname>
    <format>installed</format>
    <mountpoints>
      <mountpoint dev="/dev/vg_centos6/lv_root">/</mountpoint>
      <mountpoint dev="/dev/sda1">/boot</mountpoint>
    </mountpoints>
    <filesystems>
      <filesystem dev="/dev/sda1">
        <type>ext4</type>
        <uuid>9c30133a-6c16-4d8c-9486-e52b1eaa5f22</uuid>
      </filesystem>
...

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

virt-inspector -d centos6 | xpath //filesystem/@dev

输出显示

Found 3 nodes:
-- NODE --
 dev="/dev/sda1"-- NODE --
 dev="/dev/vg_centos6/lv_root"-- NODE --
 dev="/dev/vg_centos6/lv_swap"

参考

Last updated