Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Create Ubuntu 20.04 KVM Guest From Cloud Image

Similar Posts

Steps

Download the Ubuntu 20.04 server cloud Image and rename to qcow2 to save confusion.

sudo mkdir /var/lib/libvirt/images/templates
wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img

sudo mv -i focal-server-cloudimg-amd64.img \
  /var/lib/libvirt/images/templates/ubuntu-20-server.qcow2

We need to ensure we have cloud-utils and whois packages for later.

sudo apt update && sudo apt install cloud-utils whois -y

The cloud-utils package is required for Debian 10 to be able to run the cloud-localds command, and the whois package is required for us to be able to run mkpasswd later. Your distro may have a different name for the required packages.

Steps

First, pick a name for your new VPS, and what you would want the username/password combo to be for the default user that will be set up:

VM_NAME="ubuntu-20-cloud-image"
USERNAME="programster"
PASSWORD="thisIsMyPassword"

Create an area for our new VM and copy the template cloud image into it, which will be used by the new VM.

sudo mkdir /var/lib/libvirt/images/$VM_NAME \
  && sudo qemu-img convert \
  -f qcow2 \
  -O qcow2 \
  /var/lib/libvirt/images/templates/ubuntu-20-server.qcow2 \
  /var/lib/libvirt/images/$VM_NAME/root-disk.qcow2

Increase the disk size to whatever you want for the VM, in this case I'm setting 20 GB

sudo qemu-img resize \
  /var/lib/libvirt/images/$VM_NAME/root-disk.qcow2 \
  20G

Create a cloud-init configuration so we can set the password and the hostname etc.

sudo echo "#cloud-config
system_info:
  default_user:
    name: $USERNAME
    home: /home/$USERNAME

password: $PASSWORD
chpasswd: { expire: False }
hostname: $VM_NAME

# configure sshd to allow users logging in using password 
# rather than just keys
ssh_pwauth: True
" | sudo tee /var/lib/libvirt/images/$VM_NAME/cloud-init.cfg

The default user to log in with will be ubuntu. I tried and failed many times to set the default user name to something else. If you need to further customize your VM on first setup, there are plenty of online cloud config examples.

Create the ISO file from the cloud config file we just created:

sudo cloud-localds \
  /var/lib/libvirt/images/$VM_NAME/cloud-init.iso \
  /var/lib/libvirt/images/$VM_NAME/cloud-init.cfg
sudo virt-install \
  --name $VM_NAME \
  --memory 1024 \
  --disk /var/lib/libvirt/images/$VM_NAME/root-disk.qcow2,device=disk,bus=virtio \
  --disk /var/lib/libvirt/images/$VM_NAME/cloud-init.iso,device=cdrom \
  --os-type linux \
  --os-variant ubuntu19.04 \
  --virt-type kvm \
  --graphics none \
  --network network=default,model=virtio \
  --import

The --os-variant is listed as ubuntu19.04 because Debain 10 does not have ubuntu20.04 in the list outputted from running sudo osinfo-query os (which I could only run after installing the libosinfo-bin package).

After running the previous command, you will be taken to the login screen in the console, which you can log in with using the username and password you specified at the start of this tutorial.

If you need to get out of the console just press ctrl + ].

Cleanup

After that, it's probably a good idea to cleanup so raw passwords aren't lying around.

sudo rm /var/lib/libvirt/images/$VM_NAME/cloud-init.iso \
  && sudo rm /var/lib/libvirt/images/$VM_NAME/cloud-init.cfg

Hostname And Hosts File

It appears that setting the hostname in the cloud-init config will set the hostname that the machine will boot as. However, it will not add the entry to the /etc/hosts file, so you may wish to do this quickly to prevent your machine taking unnecessarily long when performing some operations. Alternatively, you may figure out how to update the cloud-init.cfg file to update the hosts file correctly using the Etc hosts module.

A Note About Cloning

If you later decide to clone the VM you just spun up, in order to create a new guest, be aware that the /etc/netplan/50-cloud-init.yaml file will have a hardcoded mac address in there to match. E.g.

network:
    ethernets:
        enp1s0:
            dhcp4: true
            match:
                macaddress: 52:54:00:c2:9e:bc
            set-name: enp1s0
    version: 2

Before you create the clone, change the "template" VM to remove the match line and the two below it to become:

network:
    ethernets:
        enp1s0:
            dhcp4: true
    version: 2

This way, when the new guests are created with new, random mac addresses, their network will still work.

References

Last updated: 19th July 2021
First published: 26th June 2021