修改镜像¶
获得虚拟机镜像后,您可能需要在将其上传到镜像服务之前对其进行一些更改。以下描述了可用于修改镜像的几种工具。
警告
请勿尝试使用这些工具修改已附加到正在运行的虚拟机的镜像。这些工具仅设计用于修改当前未运行的镜像。
guestfish¶
guestfish 程序是 libguestfs 项目中的一个工具,它允许您修改虚拟机镜像内部的文件。
注意
guestfish 不会直接将镜像挂载到本地文件系统。相反,它为您提供了一个 shell 界面,使您可以查看、编辑和删除文件。许多 guestfish 命令,例如 touch、chmod 和 rm,类似于传统的 bash 命令。
示例 guestfish 会话¶
有时您必须修改虚拟机镜像以删除分配给虚拟网络接口卡在镜像首次创建时分配的 MAC 地址的任何痕迹。这是因为虚拟机镜像启动时 MAC 地址不同。本示例演示如何使用 guestfish 删除对旧 MAC 地址的引用,方法是删除 /etc/udev/rules.d/70-persistent-net.rules 文件,并从 /etc/sysconfig/network-scripts/ifcfg-eth0 文件中删除 HWADDR 行。
假设您有一个名为 centos63_desktop.img 的 CentOS qcow2 镜像。以 root 身份以读写模式挂载镜像,如下所示
# guestfish --rw -a centos63_desktop.img
Welcome to guestfish, the libguestfs filesystem interactive shell for
editing virtual machine filesystems.
Type: 'help' for help on commands
'man' to read the manual
'quit' to quit the shell
><fs>
这将启动一个 guestfish 会话。
注意
guestfish 提示符看起来像一条鱼:><fs>。
我们必须首先在 guestfish 提示符下使用 run 命令,然后才能执行任何其他操作。这将启动一个虚拟机,该虚拟机将用于执行所有文件操作。
><fs> run
现在我们可以使用 list-filesystems 命令查看镜像中的文件系统
><fs> list-filesystems /dev/vda1: ext4 /dev/vg_centosbase/lv_root: ext4 /dev/vg_centosbase/lv_swap: swap
我们需要挂载包含根分区的逻辑卷
><fs> mount /dev/vg_centosbase/lv_root /接下来,我们想要删除一个文件。我们可以使用 rm guestfish 命令,它的工作方式与传统 shell 中的方式相同。
><fs> rm /etc/udev/rules.d/70-persistent-net.rules我们想要编辑
ifcfg-eth0文件以删除HWADDR行。 edit 命令会将文件复制到主机,调用您的编辑器,然后将文件复制回去。><fs> edit /etc/sysconfig/network-scripts/ifcfg-eth0如果您想修改此镜像以在启动时加载 8021q 内核,则必须在
/etc/sysconfig/modules/目录中创建一个可执行脚本。您可以使用 touch guestfish 命令创建空文件,使用 edit 命令编辑它,并使用 chmod 命令使其可执行。><fs> touch /etc/sysconfig/modules/8021q.modules ><fs> edit /etc/sysconfig/modules/8021q.modules
我们将以下行添加到文件中并保存它
modprobe 8021q然后我们设置为可执行
><fs> chmod 0755 /etc/sysconfig/modules/8021q.modules我们完成了,可以使用 exit 命令退出
><fs> exit
进一步了解 guestfish¶
guestfish 中包含大量功能,超出本文档的范围。相反,我们建议您阅读 guestfs-recipes 文档页面,以了解使用这些工具的可能性。
guestmount¶
对于某些类型的更改,您可能会发现直接在客户机中挂载镜像的文件系统更容易。 guestmount 程序也来自 libguestfs 项目,允许您这样做。
例如,要将我们的
centos63_desktop.qcow2镜像的根分区挂载到/mnt,我们可以执行# guestmount -a centos63_desktop.qcow2 -m /dev/vg_centosbase/lv_root --rw /mnt
如果事先不知道客户机中的挂载点是什么,我们可以使用
-i(inspect) 标志告诉 guestmount 自动确定要使用的挂载点# guestmount -a centos63_desktop.qcow2 -i --rw /mnt
挂载后,我们可以使用 rpm 列出已安装的软件包等
# rpm -qa --dbpath /mnt/var/lib/rpm
完成后,我们卸载
# umount /mnt
virt-* 工具¶
libguestfs 项目还有许多其他有用的工具,包括
virt-edit 用于编辑镜像中的文件。
virt-df 用于显示镜像中的可用空间。
virt-resize 用于调整镜像大小。
virt-sysprep 用于准备镜像以供分发(例如,删除 SSH 主机密钥、删除 MAC 地址信息或删除用户帐户)。
virt-sparsify 用于使镜像稀疏。
virt-p2v 用于将物理机转换为在 KVM 上运行的镜像。
virt-v2v 用于将 Xen 和 VMware 镜像转换为 KVM 镜像。
修改镜像中的单个文件¶
本示例演示如何使用 virt-edit 修改文件。该命令可以接受带有 -a 标志的文件名作为参数,也可以接受带有 -d 标志的域名作为参数。以下示例演示如何使用它来修改 libvirt 域名为 instance-000000e1 的实例中的 /etc/shadow 文件
# virsh shutdown instance-000000e1
# virt-edit -d instance-000000e1 /etc/shadow
# virsh start instance-000000e1
调整镜像大小¶
以下是如何使用 virt-resize 调整镜像大小的示例。假设我们有一个 16 GB 的 Windows 镜像,格式为 qcow2,我们想将其调整为 50 GB。
首先,我们使用 virt-filesystems 识别分区
# virt-filesystems --long --parts --blkdevs -h -a /data/images/win2012.qcow2 Name Type MBR Size Parent /dev/sda1 partition 07 350M /dev/sda /dev/sda2 partition 07 16G /dev/sda /dev/sda device - 16G -
在这种情况下,是我们想要调整大小的
/dev/sda2分区。我们创建一个新的 qcow2 镜像并使用 virt-resize 命令将原始镜像的调整大小后的副本写入新镜像# qemu-img create -f qcow2 /data/images/win2012-50gb.qcow2 50G # virt-resize --expand /dev/sda2 /data/images/win2012.qcow2 \ /data/images/win2012-50gb.qcow2 Examining /data/images/win2012.qcow2 ... ********** Summary of changes: /dev/sda1: This partition will be left alone. /dev/sda2: This partition will be resized from 15.7G to 49.7G. The filesystem ntfs on /dev/sda2 will be expanded using the 'ntfsresize' method. ********** Setting up initial partition table on /data/images/win2012-50gb.qcow2 ... Copying /dev/sda1 ... 100% [ ] 00:00 Copying /dev/sda2 ... 100% [ ] 00:00 Expanding /dev/sda2 using the 'ntfsresize' method ... Resize operation completed with no errors. Before deleting the old disk, carefully check that the resized disk boots and works correctly.
循环设备、kpartx、网络块设备¶
如果您无法访问 libguestfs,可以使用循环设备、kpartx 和网络块设备直接在主机中挂载镜像文件系统。
警告
使用本节中描述的工具挂载不受信任的客户机镜像存在安全风险,始终使用 libguestfs 工具(如 guestfish 和 guestmount)如果您可以访问它们。有关更多详细信息,请参阅 Daniel Berrangé 的 为什么永远不应将客户机磁盘镜像挂载到主机操作系统。
挂载原始镜像(无 LVM)¶
如果您有一个原始虚拟机镜像,未使用 LVM 来管理其分区,请使用 losetup 命令查找未使用的循环设备。
# losetup -f
/dev/loop0
在此示例中,/dev/loop0 是免费的。将循环设备与原始镜像关联
# losetup /dev/loop0 fedora17.img
如果镜像只有一个分区,您可以直接挂载循环设备
# mount /dev/loop0 /mnt
如果镜像有多个分区,请使用 kpartx 将分区作为单独的设备公开(例如,/dev/mapper/loop0p1),然后挂载与根文件系统对应的分区
# kpartx -av /dev/loop0
如果镜像有,例如三个分区(/boot、/、swap),应该为每个分区创建一个新的设备
$ ls -l /dev/mapper/loop0p*
brw-rw---- 1 root disk 43, 49 2012-03-05 15:32 /dev/mapper/loop0p1
brw-rw---- 1 root disk 43, 50 2012-03-05 15:32 /dev/mapper/loop0p2
brw-rw---- 1 root disk 43, 51 2012-03-05 15:32 /dev/mapper/loop0p3
要挂载第二个分区,作为 root
# mkdir /mnt/image
# mount /dev/mapper/loop0p2 /mnt/image
完成后,清理
# umount /mnt/image
# rmdir /mnt/image
# kpartx -d /dev/loop0
# losetup -d /dev/loop0
挂载原始镜像(有 LVM)¶
如果您的分区使用 LVM 管理,请使用 losetup 和 kpartx 命令如前所述将分区暴露给主机。
# losetup -f
/dev/loop0
# losetup /dev/loop0 rhel62.img
# kpartx -av /dev/loop0
接下来,您需要使用 vgscan 命令识别 LVM 卷组,然后使用 vgchange 命令将卷暴露为设备
# vgscan
Reading all physical volumes. This may take a while...
Found volume group "vg_rhel62x8664" using metadata type lvm2
# vgchange -ay
2 logical volume(s) in volume group "vg_rhel62x8664" now active
# mount /dev/vg_rhel62x8664/lv_root /mnt
完成后清理
# umount /mnt
# vgchange -an vg_rhel62x8664
# kpartx -d /dev/loop0
# losetup -d /dev/loop0
挂载 qcow2 镜像(无 LVM)¶
您需要加载 nbd(网络块设备)内核模块才能挂载 qcow2 镜像。这将使用 16 个块设备的配置加载它,对于我们的目的来说,这很好。作为 root
# modprobe nbd max_part=16
假设第一个块设备 (/dev/nbd0) 当前未使用,我们可以使用 qemu-nbd 和 partprobe 命令公开磁盘分区。作为 root
# qemu-nbd -c /dev/nbd0 image.qcow2
# partprobe /dev/nbd0
如果镜像有,例如三个分区(/boot、/、swap),应该为每个分区创建一个新的设备
$ ls -l /dev/nbd0*
brw-rw---- 1 root disk 43, 48 2012-03-05 15:32 /dev/nbd0
brw-rw---- 1 root disk 43, 49 2012-03-05 15:32 /dev/nbd0p1
brw-rw---- 1 root disk 43, 50 2012-03-05 15:32 /dev/nbd0p2
brw-rw---- 1 root disk 43, 51 2012-03-05 15:32 /dev/nbd0p3
注意
如果选择的网络块设备已被使用,则初始 qemu-nbd 命令将无声地失败,并且不会创建 /dev/nbd0p{1,2,3} 设备文件。
如果镜像分区不由 LVM 管理,则可以直接挂载它们
# mkdir /mnt/image
# mount /dev/nbd0p2 /mnt/image
完成后,清理
# umount /mnt/image
# rmdir /mnt/image
# qemu-nbd -d /dev/nbd0
挂载 qcow2 镜像(有 LVM)¶
如果镜像分区由 LVM 管理,在使用 qemu-nbd 和 partprobe 后,必须使用 vgscan 和 vgchange -ay 才能将 LVM 分区暴露为可以挂载的设备
# modprobe nbd max_part=16
# qemu-nbd -c /dev/nbd0 image.qcow2
# partprobe /dev/nbd0
# vgscan
Reading all physical volumes. This may take a while...
Found volume group "vg_rhel62x8664" using metadata type lvm2
# vgchange -ay
2 logical volume(s) in volume group "vg_rhel62x8664" now active
# mount /dev/vg_rhel62x8664/lv_root /mnt
完成后,清理
# umount /mnt
# vgchange -an vg_rhel62x8664
# qemu-nbd -d /dev/nbd0