11 KiB
Virsh
Virtual Machine Management
- Virsh
Before you Begin
- Add yourself to the
qemuandlibvirtgroups:usermod -aG libvirt,qemu ducoterra - Change the images ownership to qemu:
chown -R qemu:qemu /var/lib/libvirt/images - Change the iso ownership to qemu:
chown -R qemu:qemu /var/lib/libvirt/iso - Allow group write access to images:
chmod 770 /var/lib/libvirt/images - Allow group write access to iso:
chmod 770 /var/lib/libvirt/iso - Tell virsh to connect to your root system rather than your user:
export LIBVIRT_DEFAULT_URI='qemu:///system' - Export your editor so virsh knows what to use:
export EDITOR=vim
Connecting to External Servers via SSH
https://libvirt.org/uri.html#ssh-transport
Configuring Aliases
-
Edit
~/.config/libvirt/libvirt.conf -
Add your aliases
uri_aliases = [ "3dserver=qemu+ssh://3dserver/system", ] -
Export the alias:
export LIBVIRT_DEFAULT_URI=3dserver
One-off Connections
export LIBVIRT_DEFAULT_URI='qemu+ssh://user@server/system'
Useful Virsh Commands
# Show node info
virsh nodeinfo
# List OS variants
osinfo-query os
# List all current machines
virsh list --all
# Connect to console VM
virsh console fedora42-test
# Connect to graphical VM
virt-viewer --wait fedora42-test
# Get leased IP Addresses for the default network
virsh net-dhcp-leases default
# Reboot a VM
virsh reboot <domain>
# Shutdown a VM
virsh shutdown <domain>
# Force shutdown a VM
virsh destroy <domain>
# Remove a VM
virsh undefine --nvram <domain>
# Remove a VM including storage
virsh undefine <domain> --nvram --remove-all-storage
Virsh Networking
Create a Virtual Network
Creating a new network will require an XML configuration file. To see the default network's configuration, use
virsh net-dumpxml default > virbr0.xml
To create a dual-stack network, use the following. (Note, I generated a unique local ipv6 address here).
<network>
<name>dual-stack</name>
<forward mode="nat"/>
<domain name="dual-stack"/>
<ip address="192.168.100.1" netmask="255.255.255.0">
<dhcp>
<range start="192.168.100.2" end="192.168.100.254"/>
</dhcp>
</ip>
<ip family="ipv6" address="fd4d:58e7:17f6:1::1" prefix="64"/>
</network>
I've already defined this network in active/software_virsh/dual-stack-dhcp.xml. Install it with
# Define and autostart the network
virsh net-define active/software_virsh/dual-stack-dhcp.xml
virsh net-start dual-stack-dhcp
virsh net-autostart dual-stack-dhcp
# List networks to ensure it created
virsh net-list --all
# Get the UUID of the created network
virsh net-uuid dual-stack-dhcp
Attach a New Virtual Network
export VM_NAME=my_vm
virsh attach-interface \
--type bridge \
--source virbr1 \
--model virtio \
--config \
--live \
--domain ${VM_NAME}
Detach a Virtual Network
# List mac addresses of connected interfaces'
export VM_NAME=my_vm
virsh domiflist --domain $VM_NAME
virsh detach-interface --domain k0s-worker0 --type bridge --mac "52:54:00:f6:b9:83" --live
Destroy a Virtual Network
export NETWORK_NAME=mynetwork
virsh net-undefine --network $NETWORK_NAME
virsh net-destroy --network $NETWORK_NAME
Set a Static IP
To set a static IP, run virsh net-edit default and add the following between <dhcp> and </dhcp>
# Add a host
virsh net-update default add-last ip-dhcp-host \
'<host mac="52:54:00:6f:78:f3" ip="192.168.122.222"/>' \
--live --config --parent-index 0
# Modify a host
virsh net-update default modify ip-dhcp-host \
'<host mac="52:54:00:6f:78:f3" ip="192.168.122.222"/>' \
--live --config --parent-index 0
# Delete a host
virsh net-update default delete ip-dhcp-host \
'<host mac="52:54:00:6f:78:f3" ip="192.168.122.222"/>' \
--live --config --parent-index 0
Creating VMs
If you have an osbuild image you can run the following to generate a qcow2 disk image. Then you can create a VM with an existing qcow2 disk and skip the installation process altogether.
sudo systemctl start osbuild-composer.socket
composer-cli compose list
export IMAGE_UUID=
export VM_DISK_PATH=/var/lib/libvirt/images/fedora43-test.qcow2
composer-cli compose image --filename ${VM_DISK_PATH} ${IMAGE_UUID}
Create VM with No Graphics and use an Existing QCOW2 Disk
# Start the default network if it isn't already
virsh net-start --network default
export VM_NAME="fedora43-test"
export VM_DISK_PATH=/var/lib/libvirt/images/fedora43-test.qcow2
# OPTIONAL: export your qcow2 disk now if using osbuild
export IMAGE_UUID=
composer-cli compose image --filename ${VM_DISK_PATH} ${IMAGE_UUID}
# Install
# `--location /path/to/image.iso` supplies a disk installer. (Remove `--import`)
# `--import` skips the installation process.
# `--graphics spice --video qxl,model.ram=131072,model.vram=131072,model.vgamem=131072 --channel spicevmc` installs graphics
# `--console pty,target.type=virtio` adds a console connection
# For any command, use `virt-install --arg=?` to see all available options
virt-install \
--name "${VM_NAME}" \
--boot uefi,firmware.feature0.name=secure-boot,firmware.feature0.enabled=no \
--cpu host-passthrough --vcpus sockets=1,cores=8,threads=2 \
--ram=8192 \
--os-variant=fedora41 \
--network bridge:virbr0 \
--graphics none \
--console pty,target.type=virtio \
--import --disk "path=${VM_DISK_PATH},bus=virtio"
Create a Cloud Init Compatible VM
https://cloudinit.readthedocs.io/en/latest/reference/examples.html
# Fedora
# https://fedoraproject.org/cloud/download
export VM_NAME="cloud-init-test-fedora"
export VM_DISK_PATH=/var/lib/libvirt/images/Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2
# Rocky
# https://rockylinux.org/download
export VM_NAME="cloud-init-test-rocky"
export VM_DISK_PATH=/var/lib/libvirt/images/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2
# Ubuntu
# https://cloud-images.ubuntu.com/noble/current/
export VM_NAME="cloud-init-test-ubuntu"
export VM_DISK_PATH=/var/lib/libvirt/images/noble-server-cloudimg-amd64.img
# Debian
# https://cloud.debian.org/images/cloud/trixie/20251117-2299/
export VM_NAME="cloud-init-test-debian"
export VM_DISK_PATH=/var/lib/libvirt/images/debian-13-generic-amd64-20251117-2299.qcow2
# Set --cloud-init disable=no to allow cloud-init to run again after first boot
virt-install \
--name "${VM_NAME}" \
--boot uefi,firmware.feature0.name=secure-boot,firmware.feature0.enabled=no \
--cpu host-passthrough --vcpus sockets=1,cores=8,threads=2 \
--ram=8192 \
--os-variant=fedora41 \
--network bridge:virbr0 \
--graphics none \
--import --disk "path=${VM_DISK_PATH},bus=virtio" \
--cloud-init disable=yes,user-data="active/software_virsh/cloud-init/user-data,meta-data=active/software_virsh/cloud-init/meta-data"
Create VM with Graphics using an ISO Installation Disk
# `--cdrom /path/to/image.iso` supplies a disk installer. (Remove `--import`)
# `--import` skips the installation process.
# `--graphics spice --video qxl --channel spicevmc` installs graphics
# `--console pty,target.type=virtio` adds a console connection
# For any command, use `virt-install --arg=?` to see all available options
export VM_NAME="fedora43-kinoite-test"
export VM_ISO_PATH=/var/lib/libvirt/iso/fedora43.iso
export VM_DISK_PATH=/var/lib/libvirt/images/fedora43.qcow2
virt-install \
--name "${VM_NAME}" \
--boot uefi,firmware.feature0.name=secure-boot,firmware.feature0.enabled=no \
--cpu host-passthrough --vcpus sockets=1,cores=8,threads=2 \
--ram=8192 \
--os-variant=fedora41 \
--network bridge:virbr0 \
--graphics spice --video virtio --channel spicevmc \
--cdrom ${VM_ISO_PATH} \
--disk "path=${VM_DISK_PATH},size=64,bus=virtio,format=qcow2"
Create VM using Host Device as Disk
# `--cdrom /path/to/image.iso` supplies a disk installer. (Remove `--import`)
# `--import` skips the installation process.
# `--graphics spice --video qxl --channel spicevmc` installs graphics
# `--console pty,target.type=virtio` adds a console connection
# `--hostdev 0x1234:0x5678` adds a block storage device
# For any command, use `virt-install --arg=?` to see all available options
export VM_NAME="usb-linux"
virt-install \
--name "${VM_NAME}" \
--boot uefi,firmware.feature0.name=secure-boot,firmware.feature0.enabled=no \
--import \
--cpu host-passthrough --vcpus sockets=1,cores=8,threads=2 \
--ram=8192 \
--os-variant=fedora41 \
--network bridge:virbr0 \
--graphics spice --video qxl --channel spicevmc \
--hostdev 0x13fe:0x6500,boot.order=1 \
--disk none
Snapshots
Virt Builder
You can use virt-builder to build vm images
export VM_NAME=fedora42-vb
export VM_DISK_PATH=/var/lib/libvirt/images/fedora42-vb.qcow2
# Build the image
virt-builder fedora-42 \
--format qcow2 --output ${VM_DISK_PATH} \
--root-password locked:disabled \
--hostname ${VM_NAME} \
--selinux-relabel \
--firstboot-command 'useradd -m -G wheel -p "" ducoterra ; chage -d 0 ducoterra'
# Run the built image
virt-install \
--name "${VM_NAME}" \
--cpu host-passthrough --vcpus sockets=1,cores=8,threads=2 \
--ram=8192 \
--os-variant=fedora41 \
--network bridge:virbr0 \
--graphics none \
--console pty,target.type=virtio \
--import --disk "path=${VM_DISK_PATH},bus=virtio"