Some notes on how to quickly create VMs in KVM using cloud-image images.

Get the base image. For instance, the actual daily build of 20.04 is:

    wget https://cloud-images.ubuntu.com/focal/20220419/focal-server-cloudimg-amd64.img

Here you can find all of them.

Generate a new disk from this image:

    BASE=focal-server-cloudimg-amd64.img
    sudo qemu-img create -f qcow2 -F qcow2 -o backing_file=$BASE vm.qcow2

Resize it to get some more usable space:

    sudo qemu-img resize vm.qcow2  120G

Create a cloud-init.cfg file with the system configuration:

#cloud-config
users:
  - name: yourusername
    gecos: User Name
    ssh_import_id:
      - gh:Your GitHub Handle
    lock_passwd: false
    passwd: # Your password hash generated with   mkpasswd --method=SHA-512 --rounds=4096
    ssh_authorized_keys:
      - ssh-rsa AA_YOUR_PUBLIC_SSH_KEY
    sudo:  ALL=(ALL) NOPASSWD:ALL
    shell: /bin/bash
hostname: vm
preserve_hostname: false

You can omit the ssh_import_id block, it simply downloads the public keys from GitHub. Similarly, if you omit the ssh_authorized_keys, only password access will be possible.

It’s now time to generate the configuration disk for the VM:

    sudo cloud-localds vm.iso cloud_init.cfg

And to generate the VM:

sudo virt-install \
  --name vm \
  --memory 64000 \
  --disk ./vm.qcow2,device=disk,bus=virtio \
  --disk ./vm.iso,device=cdrom \
  --os-type linux \
  --os-variant ubuntu20.04 \
  --vcpus=32,sockets=1,cores=16,threads=2 \
  --virt-type kvm \
  --graphics spice \
  --network network=default,model=virtio \
  --network type=direct,source=eth0,source_mode=bridge,model=virtio \
  --import \
  --noautoconsole

Adjust the above with your system settings. In this case, I am creating a machine with 32 cores, 64 GB of RAM. The network side is populated both by a NATted interface and by a bridge on the physical network.

You can now connect to it from the host with ssh yourusername@IP, where IP is the one stated in sudo virsh domifaddr --domain vm.