Exporting and Prepping a VM disk image for OpenStack

If you have a running virtual machine in OpenStack and want to export it, shrink it, and prep it for installation to Glance to use as a template for other machines, use these instructions.


In order to get cloud cloud-init working with resizefs in CentOS 6.x, you need to install it manually in the VM.

Instructions here:.

Short version:

Install cloud-init packages and git (this one is required to install linux-rootfs-resize):

# yum install -y cloud-utils cloud-init parted git

Install linux rootfs resize:

# cd /tmp
# git clone https://github.com/flegmatik/linux-rootfs-resize.git
# cd linux-rootfs-resize
# ./install


This has to be done each time the kernel is updated.

Examples of when this needs to be done:

  • Creating a new head node image
  • Creating a new login node image

You will want to install your packages in a VM that was “boot from volume”, so that there is a persistent volume in Cinder left around after you power off the VM.

In this example, we will grab the disk called loginnode image:

# cinder list
|                      ID                      | Status |         Display Name         | Size | Volume Type | Bootable |                 Attached to                  |
| 51e27df2-387b-40f1-97e1-50a848707fb1 | in-use |   loginnode image        |  10  |         None        |   true   | 91da14b6-fbf3-4fa0-b4b5-0c4cd504a9ca |

Note the ID.

You will then need to export this disk onto a machine to work with. This machine will need access to ceph (i.e. rbd ls works), and will need the following tools:


Export the image:

# rbd export volumes/volume-51e27df2-387b-40f1-97e1-50a848707fb1 loginnode.raw

Prep the image (this removes log files, persistent net rules, etc):

# virt-sysprep -a loginnode.raw

Use guestfish to resize the root filesystem down to its minimum size. In this example, we know that /dev/vda1 is /boot, and /dev/vda2 is /.

# guestfish --rw -a loginnode.raw

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> run
><fs> list-filesystems
/dev/vda1: ext4
/dev/vda2: ext4
><fs> e2fsck-f /dev/vda1
><fs> e2fsck-f /dev/vda2
><fs> resize2fs-M /dev/vda2

Now, check the size of the resulting file system:

><fs> mount /dev/vda2 /
><fs> mount /dev/vda1 /boot
><fs> df-h
Filesystem          Size  Used Avail Use% Mounted on
tmpfs                96M  152K   96M   1% /run
/dev/vda2           2.1G  2.1G         0 100% /sysroot
/dev/vda1           481M   99M  354M  22% /sysroot/boot

><fs> quit

The two devices use just over 2.5G. We will need to know this.

Now, sparsify the disk (fill what we can with zeroes):

# virt-sparsify loginnode.raw loginnode.sparse.raw

Create overlay file to protect source disk ...

Examine source disk ...
Fill free space in /dev/vda1 with zero ...
Fill free space in /dev/vda2 with zero ...
Copy to destination and make sparse ...

Sparsify operation completed with no errors.  Before deleting the old
disk, carefully check that the target disk boots and works correctly.

Even though we minimized the root filesystem, we haven’t shrunk the partition inside the disk. You can see that with:

# virt-filesystems --long --parts --blkdevs -h -a loginnode.sparse.raw
Name           Type           MBR  Size  Parent
/dev/sda1  partition  83   500M  /dev/sda
/dev/sda2  partition  83   9.5G  /dev/sda
/dev/sda   device         -        10G   -

Resize the /dev/sda2 partition. Create a new disk (not a partition) that will hold everything. Since we have 2.5G of files, we will create a 3G disk:

# truncate -s 3G[b] outdisk
# virt-resize --shrink /dev/sda2 loginnode.sparse.raw outdisk
Examining loginnode.sparse.raw ...

Summary of changes:

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

/dev/sda2: This partition will be resized from 9.5G to 2.5G.  The
        filesystem ext4 on /dev/sda2 will be expanded using the 'resize2fs'

Setting up initial partition table on outdisk ...
Copying /dev/sda1 ...
Copying /dev/sda2 ...
Expanding /dev/sda2 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.

Now outdisk has our finished disk file, and can be renamed and imported into Glance. You can check the final partition size if you like.

# virt-filesystems --long --parts --blkdevs -h -a outdisk
Name           Type           MBR  Size  Parent
/dev/sda1  partition  83   500M  /dev/sda
/dev/sda2  partition  83   2.5G  /dev/sda
/dev/sda   device         -        3.0G  -

Importing to OpenStack

If you are importing a new “loginnode image” follow these steps.

First, deactivate the old image so it’s not used anymore:

# glance image-update --name Login_Node_retired --property active=false Login_Node

Upload the new resized image to glance and activate with:

# glance image-create \
    --name Login_Node \
    --disk-format raw \
     --container-format bare \
     --min-disk 10 \
     --min-ram 512 \
     --file ./outdisk \
     --is-public True \
     --progress \
     --property active=true \
     --property image_type=loginnode