I'm using plain KVM + Libvirt as my hypervisor of choice in my Homelab since it gives me a lot of flexibility, reliability and performance. Installing VMs using traditional installers allows for customizations during install but if all you're doing is quickly spinning up a VM to test something, pre-built Cloud Images are probably a better choice.
The Cloud Images can be customized though before importing them using tools like virt-sysprep or cloud-init.
In this Article, I'll be covering my workflow using virt-sysprep with a Alma Cloud Image although any other cloud image should work.
[root@hyv02 ~]# curl -4 -f -k -L -Z -o '/var/kvm/nfs-vm-templates/almalinux-9-2025-05-22-x86_64.qcow2' -X 'GET' -H 'Accept: application/octet-stream' https://raw.repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-9.6-20250522.x86_64.qcow2
[root@hyv02 ~]# chown root:root /var/kvm/nfs-vm-templates/almalinux-9-2025-05-22.x86_64.qcow2; chmod 600 /var/kvm/nfs-vm-templates/almalinux-9-2025-05-22.x86_64.qcow2
You can now clone the cloud-image and create a new qcow2 image using it as a reference for the new VM:
[root@hyv02 ~]# qemu-img create -b /var/kvm/nfs-vm-templates/almalinux-9-2025-05-22-x86_64.qcow2 -f qcow2 -F qcow2 /var/kvm/nfs-vm-data/almalinux-virt-sysprep.qcow2 10G
This will now create a new Image using the Cloud Image as basis for the ephemeral testing vm.
Now, let's run virt-sysprep to do the following tasks:
- set the hostname
- set the timezone
- set a root password
- create a user and group with custom uid/gid
- modify sudo to allow passwordless sudo for the newly created user
- since we're using a SELinux system, disable SELinux temporarily for firstboot to run
- set a firstboot command to enable selinux, relabel the whole system and reboot
- also inject a few SSH Keys that I would like to add to my user's authorized_keys
[root@hyv02 ~]# virt-sysprep -c 'qemu:///system' --format 'qcow2' --add '/var/kvm/nfs-vm-data/almalinux-virt-sysprep-disk1.qcow2' \
--hostname 'almalinux-virt-sysprep' --timezone 'Europe/Prague' --root-password 'password:provisioned-by-virt-sysprep' --password-crypto 'sha512' \
--run-command 'groupadd -g "10117" archy' \
--run-command 'useradd -m -c "privisioned by virt-sysprep" -d "/home/archy" -g "archy" -s "/bin/bash" -u "10117" archy" \
--run-command 'echo -e "archy ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers.d/archy' \
--run-command 'sed -i /etc/selinux/config -E -e "s/^SELINUX=.*/SELINUX=permissive/g"' \
--firstboot-command 'sed -i /etc/selinux/config -E -e "s/^SELINUX=.*/SELINUX=enforcing/g"; touch /.autorelabel; systemctl reboot' \
--ssh-inject 'archy:string:ssh-ed25519 AAAAC3Nza1...' \
--ssh-inject 'archy:string:ssh-ed25519 AAAAC3Nza2...' \
--ssh-inject 'archy:string:ssh-ed25519 AAAAC3Nza3...' \
--selinux-relabel --colors --no-network
The flags '--network|--no-network' tell virt-sysprep to either enable or disable network connections during sysprepping.
After the command finished, the image is now ready to be imported using tools like virt-install, virt-manager or cockpit-machines.
An Example of installing the VM using virt-install could look like this:
[root@hyv02 ~]# virt-install --import --hvm --noautoconsole \
--connect 'qemu:///system' \
--name 'almalinux-virt-sysprep' \
--memory '1024' \
--vcpus '2' \
--cpu 'host-model' \
--controller 'type=virtio-serial' \
--disk '/var/kvm/nfs-vm-data/almalinux-virt-sysprep-disk1.qcow2,bus=virtio' \
--network 'bridge=br-internal,model=virtio' \
--arch 'x86_64' \
--machine 'q35' \
--os-variant 'almalinux9' \
--rng '/dev/urandom'
This will create a vm named 'almalinux-virt-sysprep' using the disk we just prepared with 1024MB of RAM and 2 CPU Cores. The disk will be attached as VirtIO Device.
Feel free t commend and / or suggest a topic.
Comments
Post a Comment