Before you read. A rack used to hold six servers doing six jobs, each one idle most of the time because you had to size it for its busiest hour.
Now it holds one server running six operating systems, each convinced it has a machine to itself. Each has its own kernel, its own disks, its own network card, its own reboot.
How can six operating systems each believe they own hardware that only one of them can be using at any instant?
By being lied to, convincingly, by something underneath them. And the interesting part is where that something lives, because on Linux it is not a separate product sitting below the operating system. It is the kernel you already have.
That fact is why virtualization on Linux looks the way it does, and it is what the first half of this lesson is about. The second half is containers, which solve a related problem in a completely different way, and the difference between them is one you can measure in a single command.
Some words you will need
- hypervisor
- The layer that presents fake hardware to several operating systems and shares the real hardware between them.
- host
- The physical machine and the software running the hypervisor.
- guest
- An operating system running on it, believing it has a machine.
- image
- A file on the host that the guest sees as a disk.
- namespace
- A kernel feature giving a process its own private view of something, process IDs, mounts, the network. What containers are built from.
What breaks without this
You cannot tell what you are on. Diagnosing a “failed disk” differently depending on whether it is a physical drive or a hypervisor volume is the difference between an engineer visit and a console click.
You size things wrong. A guest sees the CPU count it was given, not the host’s, and thin-provisioned disks can promise more space than exists.
You cannot reach the machine you built. VM networking has four modes and three of them produce a guest that works perfectly and cannot be reached from where you are sitting.
Type 1, type 2, and where KVM sits
| Type 1, “bare metal” | Type 2, “hosted” | |
|---|---|---|
| Runs on | The hardware directly | On top of a normal operating system |
| Examples | VMware ESXi, Xen, Hyper-V | VirtualBox, VMware Workstation, QEMU alone |
| Overhead | Lower | Higher |
| Used for | Servers | Desktops, development |
KVM does not fit either box cleanly, and that is the interesting part. KVM is a kernel module. Load it and the Linux kernel becomes a type 1 hypervisor, while remaining an ordinary operating system you can log into and run things on.
So a Linux host with KVM is simultaneously a general-purpose OS and a bare-metal hypervisor, which is why “type 1 or type 2” is a question the exam asks and practitioners argue about. The expected answer is type 1, because the hypervisor is in the kernel with direct hardware access rather than a program running on top of it.
Three names that always appear together and do different jobs:
| Is | Does | |
|---|---|---|
| KVM | A kernel module | Gives the kernel hardware-accelerated virtualization |
| QEMU | A userspace program | Emulates the devices: disks, network cards, display |
| libvirt | A management layer | A stable API and tooling over both, plus virsh |
KVM makes the CPU fast; QEMU pretends to be the hardware around it; libvirt is what you actually type at. Without KVM, QEMU still works by emulating the processor too, which is dramatically slower, and is exactly what happens when you run an x86 image on an ARM machine.
Hardware virtualization must be enabled in firmware. Intel VT-x or AMD-V,
frequently off by default on desktop boards. grep -E 'vmx|svm' /proc/cpuinfo
returns nothing when it is disabled, and the symptom is a VM that runs at roughly
a twentieth of the speed you expected.
Telling where you are
systemd-detect-virt reports what is virtualising the machine. Note that the
command’s exit status is also printed.
This is a script-friendly command, so its exit status has to mean something. Given it runs on a virtual machine here, what status would it return on bare metal?
# Fedora CoreOS 44.20260707.3.1 on a virtual machine, aarch64
$ systemd-detect-virt; echo "exit status $?"; echo "--- what does the firmware call this machine ---"; sudo dmidecode -s system-product-name
apple
exit status 0
--- what does the firmware call this machine ---
Apple Virtualization Generic Platform
systemd-detect-virt is the one-word answer. It names the hypervisor
(kvm, vmware, microsoft, oracle, xen, or here apple) and exits
non-zero on bare metal, which makes it the version to use in a script.
dmidecode -s system-product-name reads what the firmware claims, which is where
the same answer comes from in a more verbose form. On a physical machine it names
the model, and that is what a hardware vendor asks for.
systemd-detect-virt -c answers specifically “am I in a container”, and -v
specifically “am I in a VM”, which matters because you can be in both.
Containers are not small virtual machines
This is the distinction the exam tests and the one worth being precise about.
These captures were taken inside a Debian container running on a Fedora host. What will uname -r report, Debian's kernel or Fedora's?
# Debian 13 (trixie), x86_64
$ echo "--- markers a container leaves for itself ---"; ls -l /run/.containerenv /.dockerenv 2>/dev/null || echo "(no marker file)"; echo "--- and PID 1 is not systemd ---"; cat /proc/1/comm; echo "--- the kernel is the hosts ---"; uname -r
--- markers a container leaves for itself ---
-rw-r--r--. 1 root root 0 Aug 8 02:37 /run/.containerenv
--- and PID 1 is not systemd ---
sh
--- the kernel is the hosts ---
7.1.3-200.fc44.aarch64
Fedora’s. 7.1.3-200.fc44, the fc44 says Fedora 44, reported from
inside a container whose entire userland is Debian 13.
That single line is the whole difference. A container has no kernel of its own. It is a set of processes on the host’s kernel, given private views of the filesystem, the process table, and the network by namespaces, and limited by cgroups. Everything else about it is Debian; the kernel is not, because there is only one.
A virtual machine would report its own kernel version here, because it has one, booted by its own bootloader, on emulated hardware, exactly as in lesson 09.
Two more tells in that output. PID 1 is sh, not systemd: a container’s first
process is whatever it was told to run, and when that exits the container stops.
And /run/.containerenv is a marker Podman leaves for anything that wants to
know; Docker leaves /.dockerenv.
The consequences follow directly from having no kernel:
- A container starts in milliseconds because there is nothing to boot.
- It cannot run a different operating system. A Windows container needs a Windows kernel and therefore a Windows host. A “Linux container on a Mac” is running inside a Linux VM, which is precisely what these captures came from.
- Kernel modules,
sysctlsettings, and the kernel version are the host’s. This is why the earlier lessons on booting and modules could not be captured in a container. - The isolation is weaker, because a kernel bug is a shared kernel bug. A VM boundary is a hardware boundary; a container boundary is a software one.
| Virtual machine | Container | |
|---|---|---|
| Kernel | Its own | The host’s |
| Boots | Yes, seconds to minutes | No, milliseconds |
| Size | Gigabytes | Megabytes |
| Runs a different OS | Yes | Only the same kernel family |
| Isolation | Hardware-enforced | Kernel-enforced |
| Right for | Different OS, strong isolation, legacy | Many instances of one application |
They are not competitors. The normal arrangement is containers running inside virtual machines: the VM gives a hard boundary between tenants and the containers give density and fast deployment inside it. Every managed Kubernetes service is built this way.
If you already administer Linux: the namespaces and cgroups a container is actually made of
“Container” is not a kernel object. There is no container system call. It is a convention built from two independent kernel features, and knowing that explains most container behaviour that otherwise looks arbitrary.
Namespaces give a private view. lsns lists them; each is a separate
mechanism:
pid, its own process table, which is why PID 1 inside isshand the host sees the same process with a different number.mnt, its own mount table, which is whyfindmntinside looks nothing like outside, and why a host filesystem mounted after the container started is invisible to it.net, its own interfaces and routing table. This is what makes port publishing necessary.uts, its own hostname.ipc,user,cgroup,time, the rest.
Cgroups impose limits. CPU shares, memory ceilings, I/O weight. A container
exceeding its memory limit is killed by the OOM killer, and the exit code 137
that people find mystifying is 128 + 9, meaning SIGKILL. systemd-cgtop shows
live usage per cgroup, on containers and on services alike, because systemd units
use the same mechanism.
nsenter joins an existing container’s namespaces from the host, which is how
you debug a container that has no shell in it: nsenter -t <pid> -n ip addr runs
the host’s ip inside the container’s network namespace.
Rootless containers map a range of host UIDs into the container via the user namespace, so root inside is an unprivileged user outside. It removes the “container root is host root if the boundary breaks” problem and costs you some capabilities. Podman defaults to rootless; Docker traditionally does not, which is the substantive security difference between them.
If you already administer Linux: the three network modes, and which one the VM you cannot reach is on
“The VM has no network” is nearly always the VM having exactly the network it was configured for, and the configuration being the wrong one for what you wanted.
| Mode | The VM gets | Reachable from the LAN | Typical use |
|---|---|---|---|
| NAT | A private address, behind the host | No, unless you forward a port | Default. A desktop VM that needs outbound access. |
| Bridged | An address from the LAN’s own DHCP | Yes, it is a peer | A server anybody else has to reach |
| Host-only | A private address, host only | No, and no internet either | Isolated test networks |
| Routed | A LAN-visible address, host routes for it | Yes, with a static route upstream | Uncommon; needs cooperation from the network |
NAT is the default on every hypervisor, and it is the answer to “why can I ssh out of the VM but not into it”. Outbound works because the host translates the source address; inbound has nothing to translate to until you publish a port, which is exactly the mechanism from the firewall lesson, DNAT at prerouting.
Bridged is what a server wants, and it has two requirements people meet the hard way. The physical interface must accept frames for a MAC address that is not its own, which wireless interfaces generally refuse, bridging over wifi usually just does not work, and the failure is silent. And the switch port must allow multiple MAC addresses; port security limiting it to one drops the VM’s traffic and sometimes disables the port entirely.
The diagnostic order when a VM is unreachable:
virsh domiflist myvm # which network is it actually on
ip -brief addr # did it get an address, and from where
bridge link # is the tap device enslaved to the bridge
ip route # does it have a default gateway
An address in 192.168.122.0/24 is libvirt’s default NAT network, and that alone
answers the question. 10.0.2.15 is QEMU’s user-mode networking, which is NAT
implemented entirely in userspace and cannot be reached inbound at all.
And one that looks like a network fault and is not: a VM cloned from a template
carries the template’s MAC address and, on some distributions, a .link or
70-persistent-net.rules file pinning the old interface name. Two clones on one
LAN with one MAC produces intermittent, direction-dependent failures that look like
a switch problem. virt-sysprep exists to strip that state before cloning.
Disk images
A guest’s disk is a file on the host. Which format decides what you can do with it.
| Format | Used by | Notable |
|---|---|---|
raw |
anything | Fastest, simplest, no features |
qcow2 |
QEMU/KVM | Thin provisioning, snapshots, compression |
vmdk |
VMware | |
vhd / vhdx |
Hyper-V, Azure | |
vdi |
VirtualBox |
qemu-img creates and converts them, including between vendors:
qemu-img create -f qcow2 disk.qcow2 40G
qemu-img info disk.qcow2
qemu-img convert -f vmdk -O qcow2 old.vmdk new.qcow2
qemu-img convert between formats is how a machine moves between
hypervisors, and it is worth knowing exists before somebody tells you a VMware
guest cannot be migrated.
Thin provisioning is the qcow2 feature that matters and the one that bites. A 40 GB qcow2 occupies a few hundred kilobytes until the guest writes to it, and grows on demand. So you can create six 40 GB disks on a 100 GB host, which is convenient right up to the day the guests fill them.
The host running out of space pauses every guest at once. Guests do not see a
disk error and handle it gracefully; they see writes stop. qemu-img info
shows the difference between virtual size and actual size, and the sum of the
virtual sizes against the host’s free space is a number worth monitoring.
Networking, and why the VM is unreachable
Four modes. Choosing wrong is the most common reason a new VM works perfectly and cannot be reached.
| Mode | Guest gets | Reachable from the LAN | Use for |
|---|---|---|---|
| NAT | A private address behind the host | No, not without port forwarding | Desktop VMs that only need outbound access |
| Bridged | An address on the real LAN, from its DHCP | Yes, like any other machine | Servers |
| Host-only | A private address, host only | No, and no internet either | Isolated testing |
| Routed | Its own subnet, host forwards | Yes, with routing configured | Segmented networks |
NAT is the default nearly everywhere, which is why this comes up so often. The guest reaches the internet, updates work, everything looks healthy, and nothing on the network can start a connection to it, because it is behind the host’s address on a private network that does not exist outside the host.
Bridged is what a server wants. The guest’s virtual interface is attached to the host’s physical one, it gets an address from the same DHCP server as everything else, and it is an ordinary machine on the LAN.
Two things that catch people with bridging: the host’s physical interface must be enslaved to a bridge, which briefly disconnects the host when you set it up; and some wireless adapters cannot bridge at all, because 802.11 does not carry arbitrary source MAC addresses. On a laptop, bridging over Wi-Fi fails for reasons that have nothing to do with your configuration.
If you already administer Linux: virsh, and what to reach for on a KVM host
virsh is libvirt’s shell, and it is the same commands whether the host is local
or remote (virsh -c qemu+ssh://host/system).
virsh list --all # every guest and its state
virsh start web01 / shutdown / destroy # destroy is a power cut, not a delete
virsh undefine web01 --remove-all-storage # this is the delete
virsh dumpxml web01 # the guest's full definition
virsh edit web01 # edit it, with validation
virsh console web01 # serial console, when the network is gone
virsh net-list --all # the virtual networks
virsh snapshot-create-as web01 pre-upgrade
destroy versus undefine is the trap. destroy stops a running guest
abruptly, the equivalent of pulling the cord, and the guest still exists.
undefine removes the definition. The naming is unfortunate and the exam
likes it.
virsh console is the one worth knowing before you need it. When a
guest’s networking is broken, the serial console still works, which turns “I
have to open the hypervisor GUI” into a command. It needs the guest configured
for a serial console: console=ttyS0 on the kernel command line, which is
lesson 09 arriving again.
Storage pools (virsh pool-list, vol-list) are libvirt’s abstraction over
where images live, so a guest definition does not hardcode a path. Worth using
from the start; retrofitting it is tedious.
virt-install creates guests from the command line and is what belongs in
automation. virt-manager is the GTK interface, and Cockpit gives you a
web console with VM management built in, which is the RHEL-family answer for
people who want a GUI on a headless server.

sudo from lesson 06 with a button instead of a prompt. Captured on this machine.virt-v2v converts a VMware or Hyper-V guest to KVM, including installing the
right drivers, which is a great deal more than qemu-img convert does on its own.
If you already administer Linux: guest agents, overcommit, and the tuning that actually matters
Install the guest agent. qemu-guest-agent in a KVM guest,
open-vm-tools under VMware. Without it the hypervisor cannot request a clean
shutdown, cannot freeze the filesystem for a consistent snapshot, and cannot
report the guest’s IP address. “Shut down” without an agent is a power button
press, and a snapshot without one is a crash-consistent image, which is the
backup consistency problem from lesson 23 in a new costume.
CPU overcommit is fine; memory overcommit is not. Guests are idle most of the time, so allocating more vCPUs than the host has cores is normal and works. Memory is different: a guest that has been given 8 GB will eventually use 8 GB, and when the host cannot supply it something is killed or swapped, which is catastrophic for latency across every guest. Ballooning and KSM reclaim some of it and neither is a licence to promise memory you do not have.
Do not give a guest more vCPUs than it needs. A four-vCPU guest has to be scheduled onto four physical cores at once for some operations, so on a busy host an over-provisioned guest waits longer than a smaller one. This is counter-intuitive and it is one of the more common performance mistakes.
Use virtio drivers for disk and network. Emulated IDE and e1000 exist for compatibility and are much slower. A Linux guest has them built in; a Windows guest needs the driver disk at install time, and a Windows VM that is inexplicably slow is very often running on emulated hardware.
Nested virtualization, running a hypervisor inside a guest, needs enabling
on the host module (kvm_intel nested=1) and is slow. It is why the podman
machine these captures came from cannot itself host VMs, and why this topic
has fewer captures than the others.
Snapshots are not backups, and the reasoning from lesson 23 applies without change: they live on the same storage. A qcow2 snapshot chain also degrades read performance the longer it gets, and a forgotten snapshot from six months ago is a performance problem as well as a space one.
Across distributions
| RHEL family | Debian family | |
|---|---|---|
| Packages | qemu-kvm, libvirt, virt-install |
qemu-kvm, libvirt-daemon-system, virtinst |
| Group for unprivileged use | libvirt |
libvirt, sometimes kvm |
| Images default to | /var/lib/libvirt/images/ |
same |
| Web management | Cockpit, with the VM plugin | Cockpit, packaged separately |
| Container tooling | Podman, default | Docker or Podman |
Podman is the RHEL family’s default and is daemonless and rootless by default, which is a genuine security difference from Docker rather than a branding one: there is no privileged daemon owning every container, and container root is an unprivileged host user.
Prove it
On a machine you have just been given:
# Am I on hardware, in a VM, or in a container
systemd-detect-virt
systemd-detect-virt -c && echo "in a container"
# If it is a VM, what is the hypervisor
sudo dmidecode -s system-product-name
# Can this machine host VMs at all
grep -c -E 'vmx|svm' /proc/cpuinfo
lsmod | grep kvm
# What is running
virsh list --all
qemu-img info /var/lib/libvirt/images/web01.qcow2
grep -c -E 'vmx|svm' /proc/cpuinfo returning 0 is the answer to “why is this
VM so slow”. Hardware virtualization is disabled in firmware and QEMU is
emulating the processor.
What trips people up
1. “Type 1 or type 2” for KVM
Type 1. It is a kernel module, so the hypervisor has direct hardware access, even though the same kernel is also running an ordinary operating system. The ambiguity is real and the exam’s answer is type 1.
2. The VM has an address and nobody can reach it
NAT. The guest is behind the host on a private network, so outbound works and inbound does not.
Switch to bridged for anything that must be reachable, or add port forwarding for
a single service. virsh domiflist <guest> shows which network a guest is
attached to.
3. Thin provisioning ran out
Six 40 GB qcow2 images on a 100 GB host is legal and works until the guests actually write. When the host fills, every guest pauses at once.
qemu-img info shows virtual against actual size. Monitor host free space,
not guest free space. The guests will all report plenty.
4. virsh destroy when you meant to shut down
destroy is an abrupt power-off, not a deletion. It risks filesystem damage in
the guest exactly as pulling the cord would.
virsh shutdown asks the guest to shut down cleanly, and needs the guest agent
installed to work reliably. undefine is the one that deletes.
5. Expecting a container to behave like a VM
No init system, so no systemctl. No separate kernel, so no modprobe and no
sysctl that survives. One foreground process, and when it exits the container
stops.
A container that “will not stay running” is nearly always a process that daemonised itself into the background, leaving PID 1 with nothing to do.
Work it through
You are asked to run a legacy application on a new server. It needs CentOS 7, kernel 3.10, and a specific out-of-tree storage driver. The new host runs a current RHEL-family release. Somebody suggests “just containerise it”.
Reason it out before reading on.
Containers cannot do this, and the reason is specific. A container shares the host’s kernel. The application needs kernel 3.10; the host is running something far newer. There is no configuration that changes this, because the container has no kernel of its own to configure.
The uname -r capture earlier is the proof: a Debian container on a Fedora host
reports Fedora’s kernel. A CentOS 7 container on this host would report the host’s
kernel, and the application would be running on exactly the kernel it cannot run
on.
The out-of-tree driver settles it twice over. Kernel modules are loaded
into the host kernel and are global. A container cannot load one, and if the
host loaded it, it would have to be built for the host’s kernel, which is
lesson 10’s vermagic rule, and which defeats the purpose.
So it needs a virtual machine. Its own kernel, its own module, its own boot.
virt-install --name legacy-app --memory 8192 --vcpus 4 \
--disk path=/var/lib/libvirt/images/legacy.qcow2,size=100,format=qcow2 \
--network bridge=br0 \
--os-variant centos7.0 \
--location /iso/CentOS-7.iso
Bridged, because it is a server other things must reach. qcow2, for
snapshots before you touch anything. --os-variant because it makes libvirt
choose sensible virtual hardware for that guest, and getting it wrong is a common
cause of poor performance.
Then the things that are easy to skip. Install the guest agent so the host can shut it down cleanly and snapshot it consistently. Snapshot before installing the driver. And write down that this guest exists and why, because a CentOS 7 machine is now an unpatched machine and that is a decision somebody should have made deliberately.
Now the point worth extracting. “Containerise it” is a good instinct and the wrong tool here, and the reason is one question: does this workload need its own kernel?
If yes (a different OS, a different kernel version, a kernel module, a real isolation boundary between tenants) it is a virtual machine, and no amount of container tooling changes that.
If no (it is an application that runs on this kernel and you want many of them, started quickly, packaged with their dependencies) it is a container, and a VM is wasteful.
That one question answers it nearly every time, and it is why the uname -r
capture is the most useful thing in this lesson.
Try it
Optional. Most of this needs a machine that can host VMs, which a virtual machine usually cannot.
systemd-detect-virton everything you have access to. Note which report bare metal.grep -c -E 'vmx|svm' /proc/cpuinfo. Zero means hardware virtualization is off in firmware.sudo dmidecode -s system-product-nameand compare with what you expected.- In a container,
podman run --rm -it debian bash, rununame -rand compare it with the host’s. Thencat /proc/1/comm. lsnson a host running containers, and find the extra namespaces.- If you have a KVM host:
virsh list --all, thenqemu-img infoon an image and compare virtual size with actual size.
Verification step. You have it when you can be handed a workload and decide between a container and a VM by answering one question, and say what the question is.
Check yourself
What is the single structural difference between a container and a virtual machine, and name two consequences?
A container shares the host’s kernel; a virtual machine has its own. That is the whole of it, and everything else follows.
Consequences, any two:
Startup time. A container has nothing to boot, so it starts in milliseconds. A VM boots (firmware, bootloader, kernel, initramfs, init) exactly as lesson 09 describes.
Operating system. A container can only run something that works on the host’s kernel. A Windows container needs a Windows host. A VM can run anything.
Kernel modules and sysctl. Both are the host’s. A container cannot load a
module or set a kernel parameter that persists.
Isolation strength. A VM boundary is enforced by hardware; a container boundary is enforced by the kernel, so a kernel vulnerability is a shared vulnerability.
uname -r inside a container proves it: it reports the host’s kernel, not the
container image’s distribution.
Is KVM a type 1 or type 2 hypervisor, and why is the question awkward?
Type 1, and that is the exam’s answer.
It is awkward because KVM does not look like the type 1 examples. It is a kernel module rather than a dedicated product, and the machine running it is also an ordinary Linux system you can log into, run a web server on, and use as a desktop, which sounds exactly like type 2.
The reason it is type 1 anyway: the hypervisor is in the kernel, with direct
hardware access, not a userspace program mediated by an operating system beneath
it. Loading kvm turns the kernel itself into the hypervisor.
Worth keeping the three parts straight: KVM is the kernel module providing acceleration, QEMU is the userspace program emulating the devices, libvirt is the management layer you type at.
A new VM can browse the internet and nothing on the LAN can connect to it. What is the likely cause and the fix?
NAT networking, which is the default in most hypervisors.
The guest sits on a private network behind the host and shares the host’s address for outbound traffic. So outbound works (updates install, DNS resolves, everything looks healthy) and there is no route for anything on the LAN to reach the guest, because its address does not exist outside the host.
The fix is bridged networking, which attaches the guest’s virtual interface to the host’s physical one. The guest then gets an address from the same DHCP server as everything else and behaves like an ordinary machine on the network.
For a single service, port forwarding from the host is a lighter alternative.
Two caveats on bridging: setting up the bridge briefly disconnects the host, so do it with console access; and many wireless adapters cannot bridge at all, so a laptop over Wi-Fi will fail for reasons unrelated to your configuration.
Six 40 GB qcow2 disks on a 100 GB host. What happens, and how do you monitor for it?
It works, until the guests actually write. qcow2 is thin-provisioned: an image occupies only what has been written, so 240 GB of promised disk fits on 100 GB of real disk as long as the guests stay mostly empty.
When the host fills, every guest pauses at once. They do not receive a graceful disk-full error; writes simply stop, and recovering means freeing host space before anything can resume.
Monitor the host’s free space, not the guests’. Every guest will report plenty of room, right up to the moment none of them can write, because each one believes it has 40 GB.
qemu-img info shows virtual size against actual size per image. The number worth
alerting on is host free space against the sum of what is still unwritten.
What is the difference between virsh destroy and virsh undefine?
destroy stops a running guest immediately, the equivalent of pulling the
power cord. The guest still exists and can be started again, and it risks
filesystem damage inside it exactly as a real power cut would.
undefine removes the guest’s definition from libvirt. That is the delete,
and --remove-all-storage takes the disk images with it.
The naming is genuinely poor and the exam likes asking about it.
virsh shutdown is the polite version of destroy: it asks the guest to shut
down cleanly. It needs the guest agent installed to work reliably, which is one
more reason qemu-guest-agent belongs in every guest.
References
Pictures. The Cockpit screenshot was taken on a machine of mine rather than copied from anywhere. Cockpit is free software from the Cockpit project, published at cockpit-project.org under LGPL v2.1 or later, and a screenshot of it carries that licence. The browser chrome is cropped off and it is resized; nothing else is altered.
- virsh(1) - libvirt project. Accessed 2026-08-07.
- libvirt networking - libvirt project. Accessed 2026-08-07.
- qemu-img - QEMU project. Accessed 2026-08-07.
- systemd-detect-virt(1) - Linux man-pages project. Accessed 2026-08-07.
- KVM in the kernel documentation - The Linux Kernel documentation. Accessed 2026-08-07.
- namespaces(7) - Linux man-pages project. Accessed 2026-08-07.
The virsh, qemu-img, and virt-install commands here are from libvirt’s
and QEMU’s own documentation rather than captured, because the podman machine
cannot host virtual machines of its own, nested virtualization is exactly what
this topic explains is unavailable. The detection captures are real. Blocks
without a distribution and architecture header are illustrative.