OpenStack镜像修改

半兽人 发表于: 2023-03-02   最后更新时间: 2023-03-02 14:48:19  
{{totalSubscript}} 订阅, 882 游览

一旦你获得了虚拟机镜像,上传到镜像服务之前你可能希望对其进行一些修改。这里我们介绍几个可用的工具,可以让你修改镜像。

警告
不要尝试使用这些工具来修改正在运行的虚拟机镜像。这些工具仅设计用于修改当前未运行的镜像

guestfish

guestfish程序是来自libguestfs项目的一个工具,允许你修改虚拟机镜像中的文件。

注意
guestfish不直接将镜像挂载到本地文件系统中。相反,它提供了一个shell界面,使你能够查看、编辑和删除文件。guestfish的许多命令,例如touchchmodrm,类似于传统的bash命令。

guestfish session 的例子

有时候你必须修改虚拟机镜像,以删除在镜像创建时分配给虚拟网络接口卡的MAC地址的任何痕迹。这是因为当虚拟机镜像启动时,MAC地址是不同的。以下示例演示如何使用guestfish通过删除 /etc/udev/rules.d/70-persistent-net.rules 文件和从 /etc/sysconfig/network-scripts/ifcfg-eth0 文件中删除 HWADDR 行来删除旧MAC地址的引用。

假设你有一个名为 centos63_desktop.imgCentOS 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 提示看起来像一条鱼: ><fs>

我们必须先在 guestfish 提示符下使用run命令,然后才能执行其他任何操作。 这将启动一个虚拟机,该虚拟机将用于执行所有文件操作:

><fs> run
  1. 现在我们可以使用list-filesystems命令查看镜像中的文件系统:

    ><fs> list-filesystems
    /dev/vda1: ext4
    /dev/vg_centosbase/lv_root: ext4
    /dev/vg_centosbase/lv_swap: swap
    
  2. 我们需要挂载包含根分区的逻辑卷:

    ><fs> mount /dev/vg_centosbase/lv_root /
    
  3. 接下来,我们想要删除一个文件。我们可以使用guestfish的rm命令,其工作方式与传统shell中的rm命令相同。

    ><fs> rm /etc/udev/rules.d/70-persistent-net.rules
    
  4. 我们想要编辑 ifcfg-eth0 文件,以删除 HWADDR 行。edit命令将把文件复制到主机,调用你的编辑器,然后再将文件复制回来。

    ><fs> edit /etc/sysconfig/network-scripts/ifcfg-eth0
    
  5. 如果你想修改这个镜像,在启动时加载8021q内核,你必须在 /etc/sysconfig/modules/ 目录中创建一个可执行的脚本。你可以使用guestfish的touch命令创建一个空文件,使用edit命令编辑它,然后使用chmod命令使其可执行。

    ><fs> touch /etc/sysconfig/modules/8021q.modules
    ><fs> edit /etc/sysconfig/modules/8021q.modules
    
  6. 我们向该文件添加以下行并保存:

    modprobe 8021q
    
  7. 然后我们设置为可执行文件:

    ><fs> chmod 0755 /etc/sysconfig/modules/8021q.modules
    
  8. 完成后,我们可以使用exit命令退出:

    ><fs> exit
    

继续学习guestfish

guestfish中有大量的功能,完整的介绍超出了本文档的范围。相反,我们建议你阅读guestfs-recipes文档页面,以了解使用这些工具可能实现的功能。

guestmount

对于某些类型的更改,你可能会发现直接在虚拟机中挂载镜像的文件系统更容易。guestmount程序,也来自于libguestfs项目,可以让你这样做。

  1. 例如,要将centos63_desktop.qcow2镜像中的根分区挂载到/mnt目录,我们可以执行以下操作:

    # guestmount -a centos63_desktop.qcow2 -m /dev/vg_centosbase/lv_root --rw /mnt
    
  2. 如果我们事先不知道在guest中的挂载点是什么,我们可以使用-i(inspect)标志,告诉guestmount自动确定要使用的挂载点:

    # guestmount -a centos63_desktop.qcow2 -i --rw /mnt
    
  3. 一旦挂载成功,我们可以执行像使用 rpm 列出已安装软件包这样的操作:

    # rpm -qa --dbpath /mnt/var/lib/rpm
    
  4. 完成后,我们卸载:

    # umount /mnt
    

virt-* tools

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标志将域名作为参数。下面的示例展示如何在当前正在运行的名为instance-000000e1的libvirt域中修改/etc/shadow文件:

# virsh shutdown instance-000000e1
# virt-edit -d instance-000000e1 /etc/shadow
# virsh start instance-000000e1

调整镜像大小

以下是如何使用 virt-resize 来调整镜像大小的示例。假设我们有一个 qcow2 格式的 16GB Windows 镜像,我们想要将其调整为 50GB。

  1. 首先,我们使用 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   -
    
  2. 在这种情况下,我们要调整大小的是/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.

Loop设备、kpartx、网络块设备

如果您无法访问libguestfs,可以使用loop驱动、kpartx和网络块设备直接在主机上挂载镜像文件系统。

警告

使用本节中描述的工具挂载不受信任的guest镜像是一种安全风险,如果可以访问libguestfs工具,应始终使用guestfish和guestmount。有关更多详细信息,请参见Daniel Berrangé的文章“A reminder why you should never mount guest disk images on the host OS”。

挂在原生镜像(没有LVM)

如果你有一个未使用LVM来管理其分区的原始虚拟机镜像,可以使用losetup命令找到一个未使用的loop设备。

# losetup -f
/dev/loop0

在这个例子中,/dev/loop0 是空闲的。将一个 loop 设备与原始镜像关联起来:

# losetup /dev/loop0 fedora17.img

如果镜像只有一个分区,您可以直接挂载loop设备:

# 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

REF

https://docs.openstack.org/image-guide/modify-images.html

更新于 2023-03-02

查看OpenStack更多相关的文章或提一个关于OpenStack的问题,也可以与我们一起分享文章