Automating VM Provisioning with Bash, Kickstart & PXE

July 19, 2026 ยท Ahmad M. Waddah ยท 19 reads

๐Ÿงฉ Stack: Bash ยท KVM/QEMU ยท Kickstart ยท PXE ยท Linux


โ“ The Problem

Setting up a KVM virtual machine manually involves:

  • Creating the disk image
  • Installing the OS (click through the installer)
  • Configuring networking, SSH, users
  • Applying baseline security
  • Installing required packages

For one VM, it's tedious. For a dozen, it's unsustainable.


๐Ÿ› ๏ธ The Solution: Modular Bash Architecture

The automation tool is organised as a set of specialised Bash modules:

kvm-spin-ups/
โ”œโ”€โ”€ kvm-spin-up.sh          # Entry point โ€” parses args, orchestrates
โ”œโ”€โ”€ lib/
โ”‚   โ”œโ”€โ”€ disk.sh             # qemu-img, disk sizing, storage pools
โ”‚   โ”œโ”€โ”€ network.sh          # bridge setup, NAT, port forwarding
โ”‚   โ”œโ”€โ”€ install.sh          # kickstart integration
โ”‚   โ”œโ”€โ”€ post-install.sh     # SSH keys, users, security hardening
โ”‚   โ””โ”€โ”€ validate.sh         # Pre-flight checks
โ””โ”€โ”€ templates/
    โ”œโ”€โ”€ minimal.ks          # Minimal kickstart config
    โ”œโ”€โ”€ server.ks           # Server with LAMP stack
    โ””โ”€โ”€ docker-host.ks      # Docker-ready VM

๐Ÿ“„ Kickstart for Unattended OS Installation

# install.sh โ€” generates kickstart config dynamically
generate_kickstart() {
    local hostname=$1
    local disk=$2
    cat > /tmp/"${hostname}".ks <<EOF
#version=RHEL8
text
url --url="http://mirror.centos.org/8/BaseOS/x86_64/os/"
lang en_US.UTF-8
keyboard us
timezone UTC --isUtc
rootpw --locked
user --name=deploy --groups=wheel --password=${DEFAULT_PASS}
# Disk layout
clearpart --all --initlabel
autopart --type=lvm
# Minimal package set
%packages
@core
openssh-server
vim
%end
%post
systemctl enable sshd
echo "deploy ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/deploy
%end
EOF
}

๐Ÿš€ Automation Flow

# kvm-spin-up.sh
main() {
    validate_env          # Check KVM, libvirt, permissions
    generate_kickstart    # Create OS config
    create_disk           # qemu-img create -f qcow2
    launch_vm             # virt-install with kickstart
    wait_for_boot         # Poll SSH until ready
    run_post_install      # Security, packages, monitoring
    print_summary         # IP, credentials, next steps
}

A single command replaces 45 minutes of manual work:

./kvm-spin-up.sh --name web-01 --ram 4096 --cpus 4 --disk 50G --template server

๐Ÿ“ˆ Results

Step Manual Automated
OS installation 25 min (clickthrough) 3 min (unattended)
Network config 5 min automatic
Security hardening 10 min 30 seconds
Total per VM ~45 min ~5 min
10 VMs 7.5 hours 50 minutes

๐Ÿ’ก Key Takeaways

  • Kickstart turns OS installation into a config file โ€” reproducible and version-controlled
  • Modular Bash (one task per file) keeps the codebase maintainable as it grows
  • Pre-flight validation catches missing dependencies before they fail mid-way
  • This approach works for any libvirt-compatible hypervisor โ€” not just KVM

๐Ÿ”— See the full tool at KVM Spin Ups.