This is an old revision of the document!

Creating OpenStack VM Image Using Imagefactory

Imagefactory Overview

  • Imagefactory is an open-source tool to automate the building, converting, and uploading images to different cloud providers.
  • It simplify the task of creating new virtual machine images and supports a variety of operating system and cloud providers.
  • It is one of the third-party tools for image creation recommended in OpenStack cloud.
  • Imagefactory uses Oz as a backend tool for automatically installing operating systems into files.
  • Currently supported operating systems in Oz can be found in its homepage. ScientificLinux 6.x is supported.

Install Imagefactory

  • This installation guide was tested on a Scientific Linux 6.4 machine.
  • The OS information of our test platform:
    $ lsb_release -a
    LSB Version:    :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch
    Distributor ID:    Scientific
    Description:    Scientific Linux release 6.4 (Carbon)
    Release:    6.4
    Codename:    Carbon



  • Add EPEL repository:
    $ rpm -Uvh
  • Add Imagefactory repository:
    $ wget -O /etc/yum.repos.d/imagefactory.repo
  • Install the Imagefactory packages:
    $ yum install imagefactory \
    imagefactory-plugins \
    imagefactory-plugins-EC2Cloud \
    imagefactory-plugins-RHEVM \
    imagefactory-plugins-vSphere \
    imagefactory-plugins-MockRPMBasedOS \
    imagefactory-plugins-EC2Cloud-JEOS-images \
    imagefactory-plugins-MockSphere \
    imagefactory-plugins-OpenStackCloud \
  • The versions of packages in our deployment:
    $ rpm -qa | grep imagefactory

Configure Imagefactory

  • As mentioned above, Imagefactory employs Oz to automatically install guest OS into image files. So there are a little things to change to Oz.
  • Prepare a big partition for storing image output from Oz. In our case, we mounted a 400GB partition to /opt/images:
    $ df -h
    Filesystem            Size  Used Avail Use% Mounted on
    /dev/sda5             422G   51G  350G  13% /opt/images
  • Modify image output location in Oz:
    $ vi /etc/oz/oz.cfg
    #output_dir = /var/lib/libvirt/images
    output_dir = /opt/images/libvirt/images
    #data_dir = /var/lib/oz
    data_dir = /opt/images/oz
    screenshot_dir = .
  • Configure Imagefactory, e.g., default image format for Openstack, image directory location:
    $ vi /etc/imagefactory/imagefactory.conf
      "no_ssl": 0,
      "no_oauth": 0,
      "imgdir": "/opt/images/imagefactory/images",
      "ec2_ami_type": "s3",
      "rhevm_image_format": "qcow2",
      "openstack_image_format": "qcow2",
      "clients": { "mock-key": "mock-secret" },
      "proxy_ami_id": "ami-id",
      "max_concurrent_local_sessions": 2,
      "max_concurrent_ec2_sessions": 4,
      "ec2-32bit-util": "m1.small",
      "ec2-64bit-util": "m1.large",
      "image_manager": "file",
      "image_manager_args": { "storage_path": "/opt/images/imagefactory/storage" }

Prepare Imagefactory Files

  • Before using Imagefactory to create images, there are still some more simple steps to go.

Define OpenStack image service endpoint (Glance)

  • Create a json-format file to define OpenStack Glance image service endpoint.
  • You should be able to find your Glance service details on OpenStack dashboard: Access & Security » API Access » API Endpoints » Image
  • Example:
    $ vi /etc/imagefactory/openstack-glance.json
      "glance-host": "",
      "glance-port": 9292

    Remember to replace with your OpenStack Glance server.

Define a provider for OpenStack authN and authZ service (Keystone)

  • Create an xml-format file with your OpenStack user credentials and OpenStack Keystone service endpoint.
  • You should be able to download your OpenStack user credential on OpenStack dashboard by following: Access & Security » API Access » Download OpenStack RC File
  • The Keystone service details can be found on OpenStack dashboard as well: Access & Security » API Access » API Endpoints » Identity
  • Example:
    $ vi /etc/imagefactory/openstack-keystone.xml
    <?xml version="1.0" encoding="utf-8"?>

    Remember to replace username, tenant, password, auth_url with your own details.

Define an image template

  • In the image template (TDL file), you can specify the desired OS type/version, system architecture, root password, OS source, repositories and packages to install, and a list of commands that you wish to run in image creation process.
  • In the os element of TDL file, you have to put in supported operating system and architecture into name, version, arch sub-elements. Since this part of job on automatic operating system installation is actually done by Oz, simply put oz-install in command line to query the information:
    $ rpm -qa oz
    $ oz-install
    Usage: oz-install [OPTIONS] <tdl>
    ....(infomation truncated)....
     Currently supported architectures are:
       i386, x86_64
     Currently supported operating systems are:
       Debian: 5, 6
       Fedora Core: 1, 2, 3, 4, 5, 6
       Fedora: 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18
       Mandrake: 8.2, 9.1, 9.2, 10.0, 10.1
       Mandriva: 2005, 2006.0, 2007.0, 2008.0
       OpenSUSE: 10.3, 11.0, 11.1, 11.2, 11.3, 11.4, 12.1, 12.2
       RHEL 2.1: GOLD, U2, U3, U4, U5, U6
       RHEL/CentOS 3: GOLD, U1, U2, U3, U4, U5, U6, U7, U8, U9
       RHEL/CentOS/Scientific Linux 4: GOLD, U1, U2, U3, U4, U5, U6, U7, U8, U9
       RHEL/CentOS/Scientific Linux{,CERN} 5: GOLD, U1, U2, U3, U4, U5, U6, U7, U8, U9
       RHEL/OEL/CentOS/Scientific Linux{,CERN} 6: 0, 1, 2, 3
       RHL: 7.0, 7.1, 7.2, 7.3, 8, 9
       Ubuntu: 6.06[.1,.2], 6.10, 7.04, 7.10, 8.04[.1,.2,.3,.4], 8.10, 9.04, 9.10, 10.04[.1,.2,.3], 10.10, 11.04, 11.10, 12.04[.1], 12.10
       Windows: 2000, XP, 2003, 7, 2008
  • In all command elements, if you have to use < (less-than sign) or & (ampersand), please use HTML special entities &lt; and &amp; for less-than and ampersand signs to avoid Imagefactory parser error in your custom commands. For more special entities, please see HTML Entities.
  • Now create an image template for Oz to create the image.
  • Example:
    $ vi /etc/imagefactory/sl6.x.tdl
      <description>Scientific Linux 6X x86_64 Image Template</description>
        <install type='url'>
        <!-- You can also install OS from a pre-downloaded local file if you wish.
        <install type='iso'>
        <!-- Put the repositories you wish to add into your guest OS image. -->
        <!-- If you use OpenStack/EC2 cloud, you have an alternative of using user-data script
             to include repositories during VM boot process as part of VM contextualisation.
             We prefer to make the changes to the VM image as little as possible so that the
             image can be reuse as much as we possibly can. Therefore we tend to use user-data
             to introduce the variety and flexibility for VM contextualisation. You may employ
             Puppet for automated service deployment and configuration management on VMs. -->
        <repository name='epel-6'>
        <!-- Put the package names you wish to install into your guest OS image. -->
        <!-- This part can be done via user-data if you use OpenStack/EC2 cloud.
             We tend to not include any package into image but use user-data or Puppet
             instead. See the explanation above in "repositories". -->
        <package name='cvmfs'/>
        <package name='cvmfs-auto-setup'/>
        <package name='cvmfs-init-scripts'/>
        <package name='cvmfs-keys'/>
        <package name='puppet'/>
        <!-- Put the system commands you wish to execute on your guest OS image. -->
        <command name='configure-console'>
          #### Configure console in order for nova console-log to work properly on SL 6.x ####
          # Remove rhgb (redhat graphical boot) and quiet from /boot/grub/grub.conf
          #   rhgb: sets a GUI mode booting screen with most of the information hidden
          #   quiet: hides the majority of boot messages before rhgb starts
          /bin/sed -i 's/ rhgb//g' /boot/grub/grub.conf
          /bin/sed -i 's/ quiet//g' /boot/grub/grub.conf
        <command name='set-timezone'>
          #### Set timezone to UTC ####
          # This is mandatory for Puppet agent to work with our Puppet server.
          /bin/sed -i 's/^ZONE=.*$/ZONE="Etc\/UTC"/' /etc/sysconfig/clock
        <command name='disable-firewall'>
          #### Turn off iptables service ####
          # The cloud security groups or Puppet would take care of access control in our case
          /sbin/chkconfig iptables off
          /sbin/chkconfig ip6tables off
        <command name='disable-autoupdate'>
          #### Disable YUM autoupdate ####
          # We don't want any system auto-update but use Puppet to manage package installation
          # instead.
          /bin/sed -i 's/^ENABLED=.*$/ENABLED="false"/' /etc/sysconfig/yum-autoupdate
        <command name='clean-mac-address'>
          #### Clean up hard-coded MAC address information ####
          # This is mandatory for our VMs to have networking connection on OpenStack cloud.
          /bin/sed -i '/^HWADDR/d' /etc/sysconfig/network-scripts/ifcfg-eth0
          /bin/echo -n > /etc/udev/rules.d/70-persistent-net.rules
          /bin/echo -n > /lib/udev/rules.d/75-persistent-net-generator.rules
          # Make sure the device is started at system bootup
          /bin/sed -i 's/^ONBOOT=.*$/ONBOOT=yes/' /etc/sysconfig/network-scripts/ifcfg-eth0
        <command name='clean-root-password'>
          #### Remove root user's password ####
          # It's highly recommended to remove user' password from the image. But use ssh key
          # to access your VM on cloud instead.
          /usr/bin/passwd -d root
        <command name='fetch-public-key'>
          #### Write a script into /etc/rc.local to fetch public key ####
          # You can replace this part with cloud.init mechanism.
          # Add code into /etc/rc.local file before the line "touch /var/lock/subsys/local"
          # The code is to fetch the SSH public key and add it to the root account
          /bin/sed -i '/^touch \/var\/lock\/subsys\/local/d' /etc/rc.d/rc.local
          /bin/cat >> /etc/rc.d/rc.local &lt;&lt; EOF
    #     Download SSH public key from Openstack Metadata service      #
    # This code only runs ONCE at first boot
    # Fetch public key from metadata service via HTTP
    while [ ! -f /root/.ssh/authorized_keys ] ; do
        wget -O /tmp/openssh-key
        if [ \$? -eq 0 ] &amp;&amp; [ -s /tmp/openssh-key ] ; then
            if [ ! -d /root/.ssh ]; then
                mkdir -p /root/.ssh
                chmod 700 /root/.ssh
            cat /tmp/openssh-key >> /root/.ssh/authorized_keys
            chmod 600 /root/.ssh/authorized_keys
            restorecon /root/.ssh/authorized_keys
            rm -f /tmp/openssh-key
            echo "Successfully retrieved public key from instance metadata, AUTHORIZED KEYS:"
            cat /root/.ssh/authorized_keys
            FAILED=\$((\$FAILED + 1))
            if [ \$FAILED -ge \$ATTEMPTS ] ; then
                echo "Failed to retrieve public key from instance metadata after \$FAILED attempts, quitting..."
            echo "Could not retrieve public key from instance metadata (attempt #\$FAILED/\$ATTEMPTS), retrying in 2 seconds..."
            sleep 2
    touch /var/lock/subsys/local
        <command name='fetch-user-data'>
          #### Write a script into /etc/rc.local to process user data ####
          # Add code into /etc/rc.local file before the line "touch /var/lock/subsys/local"
          # The code is to fetch the user-data script and execute it as part of VM contextualisation.
          /bin/sed -i '/^touch \/var\/lock\/subsys\/local/d' /etc/rc.d/rc.local
          /bin/cat >> /etc/rc.d/rc.local &lt;&lt; EOF
    #     Process user-data fetched from Openstack Metadata service    #
    # This code runs EVERYTIME at every single boot
    # Retrieve user data to a /tmp/user-data file
    wget -O /tmp/user-data
    if [ \$? -eq 0 ] &amp;&amp; [ -s /tmp/user-data ] ; then
        # Check if user-data starts with shebang
        if head -1 /tmp/user-data | egrep -q '^#!' ; then
            # Run user-data
            cat /tmp/user-data | bash
            rm -f /tmp/user-data
    touch /var/lock/subsys/local

Create Image

  • Run the following command using the files you created in previous steps to build an image locally:
    $ imagefactory --verbose target_image --template /etc/imagefactory/sl6.x.tdl /etc/imagefactory/openstack-glance.json
  • The image building process can take a while to finish. It's about 10 minutes in our case.
  • If the image is created successfully, you should be able to see an output in the end of process similar to:
    ....(infomation truncated)....
    ============ Final Image Details ============
    UUID: 6ea2ffa4-fdf9-4dab-9ec5-783d189cef6b
    Type: target_image
    Status: COMPLETE
    Status Details: {'error': None, 'activity': 'Target Image build complete'}

    Keep the UUID information. You will use it for uploading image to OpenStack cloud.

Upload Image

  • The output from previous image creation command has an image UUID. Fill the image UUID (6ea2ffa4-fdf9-4dab-9ec5-783d189cef6b) and the names of files created before (openstack-glance.json and openstack-keystone.xml) in the command below for uploading the image just created to OpenStack cloud:
    $ imagefactory --verbose provider_image --id 6ea2ffa4-fdf9-4dab-9ec5-783d189cef6b openstack-kvm /etc/imagefactory/openstack-glance.json /etc/imagefactory/openstack-keystone.xml
  • If the upload of image was successfully finished, you should be able to see the information in the end of output similar to:
    ....(infomation truncated)....
    ============ Final Image Details ============
    UUID: 232fb27e-ed16-4a03-8e7d-ab6a5fb2594d
    Type: provider_image
    Image ID on provider: 87f1e268-341a-43a8-860a-99963e718c4e
    Status: COMPLETE
    Status Details: {'error': None, 'activity': 'Provider Image build complete'}

Known Issues

  • Disabling SELinux defined in TDL doesn't work. Need further investigation.
    <command name='disable-selinux'>
      #### Turn off SELinux 'enforcing' mode ####
      # The command seems not working with Imagefactory
      /bin/sed -i 's/^SELINUX=.*$/SELINUX=disabled/' /etc/selinux/config
      /usr/sbin/setenforce Permissive

    SELinux is still on enforcing state in the VM instance booted from the image created by Imagefactory.

  • Disabling SSH PasswordAuthentication method defined in TDL doesn't work.
    <command name='disable-ssh-password-auth'>
      #### Disable SSH PasswordAuthentication method ####
      # The command seems not working with Imagefactory
      /bin/sed -i 's/^PasswordAuthentication.*$/PasswordAuthentication no/' /etc/ssh/sshd_config

    PasswordAuthentication is still enabled in the VM instance booted from the image created by Imagefactory.

  • Imagefactory requires user to define a password for root user in the image definition file (TDL). But it will introduce a security concern. If you would like to avoid leaving the root user password in your VM image then remember to add the following command into your TDL to remove root password from your image:
    <command name='clean-root-password'>
      #### Remove root user's password ####
      /usr/bin/passwd -d root
cloud/imagefactory_openstack.1383283945.txt.gz · Last modified: 2013/11/01 16:32 (external edit)
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 4.0 International
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki