Ok, I finally got tired of some of the issues I had with my simple Ubuntu golden image template in Proxmox, and it’s time to setup something a little more permanent and professional. Proxmox has great support for a tool called Cloud-Init. Cloud-init is basically a distro agnostic tool for deploying VMs that auto-populate with individualized data. What the hell do I mean by that? For example, the hostname of the VM. In my current configuration, every VM i create as a clone of my golden image has the same hostname as what I set in the golden image, duh. I would be really nice if each VM I create copied the name of the VM in Proxmox and made that its hostname. Other things that can be changed include the user account credentials, SSH keys, network configurations and IP addresses, and a whole lot more if you want. Cloud-init also makes using other automation tools like Ansible and even CI/CD tools much easier to work with.
In my case, I’m going to keep running Ubuntu. Ubuntu provides Cloud-init images pre-made for us, but you could also make your own, which I will look into later because I would like to try making an Arch image for testing our future custom Arch ISOs.
https://cloud-images.ubuntu.com/
I’ll grab the link to ubuntu-server 20.04 because it is the current LTS
You are most likely looking for the file ending in amd64.img. For this next part, we will need to use shell access to download the image. Once at the shell, wget
the image into your root home.
wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
BashThen, we need a dummy VM that we are going to import this image onto. We can do this either from the GUI or from the shell. The command from the shell will look something like this, but make sure you understand these parameters because your network bridge may be different or that id may already be in use etc…
qm create 9000 --name "ubuntu-2004-cloudinit-template" --memory 2048 --net0 virtio,bridge=vmbr0
BashOne gotcha here is that proxmox only really works with qcow2 or raw images, but we have a .img, so we have to rename it. If you have no other .img files in your root home, you can just do something like:
mv *.img ubuntu-2004-cloudinit.qcow2
BashIn this case, we are lucky, because the .img file is actually encoded as a qcow2 with a different extension, but this may be different for other distro providers.
Now we import that disk into our new VM:
qm importdisk 9000 ubuntu-2004-cloudinit.qcow2 local-lvm
BashAnd tell our vm to actually use it:
The first command creates a new ‘unused disk’ on the vm pointing to our img, which gets imported into our local-lvm storage pool typically with the name vm–disk-0. The second converts the ‘unused disk’ into a ‘hard disk’ of type scsi, and it’s the first scsi device (0).
Finally, we need to add the cloud-init cd-rom image. This can be done from the UI quite easily by clicking on your VM, going to hardware, then clicking on Add->CloudInit Drive… Or you can do this:
qm set 9000 --ide2 local-lvm:cloudinit
BashThen you want to set the VM to boot from the Cloud-Init Hard disk. From the UI, click on the VM, then go to Options, Click on Boot Order, Edit, then deselect anything but the scsi device and move it to the top… Or:
qm set 9000 --boot c --bootdisk scsi0
BashAnd… Some distros, including Ubuntu, require a serial port for some reason:
qm set 9000 --serial0 socket --vga serial0
BashAnother gotcha here. This is all fine and dandy, but you may notice that once you create your VM and try to login with an account with a blank password, you can’t. This is because the server is setup so that if there is no password, you can’t get in. This is actually a fantastic security feature because it enforces the use of SSH keys for administration. One of the fields in CloudInit is the public ssh key. If you are on Linux, it is very easy to set up a public ssh key on your workstation and share it with the VM. Now, you can ssh into all VMs created with this template without a password, but as long as you don’t share that ssh private key, no one else can log in to the server from a shell.
At this point, I need to log into the main VM that will be my template, and do all the previous setup things I did before like installing guest tools and wiping the machine_id. You can also do anything else you want to the base image at this point, and when you are done, just convert to template. Keep in mind that the Hard Disk on this VM is only just over 2Gb. This is actually good, because we can always expand the clones later. I think I will expand it to 3 or 4 gb at the base level though, just for simplicity later.
Ubuntu cloud image actually has the growroot package pre-installed, so no commands are needed on the VM to expand the root partition, therefore no reason to expand it now because it is very easy later.
So I will install the qemu-guest-agent
apt-get install qemu-guest-agent
BashHere you would do whatever else you want to do.
Then we need to wipe any evidence that we were here:
sudo truncate -s 0 /etc/machine-id
sudo rm /var/lib/dbus/machine-id
sudo ln -s /etc/machine-id /var/lib/dbus/machine-id
BashThen, click on options in the VM, and enable QEMU Guest Agent.
And Finally, Convert to Template.