Running cloud-images with qemu

Table of Contents

Keywords: qemu cloud images

In this post I will show how to obtain a cloud image and run it with qemu. We will provide a file that is processed by cloud-init to install software in the VM at boot time. We will also redirect requests from the host machine to the guest.

Obtain the image

We are going to save the image to a folder (it is a demo so /tmp/demo is a good place):

mkdir /tmp/demo

wget https://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-amd64-disk1.img -O /tmp/demo/xenial.img

Increase disk size (if you need it):

IMG="/tmp/demo/xenial.img"
qemu-img info $IMG
qemu-img resize $IMG 10G
echo "------------------"
qemu-img info $IMG

Run the image with qemu

These images run cloud-init at boot time and the try to connect to the IP 169.254.169.254 to get initial configuration from the metadata service. As we are not in a cloud environment we need to provide this information with a different datasource.

We create the file user-data:

cd /tmp/demo
cat > user-data << HERE
#cloud-config
chpasswd:
   list: |
     ubuntu:ubu123
   expire: False
HERE

and the file meta-data:

cd /tmp/demo
cat > meta-data << HERE
instance-id: worker
local-hostname: worker
HERE

Then we create an ISO file containing these two files:

cd /tmp/demo
genisoimage -o nocloud.iso -V cidata -r -J user-data meta-data

ls

Finally we can run qemu providing the ISO file:

DIR=/tmp/demo
IMG="$DIR"/xenial.img
sudo qemu-system-x86_64 -m 2048 --enable-kvm \
   --name test1 \
   -vga virtio \
   -cpu host \
   -drive file="$IMG",if=virtio,format=qcow2 \
   -drive file="$DIR"/nocloud.iso,media=cdrom

We can login into the VM using ubuntu and the password provided in the user-data file.

This VM has access to internet and we can install the required software.

Bonus: installing software at boot time

In this example, we are going to modify user-data to install Apache and download static files from a host (using wget). You should provide a host name or IP instead of HOST:

cd /tmp/demo
cat > user-data << HERE
#cloud-config
ssh_pwauth: True
chpasswd:
   list: |
     ubuntu:ubu123
   expire: False

package_update: true

packages:
   - apache2

runcmd:
   - wget http://HOST/public/site.tgz -O /var/www/html/site.tgz
   - tar xzvf /var/www/html/site.tgz -C /var/www/html
   - mv /var/www/html/site/* /var/www/html
   - rmdir /var/www/html/site
HERE

We use the same meta-data file:

cd /tmp/demo
cat > meta-data << HERE
dsmode: local
instance-id: worker
local-hostname: worker
HERE

We also generate the ISO file:

cd /tmp/demo
genisoimage -o nocloud.iso -V cidata -r -J user-data meta-data

We can also generate the static content and upload it to the server: Generación del contenido:

mkdir /tmp/demo/site
cd /tmp/demo/site
cat > index.html << HERE
<html>
   <head>
      <link rel="stylesheet" href="css/site.css"/>
   </head>
   <body>
   <h1 class="header"> Welcome </h1>
   <div id="content">
      <p> This is my site!</p>
   </div>
   </body>
<html>
HERE
mkdir css
cd css
cat > site.css << HERE
.header{
      font-size: 140%;
      margin-left: 20px;
      background: #AFAFAF;
   }
#content{
      margin: 12px;
      background: #9AF19A;
      font-size: 120%;
    }
HERE
cd /tmp/demo
tar czvf site.tgz site
# I assume that HOST runs an HTTP server and a SSH server
scp site.tgz user@HOST:/path/public
rm -rf site/

Finally, we run qemu:

DIR=/tmp/demo
IMG="$DIR"/xenial.img
sudo qemu-system-x86_64 -m 2048 --enable-kvm \
   --name test1 \
   -net user,hostfwd=tcp::8080-:80 \
   -net nic \
   -vga virtio \
   -cpu host \
   -drive file="$IMG",if=virtio,format=qcow2 \
   -drive file="$DIR"/nocloud.iso,media=cdrom

We are providing the parameters -net user,hostfwd=tcp::8080-:80 to redirect requests from port 8080 to port 80 of the guest where apache service should be running.

We can open a browser and try the following address: http://localhost:8080/index.html.

Date: 03/02/2021

Author: Juan Gutiérrez Aguado

Emacs 27.1 (Org mode 9.4.4)

Validate