- Posted on
- • Artificial Intelligence
Artificial Intelligence Nested Virtualisation
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Artificial Intelligence Nested Virtualization on Linux: How and Why to Run VMs Inside VMs for AI Workloads
You’ve built a perfect AI lab in a VM… but you need to spin up yet another isolated VM inside it to test drivers, images, or multi-tenant training safely. Or you’re in the cloud and want each teammate to have their own “mini hypervisor” for reproducible experiments—without handing out bare metal. That’s where nested virtualization shines: running a VM (L2) inside another VM (L1), all accelerated by KVM on Linux.
In this article, you’ll learn what nested virtualization is, why it’s valuable for AI/ML, and—most importantly—how to set it up with QEMU/KVM and libvirt. You’ll get distro-agnostic steps with installation commands for apt, dnf, and zypper, along with actionable performance tips and real-world patterns.
What is nested virtualization (and why AI teams care)
Nested virtualization is when a guest VM (L1) itself runs a hypervisor that starts its own guests (L2). With KVM on Linux, that typically means enabling “vmx” (Intel VT-x) or “svm” (AMD-V) inside the L1 guest so it can use KVM acceleration too.
Why it matters for AI:
Reproducible labs: Build golden L1 hypervisor images that spawn clean L2 experiment VMs per run or per user.
Isolation beyond containers: Some experiments need kernel modules, custom kernels, or low-level drivers—hard to do safely in containers.
CI/CD for VM images: Automatically test AI images and drivers (CUDA, ROCm, OpenVINO) across OS variants without needing multiple bare-metal hosts.
Teaching and workshops: One L0 host (or a cloud VM with nesting) can host multiple L1 hypervisors, each with student-owned L2 sandboxes.
Note: There is overhead relative to running a single-level VM. Measure your own workloads and keep the L2 minimal when possible.
1) Prerequisites and host checks
You’ll work with three conceptual layers:
L0: The real hardware (or a cloud VM whose provider enables nested virtualization).
L1: A guest VM running a Linux hypervisor (KVM/libvirt).
L2: A VM inside the L1.
First, confirm your CPU virtualization support on the host you control (L0). For cloud, verify with your provider that nested virtualization is supported on your chosen instance type. Some platforms support it on specific families; always check their docs and enable the feature when creating the instance.
Check CPU flags and KVM:
lscpu | grep -i virtualization
egrep -o 'vmx|svm' /proc/cpuinfo | head -n1
lsmod | grep kvm
If your L0 is Linux you manage (bare metal):
- Enable nested KVM (Intel):
# Temporary (until reboot)
sudo modprobe -r kvm_intel kvm 2>/dev/null || true
sudo modprobe kvm
sudo modprobe kvm_intel nested=1
# Make it persistent
echo "options kvm_intel nested=1" | sudo tee /etc/modprobe.d/kvm.conf
# Verify
cat /sys/module/kvm_intel/parameters/nested
- Enable nested KVM (AMD):
# Temporary (until reboot)
sudo modprobe -r kvm_amd kvm 2>/dev/null || true
sudo modprobe kvm
sudo modprobe kvm_amd nested=1
# Make it persistent
echo "options kvm_amd nested=1" | sudo tee /etc/modprobe.d/kvm.conf
# Verify
cat /sys/module/kvm_amd/parameters/nested
If the module won’t unload because it’s busy, stop libvirt and try again or reboot:
sudo systemctl stop libvirtd
sudo modprobe -r kvm_intel kvm_amd kvm
sudo reboot
2) Install the virtualization stack (L0 and L1)
You’ll install the same base stack on both L0 and L1: QEMU/KVM, libvirt, and optionally virt-manager and OVMF (UEFI). Use your distro’s package manager below.
- apt (Debian/Ubuntu):
sudo apt update
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients virt-manager bridge-utils ovmf cpu-checker
sudo systemctl enable --now libvirtd
sudo usermod -aG libvirt,kvm $USER
newgrp libvirt
- dnf (Fedora/RHEL/CentOS Stream):
sudo dnf groupinstall -y "Virtualization"
sudo dnf install -y virt-manager bridge-utils edk2-ovmf
sudo systemctl enable --now libvirtd
sudo usermod -aG libvirt,kvm $USER
newgrp libvirt
- zypper (openSUSE/SLE):
sudo zypper refresh
sudo zypper install -y qemu-kvm libvirt virt-install virt-manager bridge-utils ovmf
sudo systemctl enable --now libvirtd
sudo usermod -aG libvirt,kvm $USER
newgrp libvirt
Quick checks:
# Ubuntu-based
kvm-ok || true
# Everyone
virsh list --all
3) Create an L1 hypervisor VM that exposes nesting
On L0, create an L1 guest VM and ensure it exposes virtualization features to its own guests. Two ways:
A) virt-install (simple CLI)
# Replace paths, RAM, vCPUs, and ISO to match your environment
virt-install \
--name l1-hypervisor \
--ram 16384 \
--vcpus 8 \
--cpu host-passthrough \
--disk size=120,format=qcow2,bus=virtio \
--cdrom /var/lib/libvirt/boot/ubuntu-24.04-live-server-amd64.iso \
--os-variant ubuntu24.04 \
--network network=default,model=virtio \
--graphics spice
B) libvirt XML (fine-grained control)
After installing the guest OS, edit the L1 domain to explicitly pass CPU features. For Intel:
virsh shutdown l1-hypervisor
virsh edit l1-hypervisor
In the XML, ensure:
<cpu mode='host-passthrough' check='none'>
<feature policy='require' name='vmx'/>
</cpu>
For AMD use svm instead of vmx.
Start the L1:
virsh start l1-hypervisor
Inside the L1, confirm you can see vmx/svm:
egrep -o 'vmx|svm' /proc/cpuinfo | head -n1
lscpu | grep -i virtualization
Now install the virtualization stack inside the L1 as in step 2 (repeat the apt/dnf/zypper commands there).
4) Launch an L2 VM and verify hardware acceleration
Inside the L1:
virt-install \
--name l2-ai-vm \
--ram 8192 \
--vcpus 4 \
--cpu host-passthrough \
--disk size=60,format=qcow2,bus=virtio \
--cdrom /var/lib/libvirt/boot/ubuntu-24.04-live-server-amd64.iso \
--os-variant ubuntu24.04 \
--network network=default,model=virtio \
--graphics spice
Verification methods:
# Inside the L2 after install
lscpu | grep -i virtualization # Should show VT-x or AMD-V
egrep -o 'vmx|svm' /proc/cpuinfo | wc -l # > 0 indicates feature is present
# On the L1, check the domain is using KVM
virsh qemu-monitor-command l2-ai-vm --hmp "info kvm"
If you see “enabled: true” (or equivalent) in the KVM info, you are running KVM-accelerated nested virtualization.
5) Performance and reliability tips for AI workloads
Nested means more layers; a few settings help keep performance predictable.
Use host-passthrough CPU everywhere:
- L0→L1 and L1→L2:
--cpu host-passthroughor the equivalent XML. This exposes host CPU features that toolchains (NumPy/BLAS/ONNX Runtime) can use.
- L0→L1 and L1→L2:
Enable huge pages for memory-heavy training:
# On the host running the VM (L0 for L1 guests, and L1 for L2 guests)
echo 8192 | sudo tee /proc/sys/vm/nr_hugepages
Add to libvirt domain XML:
<memoryBacking>
<hugepages/>
</memoryBacking>
- CPU pinning and NUMA awareness (for consistent latency):
# Example: pin first two vCPUs to pCPUs 0 and 1
virsh vcpupin l2-ai-vm 0 0
virsh vcpupin l2-ai-vm 1 1
# Keep memory local to NUMA node 0
virsh numatune l2-ai-vm --mode strict --nodeset 0
- Fast virtio devices, cache semantics:
- Use virtio for disk and network.
- Consider disk cache “none” for better fsync semantics on databases/checkpointing:
# In disk XML
<driver name='qemu' type='qcow2' cache='none'/>
About GPUs in nested setups:
- Full GPU passthrough to L2 is rarely supported or is highly vendor/platform-specific. A practical pattern is to passthrough or assign the GPU to L1 and run your AI workload there (or in containers inside L1).
- If you need multi-tenant GPU sharing, investigate your vendor’s vGPU/SR-IOV documentation for your platform; expect constraints under nesting.
Security and stability:
- Keep firmware, microcode, and kernel updated across all layers.
- Nested virtualization increases complexity; only enable it where required and disable when not in use.
Real-world patterns you can adopt today
Reproducible AI experiment lab:
- Build a minimal L1 hypervisor image with libvirt + cloud-init.
- Developers boot L1, then use scripts to spin L2 experiments from a golden qcow2 in seconds.
- Archive L2 qcow2 after runs for exact reproducibility.
Driver/stack validation CI:
- Pipeline builds L2 images containing CUDA/ROCm + frameworks.
- Tests run inside L2, while L1 remains stable and disposable.
- Confidently ship VM images to on-prem users.
Training workshops:
- One powerful L0 host (or a cloud VM with nesting enabled) runs several L1 hypervisors.
- Each attendee gets an L2 VM they can break and reset instantly via snapshots.
Troubleshooting quick hits
“KVM acceleration not available” in L2:
- Inside L1, ensure
/proc/cpuinfoshowsvmxorsvm. - In L0→L1 libvirt config, set
<cpu mode='host-passthrough'>and require the right feature. - Confirm nested=1 on L0 kernel module.
- Inside L1, ensure
Permission errors opening /dev/kvm:
ls -l /dev/kvm
groups $USER
sudo usermod -aG kvm,libvirt $USER
newgrp kvm
Module won’t reload:
- Stop libvirt (
sudo systemctl stop libvirtd) and unloadkvm_*modules, or reboot.
- Stop libvirt (
Cloud VM won’t nest:
- Choose an instance type and image that explicitly supports nested virtualization and enable the provider’s nesting flag on creation.
Conclusion and next steps
Nested virtualization lets AI teams build safer, more reproducible, and more flexible environments—without needing many bare-metal hosts. Start small:
1) Enable nested KVM on your host (or pick a cloud VM that supports it).
2) Create an L1 hypervisor VM with host-passthrough CPU and vmx/svm exposed.
3) Spin an L2 VM and validate acceleration.
4) Add huge pages and pinning for performance. Run your first training job.
Call to action: Turn today’s article into a template. Script your L1 and L2 creation with virt-install or libvirt XML, bake cloud-init user data, and share a ready-to-run nested AI lab with your team. Once you’ve got it working, benchmark your model training to tune memory, CPU, and storage for your hardware.