В прошлой части мы научились описывать домен и управлять его жизненным циклом. Но виртуальная машина без диска и без сети - это просто кусок выделенной памяти. В этом уроке разбираем две подсистемы libvirt, которые дают домену тело и связь с миром: виртуальные сети (NAT, bridged, isolated, routed) и пулы хранилищ (dir, LVM, iSCSI). Научимся создавать их через virsh, ставить на автозапуск и горячо подключать диски и интерфейсы к работающей машине. Это ровно тот набор, который спрашивают на 305-300.

Как это работает
Виртуальная сеть libvirt - это не магия, а связка из нескольких хорошо известных кирпичей Linux. В центре стоит программный мост (Linux bridge, обычно virbr0), к которому подключаются виртуальные интерфейсы доменов через драйвер tap. libvirt поднимает мост, вешает на него адрес и запускает отдельный экземпляр dnsmasq, который раздаёт гостям IP по DHCP и резолвит локальные имена. Сам трафик наружу режется правилами фаервола.
Режим сети определяет, как пакет выходит за пределы моста. В NAT (по умолчанию) libvirt добавляет правила маскарадинга, и гости ходят в интернет под адресом хоста - внешний мир их не видит. В режиме routed маскарадинга нет: пакеты маршрутизируются как есть, поэтому хосту нужна настоящая маршрутизация подсети гостей и согласие соседнего роутера. Isolated - это мост вообще без выхода наружу, только гость-гость и гость-хост. А bridged - это когда домен цепляется напрямую к физическому мосту хоста и оказывается в той же L2-сети, что и сам хост, получая адрес от внешнего DHCP.
Важная деталь 2026: в современных RHEL 10 и Fedora 41+ libvirt по умолчанию управляет фаерволом через nftables (драйвер firewalld тоже на nftables), а старый бэкенд iptables считается легаси и часто вообще не установлен. На Debian 13 и Ubuntu 24.04 поведение схожее, хотя там встречается и прямое управление nft. Команды virsh от бэкенда не зависят - меняется лишь то, чем именно libvirt пишет правила под капотом.
Хранилище в libvirt устроено двухуровнево: пул (storage pool) - это источник места, том (volume) - конкретный кусок внутри пула, который виден домену как диск. Тип пула задаёт, откуда место берётся. dir - просто каталог с файлами образов (qcow2/raw). logical - это LVM: пул соответствует volume group, а тома - это логические тома (lvcreate под капотом). iscsi - пул, который логинится на iSCSI-таргет, и тома там - это LUN'ы, libvirt их только импортирует, но не создаёт. Есть ещё netfs, rbd (Ceph), zfs и другие, но в цели экзамена прямо названы dir, LVM и iSCSI.
Команды и примеры
Сначала пакеты. Debian/Ubuntu:
Код: Выделить всё
apt install libvirt-daemon-system virtinst qemu-utils
systemctl enable --now libvirtdКод: Выделить всё
dnf install libvirt virt-install qemu-img
systemctl enable --now libvirtdКод: Выделить всё
virsh net-list --all
virsh net-start default
virsh net-autostart defaultОпишем изолированную сеть. Создаём файл isolated.xml:
Код: Выделить всё
<network>
<name>lab-isolated</name>
<bridge name='virbr10' stp='on' delay='0'/>
<ip address='192.168.150.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.150.10' end='192.168.150.99'/>
</dhcp>
</ip>
</network>Код: Выделить всё
virsh net-define isolated.xml
virsh net-start lab-isolated
virsh net-autostart lab-isolated
virsh net-dumpxml lab-isolatedТеперь хранилище. Создаём каталоговый пул:
Код: Выделить всё
virsh pool-define-as labdir dir --target /var/lib/libvirt/images/lab
virsh pool-build labdir
virsh pool-start labdir
virsh pool-autostart labdir
virsh pool-list --allКод: Выделить всё
virsh vol-create-as labdir disk1.qcow2 20G --format qcow2
virsh vol-list labdirКод: Выделить всё
virsh pool-define-as lvmpool logical --source-name vg_lab --target /dev/vg_lab
virsh pool-start lvmpool
virsh vol-create-as lvmpool lv_vm1 15GКод: Выделить всё
virsh pool-define-as iscsipool iscsi \
--source-host 10.0.0.50 \
--source-dev iqn.2026-06.ru.cyberlake:target1 \
--target /dev/disk/by-path
virsh pool-start iscsipool
virsh vol-list iscsipoolКод: Выделить всё
virsh attach-disk web1 \
/var/lib/libvirt/images/lab/disk1.qcow2 \
vdb --subdriver qcow2 --persistent --liveКод: Выделить всё
virsh attach-interface web1 network lab-isolated \
--model virtio --persistent --liveЧастые грабли
- Гость в NAT-сети не выходит в интернет - на хосте выключен net.ipv4.ip_forward. libvirt включает его при старте сети, но жёсткий sysctl или внешний фаервол могут перебить. Проверяйте sysctl net.ipv4.ip_forward.
- Bridged-сеть собирают на virbr0. Так нельзя: virbr0 - это внутренний мост libvirt с NAT. Для bridged нужен отдельный физический мост (br0), созданный через NetworkManager/netplan, а домен цепляют к нему типом bridge, а не network.
- net-create вместо net-define: сеть работает, но после рестарта libvirtd исчезает. Для постоянной конфигурации всегда net-define плюс net-autostart.
- pool-define без pool-build для dir, и каталога физически нет - пул не стартует. Для logical-пула, наоборот, pool-build может затереть существующую VG, будьте осторожны на готовых группах.
- Забыли --persistent у attach-disk: диск виден в работающей машине, но после reboot гостя пропадает, а в инвентаре путаница.
- Удаляете том через rm в каталоге вместо vol-delete - libvirt продолжает считать том существующим, пул показывает мусор. Чистите через vol-delete.
- На RHEL 10 ищете правила в iptables и не находите - libvirt пишет в nftables. Смотрите nft list ruleset, а не iptables-save.
- Создайте и активируйте изолированную сеть lab-isolated по XML выше, поставьте на автозапуск, проверьте net-dumpxml.
- Создайте dir-пул labdir в /var/lib/libvirt/images/lab, выполните pool-build и pool-autostart.
- Нарежьте в нём два тома: disk-a.qcow2 на 10G и disk-b.qcow2 на 5G, посмотрите vol-list и vol-info.
- Подключите disk-a к существующему домену горячо с --persistent --live, зайдите в гостя и убедитесь, что появился /dev/vdb.
- Добавьте домену интерфейс в lab-isolated, проверьте, что гость получил адрес из диапазона 192.168.150.x.
- Переведите сеть в NAT: добавьте в XML forward mode='nat', переопределите сеть и проверьте выход гостя в интернет (ping и nft list ruleset на хосте).
- Аккуратно удалите том через vol-delete и убедитесь, что пул чист.
- Чем режим routed отличается от NAT на уровне правил фаервола и какие требования к окружению он накладывает?
- Почему домен в bridged-режиме нельзя подключать к virbr0 и что нужно подготовить заранее?
- В чём разница между net-create и net-define, pool-create и pool-define?
- Что делает pool-build для типов dir и logical и чем это опасно на готовой VG?
- Какие тома можно создавать через vol-create-as, а в каком типе пула libvirt тома только импортирует?
- Зачем нужны флаги --live и --persistent при attach-disk и что будет, если опустить второй?