KVM Headless Lab Provisioner A lightweight, hardware-efficient bash toolset for quickly spinning up and tearing down headless Linux virtual machine labs using KVM/QEMU and cloud-init.
Designed specifically for environments with finite hardware resources (e.g., 8GB RAM, 256GB SSD), this tool maximizes performance by avoiding graphical interfaces (GUIs) and utilizing minimal cloud images. It is ideal for practicing system administration, DevOps pipelines, and infrastructure automation (Ansible).
Features Resource Efficient: Uses minimal cloud images (Debian, Ubuntu, Rocky Linux) and runs completely headless.
Hardware Safeguards: Built-in checks prevent Out-of-Memory (OOM) host crashes by calculating requested vs. available RAM.
Automated Cloud-Init: Automatically injects your host machine's SSH keys and sets up a labadmin user with passwordless sudo access.
Ansible Ready: Automatically queries KVM DHCP leases and generates a ready-to-use inventory.ini file.
Instant Rollbacks: Automatically takes a fresh baseline snapshot immediately upon successful boot.
Clean Teardown: A dedicated script safely destroys VMs, frees up KVM memory, and deletes disk files to reclaim storage space.
Prerequisites This tool is built for Linux hosts (tested on Ubuntu) running KVM. Ensure you have the necessary virtualization tools installed on your host machine before running the scripts:
Bash
sudo apt update sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils qemu-utils cloud-image-utils wget Note: cloud-image-utils is strictly required to generate the cloud-init ISO files using cloud-localds.
Installation & Setup Clone the repository:
Bash
git clone https://github.com/linuxech/virt-lab-builder.git cd virt-lab-builder Make the scripts executable: Before you can run the provisioner or teardown tools, you must grant them execution permissions. Run the following command in the project directory:
Bash
chmod +x lab_init.sh lab_destroy.sh Usage: Provisioning a Lab To build a new lab environment, run the initialization script:
Bash
./lab_init.sh The Provisioning Flow: System Check: The script will detect your available host RAM.
Sizing Prompts: You will be asked to name the lab, choose the number of VMs, and allocate CPU cores, RAM, and Storage per VM.
OS Selection: Choose between Debian 12, Ubuntu 24.04, or Rocky Linux 9. The script will automatically wget the minimal cloud image if it does not already exist locally.
Network Selection:
NAT (Default): VMs are placed on an isolated internal network. Highly recommended for security and efficiency.
Bridged: VMs bypass host routing and pull an IP directly from your local network router. Use with caution.
Execution: The script will clone the disks, generate cloud-init configurations, and boot the VMs in the background.
Output: Once booted, the script outputs the IP addresses and generates an inventory.ini file in your lab directory.
Usage: Tearing Down a Lab When you are finished practicing, use the teardown script to completely wipe the environment and reclaim your hardware resources.
Bash
./lab_destroy.sh You will be prompted to enter the exact Lab Name you provided during initialization.
WARNING: This action is destructive and irreversible. It will:
Force power-off the VMs.
Undefine the VMs and delete all associated snapshots from KVM.
Delete the virtual disks (.qcow2), cloud-init ISOs, and the lab directory from your host filesystem.
Directory Structure By default, the script isolates all lab data within your home directory to keep your filesystem clean:
Plaintext
/labs/
├── base_images/ # Downloaded OS templates (kept permanently to speed up future builds)
│ ├── debian-12-generic.qcow2
│ └── ...
└── / # The working directory for an active lab
├── cloud-init/ # Seed ISOs and user-data files
├── disks/ # The active VM virtual hard drives
└── inventory.ini # Auto-generated Ansible inventory
Security Notes
SSH Keys: The script automatically generates an RSA key pair (/.ssh/id_rsa) if one does not exist on your host. It injects the public key into the VMs via cloud-init. Passwords are disabled by default to comply with standard security practices.
Isolation: It is highly recommended to use the default NAT network type. This keeps intentionally vulnerable or experimental lab configurations hidden from the rest of your local area network.