There are many ways to create virtual machines. In this article, we aim to leverage cloud images as our primary method for automation while provisioning on Proxmox.
Cloud Images
Cloud images are pre-configured disk images designed to be used in virtualized environments, such as cloud infrastructure or virtual machine hosts. These images include minimal operating system installation and are optimized for quick deployment and scalability. They have support for quick configuration tools, we will be using cloud-init for our example.
Script
You’ll need a Proxmox Virtual Environment node with SSH access. In our script, we will perform some actions to download and prepare a cloud image.
Variable and packages
First, we set up some variables and install some useful packages we will be using in the script.
VM_TEMPLATE_ID=999
TEMPLATE_NAME=‘ubuntu-2204-template’
UBUNTU_IMAGE=‘ubuntu-22.04-server-cloudimg-amd64-disk-kvm.img’
UBUNTU_IMAGE_QCOW2=‘ubuntu-22.04.qcow2’
USERNAME=‘cap’
PASSWORD=‘12345’
MEMORY=‘4096’
CPUS=‘2’
apt update -y && apt install nano wget curl libguestfs-tools -y
Idempotency
Run a couple of commands to make our script idempotent. We want a quick way of iteration, so we will be deleting the template in case of changes.
rm -rfv ${UBUNTU_IMAGE}
# remove old template container – WILL DESTROY COMPLETELY
qm destroy ${VM_TEMPLATE_ID} –destroy-unreferenced-disks 1 –purge 1
Download the image:
wget http://cloud-images.ubuntu.com/releases/22.04/release/${UBUNTU_IMAGE}
Customize the image
Add the QEMU guest agent to the image so we don’t need to install it later. Here, you can use virt-customize to add other tools and have them pre-installed on the image.
QEMU guest agent is a daemon installed in the guest and helps us get information about our VMs in the Proxmox environment. See more documentation on PVE docs.
Change image extension
Change the img extension on the image file to QCOW2, if you don’t rename it in some versions of proxmox qemu will not work
Resize
Now we resize the image to a generic size. It doesn’t really matter now; we will configure each clone based on the template later.
Create the vm
Again, the values for resources here are not really important. Set up a generic value for memory and CPU. We are setting up a network interface. Another key configuration is the storage controller; we use virtio-scsi as it covers more use cases. To learn more about virtualization of ‘physical’ devices on the virtio family and emulated storage controllers of the virtio family, go to Virtio
After creating the vm we need to configure and convert to a template, so it can be cloned.
Configure the vm
We will perform in order the following configuration:
Import the image to a disk and attach to the vm
attach a cloud-init drive to the vm via ide interface
Configuring vga output for the console on serial0
Setting up dhcp for the network so we have connection
enabling the qemu agent
seting default user and password
adding ssh keys so we can have ssh access, it will use the same ssh keys from the host in witch you will be executing the script
qm set ${VM_TEMPLATE_ID} –ide2 local-lvm:cloudinit
qm set ${VM_TEMPLATE_ID} –boot order=scsi0
qm set ${VM_TEMPLATE_ID} –serial0 socket –vga serial0
qm set ${VM_TEMPLATE_ID} –ipconfig0 ip=dhcp
qm set ${VM_TEMPLATE_ID} –agent enabled=1
qm set ${VM_TEMPLATE_ID} -ciuser ${USERNAME}
qm set ${VM_TEMPLATE_ID} -cipassword ${PASSWORD}
qm set ${VM_TEMPLATE_ID} –sshkeys ~/.ssh/authorized_keys
Converting to template
In the last step, we convert this VM to a template. A template is a VM with a frozen state used as a base for many machines. It provides a stable starting point and makes it easy for provisioning automation.
The complete script can be found on my homelab github
To run over ssh we can pipe the output via ssh running:
Result should be a template on your Proxmox node
Now you can run any number of copies, we can use qemu set to configure any variable to the clone we want to change from the template.
qm clone ${VM_TEMPLATE_ID} ${VM_ID} –name ${VM_NAME}
# configure the vm
qm set ${VM_ID} –scsi1 local-lvm:40
qm set ${VM_ID} –memory ${MEMORY}
qm set ${VM_ID} –cores ${CPUS}
qm set ${VM_ID} –boot order=scsi0
qm set ${VM_ID} –serial0 socket –vga serial0
qm set ${VM_ID} –ipconfig0 ip=dhcp
qm set ${VM_ID} –agent enabled=1
# start
qm start ${VM_ID}
Running again over ssh should create a new vm based on the template:
Its as fast as it gets, less than 30 seconds and you have a vm running:
Now we know how to create vms based on templates we can explore more options of remote code execution for provisioning.
Socials:
Photo by Arno Senoner on Unsplash