NEW! Mirantis Academy -   Learn confidently with expert guidance and On-demand content.   Learn More

< BLOG HOME

How to manually create an OpenStack image

Eric Gregory, Nick Chase - March 01, 2023
image

In order to create a virtual machine (VM) on OpenStack, you'll need to have an image that serves as a basis for it.  For example, you might have an image that represents a VM running the Ubuntu operating system, or one that has certain applications installed. In some cases, the image you want will already be uploaded to OpenStack, or you'll be able to download it from an authoritative source. Sometimes, however, you just need to start from scratch. 

There are several ways to create your own image using open source tools. We’ll cover two approaches here: one on the command line, and one (mostly) using the GUI-driven virtualization software VirtualBox.

There are several ways to create your own image using open source tools. We’ll cover two approaches here: one on the command line, and one (mostly) using the GUI-driven virtualization software VirtualBox.

Prerequisites

For either approach, you will need access to a Linux environment. In this tutorial, we’re using Ubuntu 22.04.01 Desktop. If you’re using Linux already, or you have a Linux machine to which you’re able to transfer files, then you’re all set. 

If you’re on Windows or Mac, you can install VirtualBox at the outset and work on your virtual machine images from within a virtual machine—in this case, an Ubuntu machine. (In order to install a working VM, you can follow the VirtualBox OS installation instructions below, substituting the Ubuntu Desktop ISO.)

You may wish to enable Guest Additions and a Shared Folder so you can transfer files between your guest and host machine as needed, but this is optional for the command line approach. 

Creating a custom image on the command line

In this example, we’re going to create a custom image of Rocky Linux 9.1 in QCOW2 format suitable for running on OpenStack.

The OpenStack documentation describes a method for creating a new image on Linux machines using libvirt, but we can automate much of the grunt-work by using a handy open source tool from the OpenStack project called diskimage-builder. Diskimage-builder is intended to simplify and standardize the process of creating cloud-ready images across major Linux distributions, with an extensible design that enables users to add new distros or image specifications. 

As of this writing, diskimage-builder supports the following target distributions:

  • Rocky

  • Ubuntu

  • Fedora

  • Debian

  • OpenSUSE

  • Gentoo

  • CentOS Stream

  • openEuler

    Install diskimage-builder

    On an Ubuntu machine, we’ll first install a couple of dependencies for running diskimage-builder:

$ sudo apt-get install tox podman

Now we’ll download the tool itself:

$ git clone https://opendev.org/openstack/diskimage-builder
$ cd diskimage-builder

Next we’ll use tox and bindep (environment and dependency management tools) to check for missing dependencies in this environment, and download any requirements indicated in the error message:

$ tox -e bindep
$ sudo apt-get install <any packages indicated by output from above>

Now we’re ready to generate our image.

Generate a Rocky Linux 9.1 image in QCOW2 format

Diskimage-builder conceptualizes all of the different ways you might provide specifications for a new image as “elements”—and each supported distribution for target images is specified via an element.

We can create a Rocky Linux image using the rocky-container element, which will source our Rocky release from the distribution’s officially maintained container image, defaulting to the latest release. This will produce a minimal Rocky image meeting OpenStack’s requirements for Linux images:

$ sudo tox -e venv -- disk-image-create rocky-container vm

When the command completes, we will have an OpenStack-ready QCOW2 file called image.qcow2, and we could stop here—but if we’re creating an image from scratch, we probably want to do some customization. 

Diskimage-builder elements provide one way to customize certain aspects of an image, but elements aren’t always interoperable with one another. For a more standardized way to customize an image, we’ll use the libguestfs suite of virtual machine tools—specifically virt-sysprep

Customize the Rocky Linux 9.1 image using virt-sysprep

We can install and configure our libguestfs tools (including virt-sysprep) as follows:

$ sudo apt-get install libguestfs-tools
$ export LIBGUESTFS_BACKEND=direct

Broadly speaking, the purpose of virt-sysprep is to bring a virtual machine to a clean, “clone-able” state by removing unique identifying information like persistent network MAC configurations, individual users, and so on. This is exactly what we want for a system like OpenStack, which is going to create instances from our image.

Because we created our image with diskimage-builder, we don’t need to remove anything—but we may want to leverage a secondary function of virt-sysprep, which is to inject various customizations into the image. These might include…

  • Installing packages

  • Adding boot commands

  • Creating directories

  • Managing users

…and much more. You can browse a complete list in the documentation.

In this tutorial, we’re simply going to define a root user password. The default behavior of virt-sysprep is to randomize the root password, but we may wish to manually tailor our implementation further—this will give us the ability to access an instance.

In order to sysprep the image, we’ll run the following command from the working directory where we generated our QCOW2 image:

$ sudo virt-sysprep --root-password password:password -a ./image.qcow2

Here, we’re defining a password as a simple string: in the above example, the password is password. You should use a strong root password instead—and note that this approach is not secure for a production image, since the password will be visible to other users on the same machine. (You can explore other approaches to users and passwords here.)

Executing the command should produce the following output:

[   0.0] Examining the guest ...
[  51.6] Performing "abrt-data" ...
[  51.7] Performing "backup-files" ...
[  56.1] Performing "bash-history" ...
[  56.2] Performing "blkid-tab" ...
[  56.4] Performing "crash-data" ...
[  56.6] Performing "cron-spool" ...
[  56.7] Performing "dhcp-client-state" ...
[  56.8] Performing "dhcp-server-state" ...
[  56.8] Performing "dovecot-data" ...
[  56.9] Performing "ipa-client" ...
[  57.1] Performing "kerberos-hostkeytab" ...
[  57.2] Performing "logfiles" ...
[  58.6] Performing "machine-id" ...
[  58.7] Performing "mail-spool" ...
[  58.7] Performing "net-hostname" ...
[  58.9] Performing "net-hwaddr" ...
[  59.1] Performing "pacct-log" ...
[  59.3] Performing "package-manager-cache" ...
[  60.2] Performing "pam-data" ...
[  60.3] Performing "passwd-backups" ...
[  60.4] Performing "puppet-data-log" ...
[  60.5] Performing "rh-subscription-manager" ...
[  60.7] Performing "rhn-systemid" ...
[  60.9] Performing "rpm-db" ...
[  61.0] Performing "samba-db-log" ...
[  61.2] Performing "script" ...
[  61.2] Performing "smolt-uuid" ...
[  61.3] Performing "ssh-hostkeys" ...
[  61.4] Performing "ssh-userdir" ...
[  61.6] Performing "sssd-db-log" ...
[  61.7] Performing "tmp-files" ...
[  61.8] Performing "udev-persistent-net" ...
[  62.0] Performing "utmp" ...
[  62.1] Performing "yum-uuid" ...
[  62.2] Performing "customize" ...
[  62.4] Setting a random seed
[  62.7] Setting the machine ID in /etc/machine-id
[  62.8] Setting passwords
[  75.4] Performing "lvm-uuids" ...

When the process is complete, your image.qcow2 file will be prepped and ready for upload to OpenStack.

Creating a custom image with VirtualBox

If you favor a graphical user interface, you may wish to use VirtualBox to create your initial image. Broadly speaking, you will… 

  • Use VirtualBox to create a new image from an ISO and install the OS

  • Configure the image to bring it in line with the requirements for an OpenStack image (which should typically involve using virt-sysprep as detailed above)

Both of these steps will vary depending on the target OS. Our guide below will create an Ubuntu Server 22.04.01 image.

Note: If you are attempting the VirtualBox approach on Windows or Mac, you will need a development instance of a Linux environment (we are using Ubuntu 22.04.01 Desktop) with Guest Additions and a Shared Folder enabled.

Step 1: Install VirtualBox

You can find installation instructions for VirtualBox in the End User Manual.

Step 2: Download the operating system

Next you'll need to download the installation ISO for the Linux distribution that you want to create.  In our case, we'll download the Ubuntu Server 22.04.01 ISO for the AMD64 architecture—this is a roughly 1.5 GB download.

Step 3: Create a new VM

Next, open VirtualBox and click New. In the dialog box, click Expert Mode, then choose these values:

Name: ubuntu-server

Type: Linux

ISO Image: <path-to-your-iso>

Version: Ubuntu (64-bit)

Check “Skip Unattended Install.”


Now click on the Hardware dropdown. We’ll give our VM 2048 MB of base memory and 1 CPU.

Next, click on Hard Disk. We’ll give the VM 5GB and put it in QCOW format. (Take note—this is QCOW Version 1, not QCOW2, which is not currently available as an option in VirtualBox.)


Now click Finish.

Step 4: Install the operating system

At this point we essentially have a computer with a blank hard drive. To install the operating system we need to put the virtual CD (the ISO) in the virtual CD-ROM drive and boot it from there to do the OS install. 

Under the Storage section, check to see if your Ubuntu Server ISO file is loaded in the optical drive. If it reads “Empty,” click and select “Choose a disk file,” and select the ISO file you downloaded earlier.



Now we’re ready to boot the VM. Click the green Start button on the VirtualBox Manager screen. A new window will open to serve as a virtual display for our VM, and from here we’ll go through the installation process for our operating system. This process will differ per OS, but you can complete the Ubuntu Server installation as follows:

Update to the new installer if necessary.

Choose the minimized Ubuntu Server installation.

Use the default configuration for an Ethernet connection.

Click Done to proceed through the proxy and Ubuntu archive mirror screens.

On the Guided storage configuration screen, select “Use an entire disk” and “Set up this disk as an LVM group.”


Click Done to move through the Storage configuration screen and click Continue to confirm.

On the Profile setup screen, enter the following details and click Done:

Your name: ubuntu

Your server’s name: ubuntu-server

Pick a username: ubuntu

Choose a password: <your password here>


On the SSH Setup screen, select “Install OpenSSH server” and click Done.


Click Done through the Featured Server Snaps screen and the installation will begin. When it completes, shut down the machine by typing shutdown now or closing the virtual screen and selecting “Power off the machine.”

Step 5: Clean up the image

Locate the QCOW file for your VM by selecting your VM in the main VirtualBox manager, then clicking Settings ->Storage.  Under Storage Devices click the QCOW file and note the Location in the right-hand pane. Copy your ubuntu-server.qcow image to either a Linux machine or a folder shared with a Linux VM. 

Installation via VirtualBox generates an image with data we will need to remove, such as MAC address details. The most standardized way to go about this is using virt-sysprep, per the command line instructions above. 

This time, we will simply sysprep the image without adding a root password—we’re assuming that we’ve made all the necessary configurations we want in VirtualBox, and now we’re simply preparing the image for upload.

From the directory containing the image file, run:

$ sudo virt-sysprep -a ./ubuntu-server.qcow

The output should look like this:

[   0.0] Examining the guest ...
[  55.4] Performing "abrt-data" ...
[  55.5] Performing "backup-files" ...
[  60.0] Performing "bash-history" ...
[  60.1] Performing "blkid-tab" ...
[  60.5] Performing "crash-data" ...
[  60.7] Performing "cron-spool" ...
[  60.9] Performing "dhcp-client-state" ...
[  61.0] Performing "dhcp-server-state" ...
[  61.0] Performing "dovecot-data" ...
[  61.2] Performing "ipa-client" ...
[  61.4] Performing "kerberos-hostkeytab" ...
[  61.6] Performing "logfiles" ...
[  63.8] Performing "machine-id" ...
[  64.0] Performing "mail-spool" ...
[  64.0] Performing "net-hostname" ...
[  64.3] Performing "net-hwaddr" ...
[  64.5] Performing "pacct-log" ...
[  64.8] Performing "package-manager-cache" ...
[  65.2] Performing "pam-data" ...
[  65.3] Performing "passwd-backups" ...
[  65.5] Performing "puppet-data-log" ...
[  65.6] Performing "rh-subscription-manager" ...
[  66.0] Performing "rhn-systemid" ...
[  66.2] Performing "rpm-db" ...
[  66.3] Performing "samba-db-log" ...
[  66.5] Performing "script" ...
[  66.5] Performing "smolt-uuid" ...
[  66.6] Performing "ssh-hostkeys" ...
[  66.7] Performing "ssh-userdir" ...
[  67.0] Performing "sssd-db-log" ...
[  67.2] Performing "tmp-files" ...
[  67.7] Performing "udev-persistent-net" ...
[  67.9] Performing "utmp" ...
[  68.0] Performing "yum-uuid" ...
[  68.2] Performing "customize" ...
[  68.4] Setting a random seed
[  68.7] Setting the machine ID in /etc/machine-id
[  69.2] Performing "lvm-uuids" ...

Our image is currently about 3.5 GB, but we’d like it to be as small as possible for use in OpenStack, so we’ll use a related libguestfs tool called virt-sparsify to eliminate unused disk space on the image, effectively shrinking the file. 

At this step, we can also use the --convert flag to convert from QCOW (Version 1) to QCOW2. In the command below, we run virt-sparsify on our existing image file, specify that we want our new image converted to QCOW2, and define a name for our new image.

$ sudo virt-sparsify ubuntu-server.qcow --convert qcow2 ubuntu-server.qcow2

The output will look like this:

[   0.0] Create overlay file in /tmp to protect source disk
[   0.1] Examine source disk
 100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ 00:00
[  21.9] Fill free space in /dev/sda2 with zero
 100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ 00:00
[ 109.9] Fill free space in /dev/ubuntu-vg/ubuntu-lv with zero
 100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ --:--
[ 140.4] Copy to destination and make sparse
[ 351.5] Sparsify operation completed with no errors.
virt-sparsify: Before deleting the old disk, carefully check that the 
target disk boots and works correctly.

Now you should have a roughly 2.6 GB file called ubuntu-server.qcow2 in your working directory. Copy that file to a location where you can use it to upload to OpenStack. 

You're now ready to upload your image to OpenStack!

Choose your cloud native journey.

Whatever your role, we’re here to help with open source tools and world-class support.

GET STARTED
NEWSLETTER

Subscribe to our bi-weekly newsletter for exclusive interviews, expert commentary, and thought leadership on topics shaping the cloud native world.

JOIN NOW