libvirt - это слой управления, который прячет за собой разные гипервизоры (KVM/QEMU, Xen, LXC) за единым API и единым языком описания. Вместо того чтобы запускать qemu-system-x86_64 с двадцатью ключами руками, вы описываете виртуальную машину один раз в XML, а демон libvirtd собирает из него процесс QEMU, ведёт его жизненный цикл и хранит конфигурацию. В этом уроке разберём, как подключаться к гипервизору, как утилитой virsh определять, запускать и гасить домены, что такое XML-описание домена и как быстро создать ВМ через virt-install и virt-manager.

Как это работает
В терминологии libvirt виртуальная машина называется доменом (domain). Это историческое наследие Xen, но прижилось везде. Домен бывает двух состояний хранения: persistent (постоянный, его XML лежит на диске и переживает перезагрузку хоста) и transient (временный, существует только пока запущен). Команда define создаёт persistent-домен из XML, а create запускает домен сразу, минуя сохранение.
Управляет всем демон. На современных дистрибутивах libvirt с 2020-х идёт по модели modular daemons: вместо одного монолитного libvirtd работают отдельные сокет-активируемые юниты virtqemud, virtnetworkd, virtstoraged и так далее. Монолитный libvirtd.service оставлен для совместимости, но в Debian 13, Ubuntu 24.04 и RHEL 10 по умолчанию активны именно модульные демоны через systemd-сокеты. Практически для вас это значит: virsh подключается к сокету, а нужный демон стартует по требованию.
Точка подключения задаётся URI. Самый важный - qemu:///system: это системный экземпляр, где ВМ запускаются от пользователя qemu (или libvirt-qemu), видны всем и стартуют при загрузке хоста. Есть ещё qemu:///session - персональный экземпляр от вашего пользователя, без root, удобен для разработки, но с ограничениями по сети (только пользовательский слирп/passt). Удалённый хост адресуется через qemu+ssh://user@host/system - libvirt туннелирует свой протокол поверх SSH.
Жизненный цикл домена прямолинеен. start поднимает определённый домен. shutdown шлёт сигнал гостю на корректное выключение через ACPI или гостевой агент - гость сам гасит ОС. destroy - это аналог выдернуть шнур: процесс QEMU убивается мгновенно, данные в полёте теряются. Поэтому destroy не удаляет ВМ, а лишь жёстко её останавливает; путаница здесь стоит людям данных. Полностью убрать persistent-домен из libvirt - это undefine.
Команды и примеры
Установка пакетов. Debian/Ubuntu и RHEL/Fedora различаются именами:
Код: Выделить всё
# Debian 13 / Ubuntu 24.04
apt install qemu-system-x86 libvirt-daemon-system virtinst virt-manager
systemctl enable --now virtqemud.socket virtnetworkd.socket
# RHEL 10 / Fedora 41+
dnf install qemu-kvm libvirt virt-install virt-manager
systemctl enable --now virtqemud.socket virtnetworkd.socket
Код: Выделить всё
virsh -c qemu:///system version
virsh uri # покажет текущий URI подключения
virt-host-validate qemu # PASS по строкам KVM - значит ускорение есть
Код: Выделить всё
virsh list --all
virsh define /etc/libvirt/qemu/web01.xml # создать persistent из XML
virsh start web01
virsh shutdown web01 # мягко, через ACPI/гостевой агент
virsh destroy web01 # жёстко, эквивалент сброса питания
virsh undefine web01 --remove-all-storage # удалить ВМ и её диски
Код: Выделить всё
virsh dumpxml web01 > web01.xml # выгрузить актуальный XML
virsh edit web01 # редактировать в $EDITOR с проверкой
virsh autostart web01 # стартовать при загрузке хоста
Код: Выделить всё
<domain type='kvm'>
<name>web01</name>
<memory unit='MiB'>4096</memory>
<vcpu>2</vcpu>
<os>
<type arch='x86_64' machine='q35'>hvm</type>
<boot dev='hd'/>
</os>
<devices>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/web01.qcow2'/>
<target dev='vda' bus='virtio'/>
</disk>
<interface type='network'>
<source network='default'/>
<model type='virtio'/>
</interface>
<graphics type='spice' autoport='yes'/>
</devices>
</domain>
Быстрое создание через virt-install. Утилита сама генерирует XML и сразу делает define+start:
Код: Выделить всё
virt-install \
--name web02 --memory 4096 --vcpus 2 \
--disk size=20,format=qcow2 \
--os-variant debian13 \
--location http://deb.debian.org/debian/dists/stable/main/installer-amd64/ \
--network network=default --graphics spice
Частые грабли
- Путают destroy и delete. destroy не удаляет ВМ, а жёстко останавливает её. Удаление - это undefine. После undefine без --remove-all-storage диск qcow2 остаётся на хосте занимать место.
- Подключаются к qemu:///session вместо qemu:///system и не понимают, почему ВМ не видно и нет нормальной мостовой сети. Проверяйте virsh uri и привычку экспортировать LIBVIRT_DEFAULT_URI.
- Ждут от modular daemons старого libvirtd. На RHEL 10 и Ubuntu 24.04 включать надо virtqemud.socket, а не libvirtd.service; одновременно их держать нельзя - конфликтуют за сокет.
- Сеть default не активна. После установки virsh net-list --all показывает её inactive; нужно virsh net-start default и virsh net-autostart default, иначе у ВМ нет сети.
- Редактируют XML файлом в /etc/libvirt/qemu и теряют правки: libvirtd перезаписывает файл из памяти. Только virsh edit.
- Забывают про права: для qemu:///system без root нужно состоять в группе libvirt, иначе virsh молча уходит в session-режим.
- Установите пакеты libvirt и virtinst для своего дистрибутива и включите virtqemud.socket. Проверьте virt-host-validate qemu.
- Экспортируйте LIBVIRT_DEFAULT_URI=qemu:///system и убедитесь через virsh uri, что подключение системное.
- Активируйте сеть default: virsh net-start default и virsh net-autostart default.
- Создайте ВМ через virt-install с --os-variant debian13, диском 10 ГБ и сетью default.
- Выгрузите её XML командой virsh dumpxml, найдите блоки disk, interface, os и измените vcpu на 1 через virsh edit.
- Проверьте цикл: virsh shutdown, затем virsh start, затем virsh destroy. Сравните поведение shutdown и destroy.
- Удалите ВМ через virsh undefine --remove-all-storage и убедитесь, что в virsh list --all её больше нет.
- Чем persistent-домен отличается от transient и какие команды virsh их создают?
- В чём разница между shutdown и destroy и почему destroy опасен для данных?
- Что означает URI qemu:///system и чем он отличается от qemu:///session?
- Какие обязательные элементы должен содержать XML-описание домена, чтобы он запустился?
- Почему в 2026 на RHEL 10 включают virtqemud.socket, а не монолитный libvirtd.service?
- Что произойдёт с диском qcow2 после virsh undefine без ключа --remove-all-storage?