8df08851d7
Improve some wording and introduce non-breaking spaces. Change-Id: I315968c155f6707b4ae57b00cf96a26b453e1d23 Co-Authored-By: Diane Fleming <diane.fleming@rackspace.com>
394 lines
22 KiB
XML
394 lines
22 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE chapter [
|
|
<!-- Some useful entities borrowed from HTML -->
|
|
<!ENTITY nbsp " ">
|
|
]>
|
|
<chapter xmlns="http://docbook.org/ns/docbook"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"
|
|
xml:id="ch_modifying_images">
|
|
<title>Modify images</title>
|
|
<?dbhtml stop-chunking?>
|
|
<para>Once you have obtained a virtual machine image, you may want
|
|
to make some changes to it before uploading it to the
|
|
OpenStack Image service. Here we describe several tools
|
|
available that allow you to modify images.<warning>
|
|
<para>Do not attempt to use these tools to modify an image
|
|
that is attached to a running virtual machine. These
|
|
tools are designed to only modify images that are not
|
|
currently running.</para>
|
|
</warning></para>
|
|
<section xml:id="guestfish">
|
|
<title>guestfish</title>
|
|
<para>The <command>guestfish</command> program is a tool from
|
|
the <link xlink:href="http://libguestfs.org/"
|
|
>libguestfs</link> project that allows you to modify
|
|
the files inside of a virtual machine image.</para>
|
|
<note>
|
|
<para><command>guestfish</command> does not mount the
|
|
image directly into the local file system. Instead, it
|
|
provides you with a shell interface that enables you
|
|
to view, edit, and delete files. Many of
|
|
<command>guestfish</command> commands, such as
|
|
<command>touch</command>,
|
|
<command>chmod</command>, and <command>rm</command>,
|
|
resemble traditional bash commands.</para>
|
|
</note>
|
|
<simplesect>
|
|
<title>Example guestfish session</title>
|
|
<para>Sometimes, you must modify a virtual machine image
|
|
to remove any traces of the MAC address that was
|
|
assigned to the virtual network interface card when
|
|
the image was first created, because the MAC address
|
|
will be different when it boots the next time. This
|
|
example shows how to use guestfish to remove
|
|
references to the old MAC address by deleting the
|
|
<filename>/etc/udev/rules.d/70-persistent-net.rules</filename>
|
|
file and removing the <literal>HWADDR</literal> line
|
|
from the
|
|
<filename>/etc/sysconfig/network-scripts/ifcfg-eth0</filename>
|
|
file.</para>
|
|
<para>Assume that you have a CentOS qcow2 image called
|
|
<filename>centos63_desktop.img</filename>. Mount
|
|
the image in read-write mode as root, as
|
|
follows:</para>
|
|
<screen><prompt>#</prompt> <userinput>guestfish --rw -a centos63_desktop.img</userinput>
|
|
<computeroutput>
|
|
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></computeroutput></screen>
|
|
<para>This starts a guestfish session. Note that the
|
|
guestfish prompt looks like a fish: <literal>>
|
|
<fs></literal>.</para>
|
|
<para>We must first use the <command>run</command> command
|
|
at the guestfish prompt before we can do anything
|
|
else. This will launch a virtual machine, which will
|
|
be used to perform all of the file
|
|
manipulations.<screen><prompt>><fs></prompt> <userinput>run</userinput></screen>
|
|
We can now view the file systems in the image using the
|
|
<command>list-filesystems</command>
|
|
command:<screen><prompt>><fs></prompt> <userinput>list-filesystems</userinput>
|
|
<computeroutput>/dev/vda1: ext4
|
|
/dev/vg_centosbase/lv_root: ext4
|
|
/dev/vg_centosbase/lv_swap: swap</computeroutput></screen>We
|
|
need to mount the logical volume that contains the
|
|
root partition:
|
|
<screen><prompt>><fs></prompt> <userinput>mount /dev/vg_centosbase/lv_root /</userinput></screen></para>
|
|
<para>Next, we want to delete a file. We can use the
|
|
<command>rm</command> guestfish command, which
|
|
works the same way it does in a traditional
|
|
shell.</para>
|
|
<para><screen><prompt>><fs></prompt> <userinput>rm /etc/udev/rules.d/70-persistent-net.rules</userinput></screen>We
|
|
want to edit the <filename>ifcfg-eth0</filename> file
|
|
to remove the <literal>HWADDR</literal> line. The
|
|
<command>edit</command> command will copy the file
|
|
to the host, invoke your editor, and then copy the
|
|
file back.
|
|
<screen><prompt>><fs></prompt> <userinput>edit /etc/sysconfig/network-scripts/ifcfg-eth0</userinput></screen></para>
|
|
<para>If you want to modify this image to load the 8021q
|
|
kernel at boot time, you must create an executable
|
|
script in the
|
|
<filename>/etc/sysconfig/modules/</filename>
|
|
directory. You can use the <command>touch</command>
|
|
guestfish command to create an empty file, the
|
|
<command>edit</command> command to edit it, and
|
|
the <command>chmod</command> command to make it
|
|
executable.<screen><prompt>><fs></prompt> <userinput>touch /etc/sysconfig/modules/8021q.modules</userinput>
|
|
<prompt>><fs></prompt> <userinput>edit /etc/sysconfig/modules/8021q.modules</userinput></screen>
|
|
We add the following line to the file and save
|
|
it:<programlisting>modprobe 8021q</programlisting>Then
|
|
we set to executable:
|
|
<screen>><fs> <userinput>chmod 0755 /etc/sysconfig/modules/8021q.modules</userinput></screen></para>
|
|
<para>We're done, so we can exit using the
|
|
<command>exit</command>
|
|
command:<screen><prompt>><fs></prompt> <userinput>exit</userinput></screen></para>
|
|
</simplesect>
|
|
<simplesect>
|
|
<title>Go further with guestfish</title>
|
|
<para>There is an enormous amount of functionality in
|
|
guestfish and a full treatment is beyond the scope of
|
|
this document. Instead, we recommend that you read the
|
|
<link
|
|
xlink:href="http://libguestfs.org/guestfs-recipes.1.html"
|
|
>guestfs-recipes</link> documentation page for a
|
|
sense of what is possible with these tools.</para>
|
|
</simplesect>
|
|
</section>
|
|
<section xml:id="guestmount">
|
|
<title>guestmount</title>
|
|
<para>For some types of changes, you may find it easier to
|
|
mount the image's file system directly in the guest. The
|
|
<command>guestmount</command> program, also from the
|
|
libguestfs project, allows you to do so.</para>
|
|
<para>For example, to mount the root partition from our
|
|
<filename>centos63_desktop.qcow2</filename> image to
|
|
<filename>/mnt</filename>, we can do:</para>
|
|
<para>
|
|
<screen><prompt>#</prompt> <userinput>guestmount -a centos63_desktop.qcow2 -m /dev/vg_centosbase/lv_root --rw /mnt</userinput></screen>
|
|
</para>
|
|
<para>If we didn't know in advance what the mount point is in
|
|
the guest, we could use the <literal>-i</literal>(inspect)
|
|
flag to tell guestmount to automatically determine what
|
|
mount point to
|
|
use:<screen><prompt>#</prompt> <userinput>guestmount -a centos63_desktop.qcow2 -i --rw /mnt</userinput></screen>Once
|
|
mounted, we could do things like list the installed
|
|
packages using
|
|
rpm:<screen><prompt>#</prompt> <userinput>rpm -qa --dbpath /mnt/var/lib/rpm</userinput></screen>
|
|
Once done, we
|
|
unmount:<screen><prompt>#</prompt> <userinput>umount /mnt</userinput></screen></para>
|
|
</section>
|
|
<section xml:id="virt-tools">
|
|
<title>virt-* tools</title>
|
|
<para>The <link xlink:href="http://libguestfs.org/"
|
|
>libguestfs</link> project has a number of other
|
|
useful tools, including:<itemizedlist>
|
|
<listitem>
|
|
<para><link
|
|
xlink:href="http://libguestfs.org/virt-edit.1.html"
|
|
>virt-edit</link> for editing a file
|
|
inside of an image.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><link
|
|
xlink:href="http://libguestfs.org/virt-df.1.html"
|
|
>virt-df</link> for displaying free space
|
|
inside of an image.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><link
|
|
xlink:href="http://libguestfs.org/virt-resize.1.html"
|
|
>virt-resize</link> for resizing an
|
|
image.</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><link
|
|
xlink:href="http://libguestfs.org/virt-sysprep.1.html"
|
|
>virt-sysprep</link> for preparing an
|
|
image for distribution (for example, delete
|
|
SSH host keys, remove MAC address info, or
|
|
remove user accounts).</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><link
|
|
xlink:href="http://libguestfs.org/virt-sparsify.1.html"
|
|
>virt-sparsify</link> for making an image
|
|
sparse</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><link
|
|
xlink:href="http://libguestfs.org/virt-v2v/"
|
|
>virt-p2v</link> for converting a physical
|
|
machine to an image that runs on KVM</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para><link
|
|
xlink:href="http://libguestfs.org/virt-v2v/"
|
|
>virt-v2v</link> for converting Xen and
|
|
VMWare images to KVM images</para>
|
|
</listitem>
|
|
</itemizedlist></para>
|
|
<simplesect>
|
|
<title>Modify a single file inside of an image</title>
|
|
<para>This example shows how to use
|
|
<command>virt-edit</command> to modify a file. The
|
|
command can take either a filename as an argument with
|
|
the <literal>-a</literal> flag, or a domain name as an
|
|
argument with the <literal>-d</literal> flag. The
|
|
following examples shows how to use this to modify the
|
|
<filename>/etc/shadow</filename> file in instance
|
|
with libvirt domain name
|
|
<literal>instance-000000e1</literal> that is
|
|
currently running:</para>
|
|
<para>
|
|
<screen><prompt>#</prompt> <userinput>virsh shutdown instance-000000e1</userinput>
|
|
<prompt>#</prompt> <userinput>virt-edit -d instance-000000e1 /etc/shadow</userinput>
|
|
<prompt>#</prompt> <userinput>virsh start instance-000000e1</userinput></screen>
|
|
</para>
|
|
</simplesect>
|
|
<simplesect>
|
|
<title>Resize an image</title>
|
|
<para>Here's a simple of example of how to use
|
|
<command>virt-resize</command> to resize an image.
|
|
Assume we have a 16 GB Windows image in qcow2 format
|
|
that we want to resize to 50 GB. First, we use
|
|
<command>virt-filesystems</command> to identify
|
|
the
|
|
partitions:<screen><prompt>#</prompt> <userinput>virt-filesystems --long --parts --blkdevs -h -a /data/images/win2012.qcow2</userinput>
|
|
<computeroutput>Name Type MBR Size Parent
|
|
/dev/sda1 partition 07 350M /dev/sda
|
|
/dev/sda2 partition 07 16G /dev/sda
|
|
/dev/sda device - 16G -
|
|
</computeroutput></screen></para>
|
|
<para>In this case, it's the
|
|
<filename>/dev/sda2</filename> partition that we
|
|
want to resize. We create a new qcow2 image and use
|
|
the <command>virt-resize</command> command to write a
|
|
resized copy of the original into the new
|
|
image:
|
|
<screen><prompt>#</prompt> <userinput>qemu-img create -f qcow2 /data/images/win2012-50gb.qcw2 50G</userinput>
|
|
<prompt>#</prompt> <userinput>virt-resize --expand /dev/sda2 /data/images/win2012.qcow2 \
|
|
/data/images/win2012-50gb.qcow2</userinput>
|
|
<computeroutput>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.
|
|
</computeroutput></screen></para>
|
|
</simplesect>
|
|
</section>
|
|
<section xml:id="losetup-kpartx-nbd">
|
|
<title>Loop devices, kpartx, network block devices</title>
|
|
<para>If you don't have access to libguestfs, you can mount
|
|
image file systems directly in the host using loop
|
|
devices, kpartx, and network block devices.<warning>
|
|
<para>Mounting untrusted guest images using the tools
|
|
described in this section is a security risk,
|
|
always use libguestfs tools such as guestfish and
|
|
guestmount if you have access to them. See <link
|
|
xlink:href="https://www.berrange.com/posts/2013/02/20/a-reminder-why-you-should-never-mount-guest-disk-images-on-the-host-os/"
|
|
>A reminder why you should never mount guest
|
|
disk images on the host OS</link> by Daniel
|
|
Berrangé for more details.</para>
|
|
</warning></para>
|
|
<simplesect>
|
|
<title>Mount a raw image (without LVM)</title>
|
|
<para>If you have a raw virtual machine image that is not
|
|
using LVM to manage its partitions. First, use the
|
|
<command>losetup</command> command to find an
|
|
unused loop device.
|
|
<screen><prompt>#</prompt> <userinput>losetup -f</userinput>
|
|
<computeroutput>/dev/loop0</computeroutput></screen></para>
|
|
<para>In this example, <filename>/dev/loop0</filename> is
|
|
free. Associate a loop device with the raw
|
|
image:<screen><prompt>#</prompt> <userinput>losetup /dev/loop0 fedora17.img</userinput></screen></para>
|
|
<para>If the image only has a single partition, you can
|
|
mount the loop device
|
|
directly:<screen><prompt>#</prompt> <userinput>mount /dev/loop0 /mnt</userinput></screen></para>
|
|
<para>If the image has multiple partitions, use
|
|
<command>kpartx</command> to expose the partitions
|
|
as separate devices (for example,
|
|
<filename>/dev/mapper/loop0p1</filename>), then
|
|
mount the partition that corresponds to the root file
|
|
system:<screen><prompt>#</prompt> <userinput>kpartx -av /dev/loop0</userinput></screen></para>
|
|
<para>If the image has, say three partitions (/boot, /,
|
|
/swap), there should be one new device created per
|
|
partition:<screen><prompt>$</prompt> <userinput>ls -l /dev/mapper/loop0p*</userinput>
|
|
<computeroutput>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</computeroutput></screen>To
|
|
mount the second partition, as
|
|
root:<screen><prompt>#</prompt> <userinput>mkdir /mnt/image</userinput>
|
|
<prompt>#</prompt> <userinput>mount /dev/mapper/loop0p2 /mnt</userinput></screen>Once
|
|
you're done, to clean
|
|
up:<screen><prompt>#</prompt> <userinput>umount /mnt</userinput>
|
|
<prompt>#</prompt> <userinput>kpartx -d /dev/loop0</userinput>
|
|
<prompt>#</prompt> <userinput>losetup -d /dev/loop0</userinput></screen></para>
|
|
</simplesect>
|
|
<simplesect>
|
|
<title>Mount a raw image (with LVM)</title>
|
|
<para>If your partitions are managed with LVM, use losetup
|
|
and kpartx as in the previous example to expose the
|
|
partitions to the host:</para>
|
|
<screen><prompt>#</prompt> <userinput>losetup -f</userinput>
|
|
<computeroutput>/dev/loop0</computeroutput>
|
|
<prompt>#</prompt> <userinput>losetup /dev/loop0 rhel62.img</userinput>
|
|
<prompt>#</prompt> <userinput>kpartx -av /dev/loop0</userinput></screen>
|
|
<para>Next, you need to use the <command>vgscan</command>
|
|
command to identify the LVM volume groups and then
|
|
<command>vgchange</command> to expose the volumes
|
|
as devices:</para>
|
|
<screen><prompt>#</prompt> <userinput>vgscan</userinput>
|
|
<computeroutput>Reading all physical volumes. This may take a while...
|
|
Found volume group "vg_rhel62x8664" using metadata type lvm2</computeroutput>
|
|
<prompt>#</prompt> <userinput>vgchange -ay</userinput>
|
|
<computeroutput> 2 logical volume(s) in volume group "vg_rhel62x8664" now active</computeroutput>
|
|
<prompt>#</prompt> <userinput>mount /dev/vg_rhel62x8664/lv_root /mnt</userinput></screen>
|
|
<para>Clean up when you're done:</para>
|
|
<screen><prompt>#</prompt> <userinput>umount /mnt</userinput>
|
|
<prompt>#</prompt> <userinput>vgchange -an vg_rhel62x8664</userinput>
|
|
<prompt>#</prompt> <userinput>kpartx -d /dev/loop0</userinput>
|
|
<prompt>#</prompt> <userinput>losetup -d /dev/loop0</userinput></screen>
|
|
</simplesect>
|
|
<simplesect>
|
|
<title>Mount a qcow2 image (without LVM)</title>
|
|
<para>You need the <literal>nbd</literal> (network block
|
|
device) kernel module loaded to mount qcow2 images.
|
|
This will load it with support for 16 block devices,
|
|
which is fine for our purposes. As
|
|
root:<screen><prompt>#</prompt> <userinput>modprobe nbd max_part=16</userinput></screen></para>
|
|
<para>Assuming the first block device
|
|
(<filename>/dev/nbd0</filename>) is not currently
|
|
in use, we can expose the disk partitions using the
|
|
<command>qemu-nbd</command> and
|
|
<command>partprobe</command> commands. As
|
|
root:<screen><prompt>#</prompt> <userinput>qemu-nbd -c /dev/nbd0 image.qcow2</userinput>
|
|
<prompt>#</prompt> <userinput>partprobe /dev/nbd0</userinput></screen></para>
|
|
<para>If the image has, say three partitions (/boot, /,
|
|
/swap), there should be one new device created for
|
|
each partition:</para>
|
|
<screen><prompt>$</prompt> <userinput>ls -l /dev/nbd3*</userinput>
|
|
<computeroutput>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</computeroutput></screen>
|
|
<note>
|
|
<para>If the network block device you selected was
|
|
already in use, the initial
|
|
<command>qemu-nbd</command> command will fail
|
|
silently, and the
|
|
<filename>/dev/nbd3p{1,2,3}</filename> device
|
|
files will not be created.</para>
|
|
</note>
|
|
<para>If the image partitions are not managed with LVM,
|
|
they can be mounted directly:</para>
|
|
<screen><prompt>#</prompt> <userinput>mkdir /mnt/image</userinput>
|
|
<prompt>#</prompt> <userinput>mount /dev/nbd3p2 /mnt</userinput></screen>
|
|
<para>When you're done, clean up:</para>
|
|
<screen><prompt>#</prompt> <userinput>umount /mnt</userinput>
|
|
<prompt>#</prompt> <userinput>qemu-nbd -d /dev/g nbd0</userinput></screen>
|
|
</simplesect>
|
|
<simplesect>
|
|
<title>Mount a qcow2 image (with LVM)</title>
|
|
<para>If the image partitions are managed with LVM, after
|
|
you use <command>qemu-nbd</command> and
|
|
<command>partprobe</command>, you must use
|
|
<command>vgscan</command> and <command>vgchange
|
|
-ay</command> in order to expose the LVM
|
|
partitions as devices that can be
|
|
mounted:<screen><prompt>#</prompt> <userinput>modprobe nbd max_part=16</userinput>
|
|
<prompt>#</prompt> <userinput>qemu-nbd -c /dev/nbd0 image.qcow2</userinput>
|
|
<prompt>#</prompt> <userinput>partprobe /dev/nbd0</userinput><prompt>#</prompt> <userinput>vgscan</userinput>
|
|
<computeroutput> Reading all physical volumes. This may take a while...
|
|
Found volume group "vg_rhel62x8664" using metadata type lvm2</computeroutput>
|
|
<prompt>#</prompt> <userinput>vgchange -ay</userinput>
|
|
<computeroutput> 2 logical volume(s) in volume group "vg_rhel62x8664" now active</computeroutput>
|
|
<prompt>#</prompt> <userinput>mount /dev/vg_rhel62x8664/lv_root /mnt</userinput></screen></para>
|
|
<para>When you're done, clean
|
|
up:<screen><prompt>#</prompt> <userinput>umount /mnt</userinput>
|
|
<prompt>#</prompt> <userinput>vgchange -an vg_rhel62x8664</userinput>
|
|
<prompt>#</prompt> <userinput>qemu-nbd -d /dev/nbd0</userinput></screen></para>
|
|
</simplesect>
|
|
</section>
|
|
</chapter>
|