Подготовка к установке
В данной статье будет кратко написано про установку KVM в Fedora 30 и более детально про последующую настройку сети и взаимодействие гостевых виртуальных машин.
Изучить подробно информацию по работе KVM\QEMU\libvirt можно по различным статьям в рунете или на оф. сайтах. Здесь же вкратце опишу основные моменты.
KVM – Kernel Virtual Machine, open source, является модулем ядра Linux c 2.6.20, разрабатывается Red Hat. Обеспечивает возможность аппаратной виртуализации на базе Intel\AMD.
QEMU – ПО, эмулирующее работу аппаратного оборудования для различных платформ. Может работать и без использования KVM, но обычно используется совместно для достижения большей производительности (QEMU-KVM). При такой связке, KVM, как модуль ядра, выполняет большую часть гостевого кода, продолжая эмулировать остальную часть машины.
Управление KVM происходит благодаря библиотеке libvirt через API, которая включает в себя GUI virt-manager или консольный вариант virsh.
Осталось выполнить несколько команд перед началом.
Для проверки, что CPU (Intel) поддерживает технологию аппаратной виртуализации VT (на выходе должен быть не пустой результат) выполнить:
grep -e 'vmx' /proc/cpuinfo
Проверка модулей ядра, аналогично результат не должен быть пустым:
egrep '^flags.*(vmx|svm)' /proc/cpuinfo
Выключить selinux:
setenforce 0
Установка
Установка пакетов QEMU:
dnf install qemu-kvm qemu-img
Установка библиотек (в т.ч. GUI & CLI инструментов управления) для гипервизора и управления:
dnf install virt-manager libvirt libvirt-python libvirt-client
И обязательные пакеты согласно оф. документации Fedora:
dnf groupinfo virtualization
Group: Virtualization
Group-Id: virtualization
Description: These packages provide a virtualization environment.
Mandatory Packages:
=virt-install
Default Packages:
=libvirt-daemon-config-network
=libvirt-daemon-kvm
=qemu-kvm
=virt-manager
=virt-viewer
Optional Packages:
guestfs-browser
libguestfs-tools
python-libguestfs
virt-top
dnf install @virtualization
Запуск сервиса libvirt, который управляет виртуализацией (поддерживает не только KVM, но и LXC, OpenVZ, Xen, Vbox, VMWare и пр.) и предоставляет API:
systemctl start libvirtd && systemctl enable libvirtd
Устройство сети
Каждая стандартная установка libvirt обеспечивает возможность подключения к виртуальным машинам на основе NAT. Это так называемая виртуальная сеть по умолчанию. Для проверки, что сеть активна:
virsh net-list --all
Name State Autostart
-----------------------------------------
default active yes
Настройки данной сети в XML:
/usr/share/libvirt/networks/default.xml
libvirt создаёт также мост:
brctl show
bridge name bridge id STP enabled interfaces
virbr0 8000.5254002edac4 yes virbr0-nic
На хост-машине можно заметить, что создался интерфейс:
virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 52:54:00:2e:da:c4 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
valid_lft forever preferred_lft forever
В терминологии libvirt, этот интерфейс называется виртуальным коммутатором(virtual network switch ) для объединения гостевых машин.
NAT
Гостевые машины по умолчанию взаимодействуют с внешним миром через виртуальный сетевой коммутатор, который работает в режиме NAT, используя IP masquerading.
Это означает, что все гостевые машины используют IP-адрес хост-машины для связи с внешним миром. А машины извне (относительно хост-машины) доступа к гостевым не имеют.
Картинка для примера из оф. документации:
Для работы гостевых виртуальных машин по сети с внешними узлами посредством NAT, libvirt создает правила в iptables в цепочках INPUT, FORWARD, OUTPUT и POSTROUTING + включается форвардинг. По-хорошему, лучше его прописать в sysctl.conf:
net.ipv4.ip_forward = 1
И применить:
sysctl -p
Резюмируя: NAT-forwarding активен по-умолчанию и не требует доп. настройки.
DNS\DHCP
Виртуальному сетевому коммутатору (их может быть > 1) назначается пул адресов, которые будут предоставляться гостям по DHCP. Для этого обычно используется dnsmasq, который автоматом настраивается и запускается для каждого виртуального сетевого коммутатора, который в этом нуждается.
Если dnsmasq уже используется отдельно от libvirt, это может вызвать проблемы, читать тут
Картинка для примера из оф. документации:
При использовании NAT для гостевых ВМ и необходимости предоставить какой-либо гостевой сервис наружу, т.е. предоставить входящий доступ извне, потребуется пробрасывать порты через iptables хоста:
- Разрешить трафик в цепочке FORWARD до гостевого узла и порта;
- Настроить DSTNAT с хост-порта до нужного гостевого узла.
/sbin/iptables -D FORWARD -o virbr0 -d $GUEST_IP --dport $GUEST_PORT -j ACCEPT
/sbin/iptables -t nat -D PREROUTING -p tcp --dport $HOST_PORT -j DNAT --to $GUEST_IP:$GUEST_PORT
Routed mode
Помимо NAT, есть ещё режим маршрутизации (т.н. роутинг), посредством которого также можно настроить взаимодействие гостей с внешними узлами.
В режиме маршрутизации виртуальный коммутатор подключается к локальной сети физического хоста, передавая трафик гостевой сети туда и обратно без использования NAT.
Для того, чтобы знать, куда передавать трафик, виртуальный коммутатор смотрит IP-адреса в каждом пакете.
При использовании такого режима, все виртуальные машины находятся в подсети, маршрутизируемой через виртуальный коммутатор. Никакие другие узлы в физической сети не знают, что эта подсеть существует или как ее достичь. Таким образом, необходимо настроить маршрутизаторы в физической сети (например, используя статический маршруты), что может вызывать некие неудобства.
Картинка для примера из оф. документации:
Резюмируя: routed forwarding может затребовать доп. настройки на вышестоящем оборудовании и более сложен в настройке.
Изолированный режим
В данном режиме гости могут общаться только друг с другом и хост-машиной и гарантированно изолированы от внешнего мира.
Картинка для примера из оф. документации:
Настройка сетевого моста
Как было сказано ранее, NAT forwarding (aka “virtual networks”) доступен по-умолчанию из коробки во всех дистрибутивах и не требует настройки. Поэтому после того, как будет установлена и запущена гостевая машина, будет выход во внешний мир, но не будет обратного доступа напрямую. Такая конфигурация удобна для быстрого развертывания.
Для того, чтобы гость имел доступ до узлов в хост-сети и наоборот, применяется Bridged networking (aka “shared physical device”), при этом никакого NAT уже не будет, т.к. мост работает на 2 уровне OSI.
Сетевой мост – это устройство на канальном уровне, которое пересылает трафик между сетями на основе MAC-адресов и поэтому называется устройством второго уровня. Мост принимает решения о пересылке на основе таблиц MAC-адресов, которые он создает, узнавая, какие хосты подключены к каждой сети.
К сожалению, беспроводные интерфейсы не могут быть подключены к хост-мосту Linux, это нужно иметь ввиду при настройке.
Также, если после попытки использовать интерфейс моста вы обнаружите, что ваше сетевое соединение перестает работать, возможно, вышестоящий маршрутизатор/коммутатор блокирует «неавторизованные коммутаторы» в сети (например, путем обнаружения BPDU-пакетов).
Основная идея моста в том, что нужно будет:
- создать интерфейс типа мост с именем br0 для хоста, который будет master-интерфейсом;
- создать slave-интерфейс, в который будет подключен enp1s0 (текущий интерфейс до настройки моста);
- отключить enp1s0.
С теорией закончили. Здесь для каждых дистрибутивов будут разные настройки. Напоминаю, в данном случае производится настройка относительно Fedora 30 c использованием NetworkManager (NM).
Для начала нужно убедиться, что NM запущен:
systemctl status NetworkManager
● NetworkManager.service - Network Manager
Loaded: loaded (/usr/lib/systemd/system/NetworkManager.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2019-10-07 11:30:49 MSK; 2 weeks 1 days ago
А теперь непосредственно создание нового соединения типа мост с именем br0:
nmcli con add ifname br0 type bridge con-name br0
Протокол связующего дерева (STP) для отлова петель в сети включен по-умолчанию при создании моста.
И создание slave, в который сразу же подключается интерфейс хост-машины enp1s0, а br0 назначается master`ом:
nmcli con add type bridge-slave ifname enp1s0 master br0
Теперь, если посмотреть список сетевых соединений, можно увидеть, что новый интерфейс br0 создан, но ещё не активен:
$ nmcli con show
NAME UUID TYPE DEVICE
wired-direct 73157bec-12fb-42d0-98c4-f4576742e095 802-3-ethernet enp1s0
br0 892869fe-f8ac-4f17-ace9-b8aeeeee61a0 bridge --
bridge-slave-enp0s25 33ee8c62-48d8-4789-97df-604c479b6860 802-3-ethernet --
А теперь нужно отключить интерфейс enp1s0 и включить br0:
nmcli con down 73157bec-12fb-42d0-98c4-f4576742e095 && nmcli con up br0
Для вступления изменений в силу, перезагрузить сеть:
systemctl restart NetworkManager.service
Если посмотреть вывод команды ip a, можно увидеть, что IP-адрес теперь назначен новому интерфейсу br0, а enp1s0 уже без IP-адреса. Подразумевается, что использовался DHCP. Для того, чтобы мосту назначать статический адрес, нужно указывать соответствующий флаг при создании моста (manual).
$ nmcli con
NAME UUID TYPE DEVICE
br0 892869fe-f8ac-4f17-ace9-b8aeeeee61a0 bridge br0
bridge-slave-enp0s25 33ee8c62-48d8-4789-97df-604c479b6860 802-3-ethernet enp0s25
Создание сети для libvirt
Итак, хост-машина настроена теперь на выход в сеть через интерфейс сетевого моста br0 (можно посмотреть ip r). Теперь нужно создать сетевой интерфейс в libvirt для гостевых машин:
cat > bridge.xml <<EOF
<network>
<name>host-bridge</name>
<forward mode="bridge"/>
<bridge name="br0"/>
</network>
EOF
Далее нужно добавить новую сеть, запустить и включить автостарт:
virsh net-define bridge.xml && virsh net-start host-bridge && virsh net-autostart host-bridge
На этом всё! Теперь при создании гостевой машины, можно выбрать новую bridged-сеть, из которой будет доступ к узлам в хост-сети и наоборот соответственно.
Спасибо! Отличная статья, я бы еще добавил команду по добавлению юзера в группу админов ВМ, что бы не приходилось каждый раз при запуске менеджера ВМ вводить пароль:
usermod -a -G libvirt имя_пользователя