This post documents the complete process of installing KVM on the management server and building a clean, optimized, minimal Ubuntu 22.04 VM template. This template will serve as the base image for all orchestrated VMs in the lab environment.
1. Install KVM
Install KVM, libvirt, and required virtualization tools:
apt -y install qemu-system-x86 libvirt-daemon-system libvirt-daemon virtinst \
bridge-utils libguestfs-tools libosinfo-bin ovmf qemu-guest-agent \
virt-manager
Ensure VMs auto-start when libvirtd restarts:
nano /etc/default/libvirt-guests
Uncomment and set:
ON_BOOT=start
2. Create a New Ubuntu 22.04 VM
Using virt-manager, create a new VM:
- Name:
ubuntu22 - Disk size: 25 GB recommended
- ISO: Ubuntu Server 22.04
- Kernel: Select Install HWE Kernel
Once installation completes, reboot to begin cleanup and optimization.
3. Remove snapd Completely
Snap is not required for VM workloads; remove it:
snap list
snap remove lxd
snap remove core20
snap remove snapd
apt purge --remove snapd
rm -rf /root/snap/
4. Disable Swap
systemctl list-units | grep swap
systemctl stop swap.target
systemctl disable swap.target
systemctl mask swap.target
swapoff -a
Edit /etc/fstab and comment out any swap entries.
5. Ensure Deterministic Network Interface Names
Force legacy NIC naming (eth0) for automated Netplan provisioning.
Edit:
nano /etc/default/grub
Modify:
GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"
Apply:
update-grub
reboot
After reboot:
rm -f /etc/cloud/cloud.cfg.d/90-installer-network.cfg
Create minimal DHCP config for eth0 only (placeholder file for orchestration later).
Disable cloud-init networking:
echo "network: {config: disabled}" > /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
6. Configure File Descriptor and Process Limits
echo "* hard nofile 65536" >> /etc/security/limits.conf
echo "* soft nofile 65536" >> /etc/security/limits.conf
echo "* hard nproc 65536" >> /etc/security/limits.conf
echo "* soft nproc 65536" >> /etc/security/limits.conf
7. Limit Journal Size
sed -i "s/#SystemMaxFileSize.*/SystemMaxFileSize=512M/g" /etc/systemd/journald.conf
8. Fix resolv.conf to Use systemd-resolved
ln -fs /run/systemd/resolve/resolv.conf /etc/resolv.conf
9. Install Standard Required Packages
apt -y install net-tools rsyslog bc fio iperf3 gnupg2 software-properties-common lvm2 nfs-common jq
10. Clean Up SSH Login Messages
Edit PAM config:
nano /etc/pam.d/ssh
Comment out:
#session optional pam_motd.so motd=/run/motd.dynamic
#session optional pam_motd.so noupdate
#session optional pam_mail.so standard noenv
Disable MOTD news:
echo "ENABLED=0" >> /etc/default/motd-news
11. Disable Unwanted Timer Services
List timers:
systemctl list-units | grep timer
Disable:
systemctl stop apt-daily-upgrade.timer apt-daily.timer fwupd-refresh.timer \
motd-news.timer update-notifier-download.timer update-notifier-motd.timer
systemctl disable apt-daily-upgrade.timer apt-daily.timer fwupd-refresh.timer \
motd-news.timer update-notifier-download.timer update-notifier-motd.timer
systemctl mask apt-daily-upgrade.timer apt-daily.timer fwupd-refresh.timer \
motd-news.timer update-notifier-download.timer update-notifier-motd.timer
12. Disable Unattended Upgrades
systemctl stop unattended-upgrades.service
systemctl disable unattended-upgrades.service
systemctl mask unattended-upgrades.service
13. Disable Ubuntu Advantage Services
systemctl stop ubuntu-advantage-tools
systemctl disable ubuntu-advantage-tools
systemctl mask ubuntu-advantage-tools
14. Disable AppArmor and UFW
These security layers are unnecessary within a trusted, firewalled lab network.
systemctl stop apparmor ufw
systemctl disable apparmor ufw
systemctl mask apparmor ufw
15. Prepare System for Export
Remove unused packages:
apt autoremove --purge -y
Generate SSH key:
ssh-keygen
Set root password:
passwd
Enable root login:
PermitRootLogin yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
Optimize filesystem and compact:
e4defrag /
fstrim -av
dd if=/dev/zero of=/zero.fill bs=1M status=progress
rm -f /zero.fill
fstrim -av
Shutdown:
history -c
shutdown -h now
16. Export the qcow2 Base Image
Use virt-sparsify to compress and generate the reusable base image:
virt-sparsify --compress /var/lib/libvirt/images/ubuntu22.qcow2 /root/kvm-local/ubuntu22/base.qcow2
This final QCOW2 file becomes the VM template used by the automation/orchestration system.