Proxmox, How To Create An Alpine Cloud-Init Image

Dec 10, 2024 · 33 mins read
Proxmox, How To Create An Alpine Cloud-Init Image

In the video below, we show how to create an Alpine Linux Cloud-Init image for Proxmox VE


Now as much as I prefer Debian over other Linux distros, after a while the packages in the repository become out of date

At the time of recording for instance, Debian 12 offers version 4.3.1 of Podman which is 2 years out of date

For other software I’ve used pip and homebrew for instance to get the latest version, but the developers of Podman recommend to use the official repository for installation

Now, Debian 13 is targeting version 5.2.x but it’s still in a state of work-in-progress

And over time that version while become out of date as well

Enter Alpine Linux, which stays up to date

Now although Alpine Linux has cloud-init images, even as of 2024, all but the AWS ones are either in Beta or Alpha

And try as I might, I couldn’t get one to work in Proxmox VE

So how do you create your own cloud-init version of Alpine Linux?

Well if that’s something you’re interested in finding out then stick around and watch this video as that’s what we’ll be going over

Useful links:
https://docs.alpinelinux.org/user-handbook/0.1a/Installing/setup_alpine.html https://wiki.alpinelinux.org/wiki/Upgrading_Alpine https://wiki.alpinelinux.org/wiki/Local_APK_cache https://git.alpinelinux.org/aports/tree/community/cloud-init/README.Alpine https://docs.alpinelinux.org/user-handbook/0.1a/Working/post-install.html https://wiki.archlinux.org/title/Doas https://wiki.alpinelinux.org/wiki/OpenRC https://cloudinit.readthedocs.io/en/latest/reference/base_config_reference.html https://cloudinit.readthedocs.io/en/latest/reference/datasources.html#datasources https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/configuring_and_managing_cloud-init_for_rhel_9/introduction-to-cloud-init_cloud-content#cloud-init-acts-upon-user-data-and-metadata_introduction-to-cloud-init https://www.ibm.com/docs/en/powervc-cloud/2.2.1?topic=aix-custom-powervc-cloud-init-modules https://www.ibm.com/docs/en/rsct/3.3?topic=subsystem-rmc-usage-hmc

Download ISO Image:
Now because we won’t be using a pre-built cloud-init image, the first thing to do is to download a suitable ISO file which you’ll find here

https://alpinelinux.org/downloads/

One of the slimmed down ones intended for virtual systems makes more sense to me, and you’ll find files for various processor architectures under the VIRTUAL section

Typically you’ll want to choose the x86_64 version which is for Intel and AMD 64 bit processors

From a security perspective it makes sense to check the file hasn’t been tampered with so click the SHA256 button next to the file to download the checksum

Once the file’s downloaded you’ll want to upload it to somewhere where at least one of your servers can access

In this demo I’ll upload it to the local storage of a server

To check the file integrity you’ll want to set the Hash algorithm to SHA256 in this case and copy and paste in the checksum

Assuming everything checks out, the file will be uploaded and ready for use

Create VM:
The next thing to do is to create a VM using the ISO image we’ve downloaded

Pick the server in the GUI you want to create a VM on and click Create VM in the top right corner

If this will become a template then you might want to set the VM ID to a higher number so that it stands out and is easier to find

I tend to use 9000 upwards when creating templates but it’s up to you

TIP: Proxmox VE 8.3 introduced a tag view so you could use that as another option

Enter a name, for example, AlpineTemplate then change any other settings you think may be relevant

Now click Next

We want to install the OS from the ISO we just downloaded so from the ISO image drop down menu select that file

Leave the Guest OS settings as is and click Next

You’ll probably want to leave the System settings as is, although I prefer to enable the Qemu Agent option

Unless the OS of a VM doesn’t support the qemu agent, enabling this now means that once the client software is installed, PVE will be able to better understand resource usage in the VM, but it will also be able to shut it down or restart it gracefully

Since Alpine will support the agent, we’ll enable this

Now click Next

The VM needs a hard drive for us to install the OS in and by default this one will given 32GB

Alpine Linux uses very little disk space, so as this won’t become used as a VM I’ll change this to 1GB to save storage space

Any clones I make will have their disk capacity increased as needed

Now click Next

Typically for VMs, I leave Sockets set to 1 and only change the Cores option to decide how many vCPUs a VM should have

Because this is a template, I’ll leave this also set to 1, to show that’s enough to install and run the OS

But you can always set this to a more common amount for future VMs

The type of CPU really depends on the system(s) you’re running

Ideally you should change this to host to get the best performance, but that can be a problem in a cluster where the servers don’t have identical CPUs

Because when the CPUs don’t match, you can’t perform a live migration of a VM from one server to another if the processor in the VM is using an instruction set the CPU on the target server doesn’t have

In addition, you shouldn’t mix different vendor CPUs in a cluster

So if the servers aren’t identical you should instead opt for whichever emulated processor will work on all servers

There are various other settings which are a bit more advanced, so typically you would just click Next

Because this is a template you may want to change the memory settings to a common value you’d expect for clones

I would suggest disabling the Ballooning Device option though as it can lead to performance problems

It only makes sense in labs where RAM is limited because what the hypervisor will do is fool the VM into thinking it has RAM when actually it uses hard drive storage

For instance, lets say a VM has 4GB of RAM but only uses 1GB, well PVE might allocate it 2GB of RAM and 2GB of disk storage

The problem is when the VM suddenly needs 3GB of RAM, PVE has to do a bit of juggling and in the meantime the VM is reading or writing to disk instead of RAM and so the performance suffers

Now click Next

The network settings really depend on your circumstances, but typically you’d only consider changing the Bridge and VLAN Tag

Ones those have been decided, click Next

You can check the summary at the end and if these look fine, click Finish

Install OS:
Power up the VM and connect to it via the console

NOTE: We won’t have access to SPICE and VNC doesn’t support copying and pasting

For the login username enter root, hit return and you’ll be taken to the command prompt as the Live CD has no password

To install Alpine onto the hard drive of the VM, run this command

setup-alpine

This will then take you through a wizard

TIP: The documentation mentions a quick mode, and even hints at using an answer file but that’s beyond the scope of this video

Some of these settings can be left with their default option, some depend on your circumstances, but there are some I’ll draw attention to

When asked for the Hostname, enter the Fully Qualified Domain name, for example

alpinetemplate.homelab.lan

In this example, the computer will be called alpinetemplate and the domain name for my lab is homelab.lan

When selecting an APK Mirror it would be good to enter f and let the computer find the closest mirror to you rather than defaulting to say the first one. This should make it quicker to download future updates

It does take a while mind as there are quite a few options to test against

TIP: You can always repeat or do this later if you prefer by running this command

setup-apkrepos

You’ll be asked after that if you want to create a new user account

TIP: Pay attention! If you want to create a user account, enter the name of the user as the answer. The start of the line implies this is a yes/no question but if you enter yes, guess what, you’ll end up with a user called yes. Doh!

Bear in mind, this user will become a member of the wheel group, as will an account created using cloud-init

And this could become a problem, as we’ll cover later, if you prefer to use sudo

Personally I prefer not to leave accounts on a template VM, other than root obviously for Linux, so I’ll not create a user account

The reason being, every new VM cloned from this one will have this user account installed and it could become compromised somewhere down the line

Even if it didn’t, at later date you may decide to use a different account but your template will be stuck with this one

The benefit of letting cloud-init create a user account is that the account isn’t created until the VM boots up for the first time and runs the cloud-init process

That feels like a better choice to me so we’ll use that method later

In any case, if you do opt to create a user account then doas will be installed

If you’re not familiar with doas, it’s similar to sudo, to gain elevated privilege

You’ll be asked if you want to allow root ssh login and although we don’t have another account yet, I suggest leaving this with the default setting of prohibit-password

You could in theory enter an SSH key for root, but I don’t see that being practical through this console session as we can’t paste into it

When setting up the hard drive, there are various choices

Because this is a basic installation of just the operating system, I’ll opt to set the drive up as a sys drive, although there are other options including encryption

You’ll want to enter y at the end when asked to erase the disk and continue, even though this is a new disk

We’ll then wait for the installation to complete, at which point we then need to reboot the VM as advised

reboot

By default, the VM should boot from the hard drive rather than the CD, but an easy way to tell is that when you login as root, this time you’ll be asked for a password. In addition, the hostname will be want you entered during the installation

Although an ISO image that was just downloaded should be fairly new, we should still make sure everything is up to date

First we’ll update the package information

apk update

If you ever do a major upgrade it’s suggested to upgrade the package manager itself first, so as an example we’ll do that

apk add --upgrade apk-tools
Or
apk add -u apk-tools

Then we’ll upgrade the rest of the software

apk upgrade --available

The –available option forces all packages to be upgraded

Alpine can keep a cache of installed packages on the local disk and the documentation recommends that you synchronise this

sync

We no longer need the CD/DVD drive so first we’ll shut down the VM

poweroff

Now, click on the Hardware section

Select the CD/DVD Drive for this VM and click Remove then click Yes to confirm

Then power this VM back up and login as root again

Remote Access:
At this stage we only have the OS installed and we don’t have access to copying and pasting in the console window

In which case, we’ll setup remote access to the VM via SSH

Now, we only have the root account on this computer, and although it isn’t advised to use that for remote logins, that’s what we’ll be doing as part of this setup process

In which case, it’s best to restrict SSH access to the VM

But the first thing we’re going to do is to install nano

apk add nano

It’s up to you, but for me, vi makes very simple things more complicated than they need to be

Next, we need to edit the repositories file

nano /etc/apk/repositories

We want to allow access to the community repository so delete the # on that line to uncomment it

Now save and exit

Next, we need to update the package information

apk update

Then we’ll install ufw as it provides a simpler frontend for setting up firewall rules

apk add ufw

What we want to do is to only allow SSH access and only from necessary devices

ufw limit proto tcp from 192.168.200.10 to any port 22

We use the limit option in case there’s a device trying to guess login credentials. After a few failed attempts that computer will be blocked from being able to access this one, or at least for a while

The source IP address could be a network although in this case I’ve restricted it to my management computer. You’ll want to change this to whatever is relevant to you

This VM has only one vNIC and it’s using DHCP. We don’t know the IP addresses of future VMs either, so that’s why the destination is set to any

Finally, for SSH the protocol is TCP and the destination port is 22

For this to take effect we need to enable ufw and make sure it starts at boot

ufw enable
rc-update add ufw

NOTE: Updating openrc is necessary on Alpine otherwise ufw won’t start on the next boot, even though the response from the ufw enable command suggests it will

Now we’ll double check that ufw is working and our rule is applied

ufw status

The default behaviour of firewalls is to implicitly drop all other traffic so it should now only allow SSH access and only from where we’ve allowed it

So now, although we’ll be allowing remote root logins, at least this will be restricted to a trusted computer

We now need to allow root login via SSH and there are various ways to do this

The best strategy to modify most config files like this is to add your own override files, rather than modifying the original config file

This is because changes can be introduced to the main file, especially after major updates, and then you’ll have to apply your modifications all over again

By using override files, you can allow the main file to be overwritten by the developer and your own preferences will remain intact

In which case, we’re going to create a new file by doing this

echo 'PermitRootLogin yes' > /etc/ssh/sshd_config.d/permitroot.conf

You can call the file something else, but it has to have an extension of .conf to be included

By adding that file, we’re allowing the root user to login remotely through SSH

First let’s check the file is correct

cat /etc/ssh/sshd_config.d/permitroot.conf

For this to take affect we need to restart the sshd service

service sshd restart

As I’m using DHCP I need to know the IP address of this VM

ip a

Now we should be able to SSH in as root with password authentication, for example

ssh root@192.168.100.20

TIP: If you can’t login, check what methods are being offered by enabling verbose mode

ssh -v root@192.168.100.20

Customisation:
If you’re going to create VMs by cloning an existing one, it makes sense to customise the original one first

This will save you having to repeat the same changes over and over again for every new VM

In which case we’ll install some additional packages

apk add cloud-init util-linux sudo openssh-server-pam e2fsprogs-extra qemu-guest-agent

The cloud-init package allows us to prepare the VM for use with cloud-init

For PVE, we’ll mount the cloud-init config file using an IDE drive, so we also need the util-linux package

Most, if not all of my computers are Debian based and I want to keep things consistent in Ansible, so I’ll install sudo

In the notes, there’s a mention that cloud-init can cause SSH login problems, in which case we’ll also add the openssh-server-pam package

Typically you’ll want to resize the disk of each new VM, but even if you don’t, I’ve noticed cloud-init generates an error relating to resizefs. For an EXT partition, like this VM has, we need to install the e2fsprogs-extra package

As we’re using PVE we’ll also install the qemu-guest agent

We’ll now enable the qemu-guest agent, as we want this to be running all the time

rc-update add qemu-guest-agent

And then we’ll start it

service qemu-guest-agent start

If you check the GUI, you should see in the Summary section of the VM an IPv4 and probably IPv6 address appear which indicates that PVE can now communicate with the guest agent

Now we’ll make another change to sshd, by adding another override file

echo 'UsePAM yes' > /etc/ssh/sshd_config.d/usepam.conf

As before, we need to enable PAM to avoid SSH login problems

For this to take affect we need to restart the sshd service

service sshd restart

Usually this doesn’t drop existing SSH sessions

Feel free to add additional packages that will be common to the VMs you’ll clone from this one

Fail2Ban for instance is a useful way to improve security

And although Debian 13 will phase out ntp in favour of ntpsec, I still prefer to use Chrony as it supports NTS that Cloudflare uses

Personally, though I save software maintenance and configuration for Ansible as it’s an ongoing task that can be better handled through automation

So this basic setup is enough for me

Enable Cloud-Init:
As useful as cloning is, enabling cloud-init brings some additional benefits

For instance, it can change the hostname for you and create a user account with elevated privileges

Before we do anything else though, take a snapshot of the VM though the GUI

This is very important because cloud-init is a one way process

For one thing, we need to do some testing, and having a snapshot will allow us to roll things back to just before cloud-init was enabled

But there’s still some final work to do on this work VM before it becomes our Alpine template

With a snapshot ready, we’ll run the cloud-init software to prepare the computer

setup-cloud-init

Now we need to override the default datasource that cloud-init will use when the VM boots up

echo "datasource_list: ['NoCloud']" > /etc/cloud/cloud.cfg.d/02-datasource.cfg

As before, PVE uses an IDE drive to present the cloud-init config on

All we need to use is the NoCloud option which basically means local provisioning

Now typically, cloud-init images are intended for cloud service providers and there won’t be a monitor attached to such a computer

Although we could switch this display over to a serial console, we’re using Proxmox VE and to me this just adds extra work

Besides, PVE has a limit on how many serial consoles you can have open at once, so we’ll skip that

In which case, we’ll power off the VM

poweroff

Once it’s off, back in the GUI, select the VM and click Hardware

From the Add drop-down menu select CloudInit Drive, select the storage location and click Add

Now click Cloud-Init and edit the settings you want for future VMs

For instance you could add a common user account and password and/or supply an SSH public key for the user

Any new VM that’s cloned from this will then create that user account as part of the cloud-init process

What makes this method preferable, is you can change this on a per VM basis, because the settings won’t be applied until the new VM boots up for the first time

One thing of note is the IP Config setting

By default, PVE has this setup with a blank static address for both IPv4 and IPv6 and that will cause cloud-init to fail, if you don’t enter anything

So for this template VM we’ll change this setting to DHCP

Now, if you want a new VM to have a static IP address, then on the cloned VM, edit this setting BEFORE you power it on

Testing:
The next thing to do is to test if cloud-init works when we clone this VM

So in the GUI, select the VM then right-click and select Clone or from the More drop-down menu in the top right corner select Clone

Set the VM ID and name then click Clone

Once the VM is created, select it and change the Cloud-Init settings if necessary and/or change its hardware settings

We want to watch the progress, so select the Console section for this VM and then power it on by clicking Start or Start Now

Now I have seen warnings about not being able to find a module called cc_reset_rmc

Initially I struggled to find what this was for, but after doing some more searching it appears to be for a Resource Monitoring and Control subsystem for IBM systems

So we could disable this or just ignore it

There is a deprecation warning as well in the ouput but that’s something for the developers to address

If there is a significant problem though, cloud-init will report a failure at the end and you’ll see red asterisks instead of green ones on the left side

First thing to note is that the hostname should match the name we provided when we did the cloning

In contrast, we would have to edit the /etc/hosts and /etc/hostname files if we cloned a normal template

Next we’ll check we can login via the console

If you created a cloud-init user account then use that, otherwise use root

Now, a user account created with cloud-init should have sudo rights, and you can check that with this command

sudo -i

Bear in mind we aren’t prompted for a password which isn’t good for security

The reason being is there is a file created for the user account to grant sudo rights

cat /etc/sudoers.d/90-cloud-init-users

Basically it grants sudo rights for all commands and without the need for a password

This is something that also needs further attention

Also, bear in mind the user account will be a member of adm and wheel as you’ll see when we check with this command

groups david

Where david in this case is the user account I setup in cloud-init

That’s something else you’ll probably want to address as even if sudo rights are removed for this account, it’s still a member of these important groups

Next we’ll want to check UFW was started

ufw status

We also want to check SSH is working, so first we need to know the IP address if we’re using DHCP

ip a

If you setup a non-root account then try connecting through SSH using that, but also test again with the root account

Now if things haven’t gone to plan you’ll have to fix any issues on the original VM, one of the reasons why we took a snapshot

Because the install process goes by so quickly, you can find a lot of useful information in the log file

more /var/log/cloud-init.log

Once you’ve identified any issues, power the clone off then delete it

Next, revert back to the snapshot of the original VM and try and fix the issues that you found

Once again, take a snapshot, then pickup from the point of running the setup-cloud-init command in the previous chapter

Repeat this until you have a working clone

In our case, things seem fine so we’ll power off this test VM

poweroff

And then delete it

Finalise VM:
As we know the cloud-init process is working, now is the time to tidy up and finalise this VM before we start using it

First, revert the VM back to the snapshot taken before cloud-init was setup

Now login as root through SSH

This is the last opportunity to ensure the root account has a strong, complex password, so do that now unless you’ve already done that

passwd

Login as root using another SSH session to make sure the new password works

Assuming it does, then close that session

Being able to resolve a hostname without having to add the domain name is useful so we’ll update the DNS resolver

nano /etc/resolv.conf

Add a new line at the end such as

search homelab.lan

But replace homelab.lan with your own domain name

Now save and exit

The computer will now append that domain name to hostnames allowing the DNS server to find entries it can resolve

Allowing remote root login was only meant to be temporary so we need to disable that by deleting the override file

rm /etc/ssh/sshd_config.d/permitroot.conf

For this to take affect we need to restart the sshd service

service sshd restart

Now try logging in as root using another SSH session to double check that you can’t

To remedy the user account concerns I brought up earlier, we’ll change the cloud-init configuration

Rather than editing the main config file though, we’ll add another override file

nano /etc/cloud/cloud.cfg.d/03-user.cfg

system_info:
  default_user:
   groups: []
   sudo: ["ALL=(ALL) ALL"]
Now save and exit

By adding this file, the user won’t be added to other groups and while it will still have full sudo rights, a password will be required

Now that I know what the cc_reset_rmc module warning relates to I could just ignore it

But instead we’ll comment it out in the main config file

sed -i 's/  - reset_rmc/#  - reset_rmc/' /etc/cloud/cloud.cfg

Now create a new snapshot as we’ll be running one final test

Next, run the cloud-init software

setup-cloud-init

Then add an our override for the datasource

echo "datasource_list: ['NoCloud']" > /etc/cloud/cloud.cfg.d/02-datasource.cfg

Now we’ll power off the VM

poweroff

Once it’s off, back in the GUI, select the VM and click Hardware

From the Add drop-down menu select CloudInit Drive, select the storage location and click Add

Now click Cloud-Init and edit the settings

As before, we’ll add a user account and password and set the IP Config settings to use DHCP

Final Test:
Hopefully this will be our final test but we need to double-check that everything works when we clone this VM

So in the GUI, select the VM then right-click and select Clone or from the More drop-down menu in the top right corner select Clone

Set the VM ID and name then click Clone

Once the VM is created, select the Console section for this new VM and then power it on by clicking Start or Start Now

This time we only expect to see a deprecated warning

Login using the cloud-init account

Again, test this has sudo rights, but this time we should be prompted for a password

sudo -i

We’ll also check the account only belongs to its own group

groups david

UFW should still work, but it’s best to check

ufw status

We also want to check SSH is working, so first we need to know the IP address if we’re using DHCP

ip a

We shouldn’t be able to login as root now, but we should be able to get access using the non-root account

In our case, things seem fine so we’ll power off this test VM

poweroff

And then delete it

Now for some, this might be all you’ll want to do

You have a VM which is cloud-init ready and if you need to update it you can roll it back to the previous snapshot, make your changes and update it

On the other hand, you may prefer to turn this into a template, which is what we’ll cover next

Or maybe you’d prefer to create a cloud-init image. If so, feel free to skip the next chapter

Create Template:
Templates are what a hypervisor admin will probably clone new VMs from

Their main appeal is that you can’t power on a Template

So to me, they’re a read-only virtual machine

Bascially, you can’t add or change the software of the original VM and so you can’t break a “golden” image

For me that’s fine as I install only what’s necessary and let Ansible take care of the rest

And whenever a major OS is released I create a new template anyway because a fresh OS installation is preferable to an upgraded one

A template also makes sense because cloud-init is a one way process

If you did power up this VM, cloud-init would kick in and then you’d run into future cloning issues

You can, however, still make some hardware changes to a template

Now bear in mind, for Proxmox VE, there is no option in the GUI to revert a template back to a VM

However, you can do this from the CLI

qm set <vmID> --template 0

Assuming you do want to turn this VM into a template you have to remove any snapshots applied to it first

Because if you do try to turn a VM with snapshots into a template PVE will just refuse

To do this, select the VM, then either right-click and select convert to template or click on the More drop-down menu and select Convert to template

Now click Yes to confirm

TIP: Once this has completed you may notice the icon next to the name has changed

Going forward, you can clone this Template just like you would a VM

Once a new VM is created, select that and make any necessary cloud-init or hardware changes BEFORE powering it on

Typically you might want to increase the hard disk size, add more vCPUs, more RAM, etc

Once the new VM has powered on and cloud-init has finished, you should test that it works as expected, so login with the non-root account

Now that cloud-init has done its job, we’ll disable it by creating this file

sudo touch /etc/cloud/cloud-init.disabled

All that’s needed is for this file to exist

It’s also a good idea to remove the cloud-init settings from the VM so they can’t be seen “over the shoulder”

First, shut down the VM

sudo poweroff

In the GUI, select the Cloud-Init section for the VM

Reset these back to their defaults

Now click on the Hardware section

Select the CloudInit Drive, click Remove and then click Yes to confirm

You can now power the VM back on and start using it

Create Cloud-Init Image:
As useful as templates are, I prefer to use cloud-init images and let Ansible automate everything

While Ansible could clone a template or VM, cloning multiple new virtual machines and then updating their settings individually is more complicated and takes longer

First, make sure that the VM/template is turned off

Now delete any existing snapshots, although I already did that in the previous chapter

For this method of cloning we’re only interested in the hard drive

In the GUI, select Datacenter and then click storage

Now make a note of the Path/Target for the storage the VM/Template hard drive is stored on

For instance, I have an NFS share and the paths shows as

/mnt/pve/VMS

On the other hand, the path for a VM stored on the local drive will be

/var/lib/vz

In this demo though, the storage for the VM is using ZFS and that stores files in chunks so I’ll have to migrate the hard drive first

To do that I’ll click on the VM then select the Hardware section

Next select the hard drive and from the Disk Action drop-down menu select Move Storage

I’ll then select the new storage location

Depending on what the storage is, you might be able to opt for a format of raw or qcow2

From what I’ve read, raw is better for performance

But it’s probably best to let the system decide, which it does by default

For instance, if you use raw on an NFS storage, you won’t be able to take snapshots of that VM

I do prefer to delete the source drive as to me it just wastes space, so I’ll select that

Finally click Move disk and wait for the process to complete

Now we want to get a copy of this VM’s hard drive

Bear in mind, for me this throws an error message when its trying to set file attributes and it only seems to happen with templates

I don’t get this error when it’s a VM and it doesn’t seem to cause a problem, so I’ll ignore this

To copy the file, first open a shell or SSH into the server that last ran the VM/template

Disk files are stored in the <path>/images/<VMID> folder so first we’ll check what file we need to copy for this VM/template which has an ID of 9002

ls -l /mnt/pve/VMS/images/9002

In this example, I’m interested in this file

base-9000-disk-0.qcow2

This is the hard drive of the template created in the previous chapter

Otherwise it would have looked more like this

vm-9000-disk-0.qcow2

We want a copy of this hard drive and for this demo I’ll store it in the home folder of root, although normally I’d upload it to the Ansible server

We’ll grab a copy of the file and rename it

cp /mnt/pve/VMS/images/9002/base-9002-disk-0.qcow2 my_nocloud-alpine-latest.qcow2

You can put more details in the name if you like but it’s easier for Ansible if the name stays the same

But that’s our cloud-init image ready for use

What I’ll do now is to manually go through the process of creating a new VM

But if you want to know how to create VMs using Ansible and cloud-init images, I’ve made another video about that
https://www.techtutorials.tv/sections/promox/proxmox-create-templates-quicker/

Back in the GUI, we’ll create a basic Linux VM with an ID of 700, without a CD/DVD drive, with the Qemu Agent enabled, without a hard drive, 1 vCPU of type Host, 2GB of RAM without Ballooning and a vNIC in the relevant VLAN

You can of course do this in the CLI if you prefer

Back in our shell or SSH session we’ll import a copy of the hard drive to the new VM

qm importdisk 700 my_nocloud-alpine-latest.qcow2 VMS --format qcow2

Where 700 is the VMID of the new VM and VMS is the storage name to add this to

The –format parameter is because we’re using a file in qcow2 format

Back in the GUI again, select the new VM then click the Hardware section

At the bottom of the list will be an unused disk drive

Select this, click Edit then click Add

From the Add drop down menu, select CloudInit Drive, select the storage location then click Add

Now click the Cloud-init section and update the relevant details

You’ll likely want to add a user account and password as a minimum but remember to update the IP Config settings or cloud-init will fail if it doesn’t have an IP address

Click the Options section, select Boot Order then click Edit

Enable the scsi0 drive then drag it to the top of the list so that the VM boots from the hard drive

Now click OK

We’ll check the progress for this VM, so select the Console section and then click Start or Start Now

What we should see is the same cloud-init process as before

Once the new VM has powered on and cloud-init has finished, you should test that it works as expected

Now that cloud-init has done its job for this VM, as I mentioned in the previous chapter, I prefer to disable it

touch /etc/cloud/cloud-init.disabled

All that’s needed is for this file to exist

It’s also a good idea to remove the cloud-init settings from the VM so they can’t be seen “over the shoulder”

First, shut down the VM

poweroff

In the GUI, select the Cloud-Init section for the VM

Reset these back to their defaults

Now click on the Hardware section

Select the CloudInit Drive, click Remove and then click Yes to confirm

You can now power the VM back on and start using it

Now although this may seem like a slower method than just cloning from a Template, Ansible will do this much quicker, particularly when creating several VMs

Summary:
I must admit, the process for creating an Alpine cloud-init image was rather lengthy and I found that it was prone to errors

It actually took me quite a while to fix various problems along the way, but in the end I now have an image that’s ready

As per Proxmox’s documentation though, creating your own image is a safer method

In any case, what I have now is a more slimline OS that is quicker to boot and has a smaller attack surface

Best of all, this allows me to take advantage of newer versions of packages such as Podman

Sharing is caring!