virsh+libvirt+kvm. Облако на вашем ноутбуке

Публичные облака предоставляют удобные сервисы по развёртыванию виртуальной инфраструктуры. Виртуальные машины и виртуальные сети создаются в считанные минуты и даже секунды. Но если требуется поэкспериментировать с небольшим количеством виртуальных машин, то арендовать облачные ресурсы слишком дорого. Вместо этого можно воспользоваться стеком виртуализации linux, который в том числе используется и в популярном облачном оркестраторе openstack, и развернуть несколько виртуальных машин на своём ноутбуке. В данной статье создадим виртуальную машину из облачного образа при помощи libvirt/kvm, подключим её к сети и предоставим к ней доступ по ssh с хоста.
Установка необходимых пакетов
Разворачивать виртуальную машину (ВМ) будем на хосте под управлением ubuntu 22.04. В качестве гипервизора будем использовать kvm c фронтэдом qemu. Для управления гипервизором будем использовать API, который предоставляет библиотека libvirt. В свою очередь для отправки команд в libvirt API будем использовать консольную утилиту virsh. Чтобы воспользоваться этим стеком виртуализации необходимо установить следующие пакеты:
sudo apt install -y qemu-system-x86 libvirt-daemon libvirt-clients libvirt-daemon-system virtinst whois
qemu-system-x86 – эмулятор, который позволяет на машине с одной архитектурой
исполнять код скомпилированный для другой архитектуры. В нашем случае он будет
использоваться в большей степени как фронтэнд к гипервизору kvm.
libvirt-daemon – библиотека libvirt и демон libvirtd, предоставляющая API к
большому количеству систем виртуализации, в том числе к используемой в нашем
случае qemu/kvm. Примером команды предоставляемого API является, например,
команда по созданию ВМ. То есть клиент, например virsh или virt-manager,
отправляет запрос в демон libvirtd на содание ВМ, который и выполняет эту
задачу, реализуя libvirt API.
libvirt-clients – разного рода клинты к API, предоставляемому libvirt, в том
числе используемый нами virsh.
libvirt-daemon-system – интеграция libvirtd в systemd.
virtinst – утилита virt-install. Ещё один клиент для libvirt, который позволяет
удобным образом создавать ВМ. Для создания ВМ при помощи утилиты virsh
необходимо описывать конфигурацию в виде xml файла. Утилита virt-install
опускает многие подробности конфигурации ВМ и позволяет указать несколько
основных параметров в командной строке.
whois – пакет, содержащий утилиту mkpasswd, которую будем использовать для
генерации хэша паролей.
Модуль kvm входит в дистрибутив ubuntu и не требует установки.
Connection URIs
Как уже было сказано, libvirt поддерживает большое количество стеков виртуализации, например, kvm, xen, vmware. Поэтому при обращении к libvirt клиент должен указатать, с каким стеком виртуализации он хочет поработать. Это делается при помощи connection URI. Для случая kvm/qemu поддерживается два типа URI: qemu:///system и qemu:///session. Разница между ними в том, что если мы работаем с URI qemu:///session, то мы будем подключаться к процессу libvirtd, который запущен с правами текущего пользователя. Поэтому и права создаваемых ВМ будут ограничены правами текущего пользователя. И основные ограничения, которые нам не позволят создать целевую конфигурацию – это огарничения накладываемые на конфигурацию сети. Если использовать qemu:///session URI, то нельзя будет подключиться по ssh с хоста простым способом к ВМ, хоть ВМ и будет иметь выход в интерент и к ней можно будет подключиться через серийную консоль. Поэтому мы будем использовать qemu:///system URI. В этом случае мы будем обращаться к демону libvirtd, запущенному с правами суперпользователя, и который будет создавать более привилегированные процессы qemu, которые будут иметь более широкие возможности по работе с виртуальными сетями. Чтобы проверть с каким URI утилита virsh работает по-умолчанию, можно выполнить команду virsh uri
virsh uri
qemu:///system
Если URI по-умолчанию qemu:///session, то можно при каждом запуске утилиты virsh указывать нужный URI в флаге -c, например
virsh -c qemu:///system list
Либо можно установить переменную окружения LIBVIRT_DEFAULT_URI
export LIBVIRT_DEFAULT_URI=qemu:///system
Настройка доступа к qemu:///system URI
При работе с qemu:///system URI отправка команд в демон libvirtd происходит через unix сокет /var/run/libvirt/libvirt-sock, который по-умолчанию создаётся с пользователем root и группой libvirt
ls -l /var/run/libvirt/libvirt-sock
rw-rw---- 1 root libvirt 0 мая 6 21:40 /var/run/libvirt/libvirt-sock
Поэтому для записи в такой сокет, если вы работаете не от root, необходимо добавить вашего пользователя в группу libvirt. Например, для пользователя tlakepro
sudo usermod -a -G libvirt tlakepro
После выполнения этой конмады необходимо заново войти в систему, чтобы изменения применились. Теперь можно выполнить первое обращение к libvirt API – вывести список запущенных ВМ
virsh list
Id Name State
--------------------
Пока не запущено ни одной ВМ. На этом установка и настройка пакетов, а также прав доступа завершена, и можно переходить к созданию образов дисков, виртуальных сетей и ВМ.
Облачные образы
Чтобы не проходить этап установки операционной системы на жёсткий диск при первом запуске ВМ, можно воспользоваться облачным образом. Облачный образ – это образ жёсткого диска с уже предустановленной операционной системой и с возможностью её настройки. Такие образы используются облачными провайдерами для быстрого создания ВМ. Воспользуемся облачным образом ubuntu 22.04 и скачаем его в домашнюю папку
wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
Настройка облачного образа при помощи cloud-init
Можно запустить ВМ используя облачный образ, никак его не настраивая. Но при этом не будет возможности войти в систему, так как в облачном образе нет аккаунта для входа. Поэтому как минимум необходимо выполнить настройку образа, чтобы когда операционная система загрузится, в ней уже был создан наш пользователь с известным нам паролем. Обычно создание такого пользовтеля происходит на этапе утановки операционной системы. В нашем случае мы работаем с уже предустановленной операционной системой, поэтому для создания пользователя воспользуемся утилитой cloud-init, входящей в облачный образ. Как и следует из назавния утилита cloud-init используется для инициализации облачных образов. Она имеет множество возможностей и в частности позволяет создать пользователя и установить ему пароль. Утилита cloud-init запускается при каждом старте операционной системы, но основные настройки, такие как создание пользователя, она делает только один раз при первом запуске. Поэтому если вы ошиблись с настройками пользователя, образ надо будет пересоздать заново, чтобы утилита cloud-init сработала как при первом запуске и применила новые настройки для создаваемого пользователя.
Источники данных для cloud-init и их типы
Утилита cloud-init может брать данные для настройки образа из большого
количества разного рода источников. Например, в случае облака openstack данные
будут браться со специального сервера(metadata service) по http протоколу. В
нашем случае мы будем использовать специально подготовленный образ cd диска,
который подключим к ВМ при первом запуске. Такой источник данных для cloud-init
называется NoCloud
Предоставляемые для cloud-init данные имеют разный тип и формат в зависимости
от источника данных. Через используемый нами NoCloud источник можно
предоставить четыре типа данных : user-data, meta-data, vendor-data и network
config. Каждый из них имеет большое количество возможностей, но если кратко, то:
user-data - используется для предосталяемых пользователем данных, например, имя
пользователя и пароль.
meta-data - дынные о ВМ в облаке, например, instance id или hostname. Несмотря
на то, что мы разворачиваем ВМ локально, а не в облаке, meta-data необходимо
будет предоставить.
vendor-data - настройки конкретного облачного провайдера или администратора.
Имеют такой же формат как и user-data и обрабатываются аналогичным образом. При
этом user-data имеет приоритет над meta-data. Vendor-data может использоваться,
например, для создания дополнительного пользователя, который будет
использоваться в административных целях.
nework config - настройки сети. Например, можно назначить статические
IP адреса сетевым интерфейсам.
Для корректной работы необходимо как минимум предоставить user-data и
meta-data. NoCloud источник может быть реализован разными способами. Мы будем
использовать NoCloud источник реализованный в виде образа cd диска,
подключённого к ВМ. В корне файловой системы такого образа должны быть файлы с
именами user-data и meta-data с необходимыми данными и в правильном формате.
user-data
user-data файл может иметь разный формат. Мы будем использовать формат cloud-config. Такой файл должен начинаться с директивы #cloud-config, после которой следуют настраиваемые параметры в формате yaml
#cloud-config
users:
- name: tlakepro
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBs8gRnx3+H3b2S71YywJGDIqZmeCiFHweF58/UIgp+o user@user-Latitude-5300
passwd: $6$Dc8qAXotbpXLk93K$2wuvxcjDP2a.ViIi6qZ6WImkR/GPPS96hLhSrFV9eVgGdCLZiHhnjS0/iUngg31k4GbteVU91YWutxd7pBT5i1
lock_passwd: false
sudo: ALL=(ALL) NOPASSWD:ALL
groups: sudo
shell: /bin/bash
В данном примере создаётся пользователь с именем
user, для которого устанавливается пароль, предоставляется беспарольный доступ
к sudo, и добавляется публичный ключ хоста, для беспарольного доступа по ssh с
хоста.
Пароль передаётся в захэшированном виде. Хэш пароля для user-data может быть
сгенерирован при помощи команды
echo password | mkpasswd -m sha-512 -s
meta-data
meta-data файл также имеет формат yaml и обязательно должен содержать instance-id. Помимо этого добавим hostname
instance-id: ubuntu-vm
local-hostname: ubuntu-vm
Образа CD диска с user-data и meta-data для cloud-init
Для создания ВМ мы будем использовать команду virt-install. Эта команда поддерживает флаг --cloud-init, который в качестве параметров принимает файлы user-data и meta-data, и который генерирует образ CD диска с этими файлами и подключает его к ВМ при первом запуске. Поэтому мы не будем сами генерировать такой образ. Например, это можно было бы сделать при помощи утилиты genisoimage.
Добавление образов в libvirt
Для того, чтобы можно было подключить образ
жёсткого диска к ВМ, необходимо, чтобы процесс qemu, который будет использовать
этот образ, имел к нему доступ, а именно, имел возможность поиска в папках на
всём пути к нему. Иными словами на всех папках на пути к образу должен быть
выставлен флажок x(execute) либо для пользователя процесса qemu, либо для
группы процесса qemu, либо для other. Например, на домашние папки пользователей
по-умолчанию не установлен флаг х для other, поэтому положить образ в домашнюю
папку не получиться, не изменяя права на неё. Права на сам файл образа демон
libvirtd установит необходимым образом.
Для работы с образом будем
использовать папку /var/lib/libvirt/images/, которая создаётся при установке
пакетов. На всем пути к этой папке и на самой папке выставлен флажок x. Для
работы с образом и для копирования его в эту папку воспользуемся возможностями
утилиты virsh.
Для работы с образами в libvirt используются понятия pool и
volume. В первом приближении можно считать, что pool – набор volume, где volume
– это синоним образа. Pool бывают разного типа, мы будем использовать pool типа
dir, то есть папка. Такой pool описывается путём к папке, а все файлы в этой
папке рассматриваются как volume.
Создадим pool с папкой /var/lib/libvirt/images
virsh pool-define-as --name tlakepro-pool --type dir --target /var/lib/libvirt/images
virsh pool-start tlakepro-pool
virsh pool-autostart tlakepro-pool
Далее создадим volume в этом pool для нашего образа и загрузим в него данные из нашего образа
virsh vol-create-as --pool tlakepro-pool --capacity 100 --name ubuntu-vm.qcow2
capacity можно выбрать произвольный, так как далее мы загрузим данные из нашего образа в этот volume
virsh vol-upload --pool tlakepro-pool --vol ubuntu-vm.qcow2 --file jammy-server-cloudimg-amd64.img
Можно посмотреть, что наш образ появился в папке /var/lib/libvirt/images/
sudo ls -lh /var/lib/libvirt/images/
total 638M
-rw------- 1 root root 637M Apr 8 09:10 ubuntu-vm.qcow2
Далее можно увеличить размер виртуального диска, который будет распознан операционной системой. Скачанный облачный образ по-умолчанию имеет не очень большой виртуальный размер
virsh vol-info --pool tlakepro-pool --vol ubuntu-vm.qcow2
Name: ubuntu-vm.qcow2
Type: file
Capacity: 2.20 GiB
Allocation: 636.80 MiB
Чтобы его увеличить можно воспользоваться командой virsh vol-resize
virsh vol-resize --pool tlakepro-pool --vol ubuntu-vm.qcow2 --capacity 100G
Size of volume 'ubuntu-vm.qcow2' successfully changed to 100G
Виртуальная сеть
При установке пактов в libvirt создаётся сеть по-умолчанию
virsh net-list
Name State Autostart Persistent
--------------------------------------------
default active yes yes
Её параметры можно посмотреть при помощи команды virsh net-dumpxml
virsh net-dumpxml default
<network connections='1'>
<name>default</name>
<uuid>b918b1e3-cc20-4d9d-9ae7-ead17a425d09</uuid>
<forward mode='nat'>
<nat>
<port start='1024' end='65535'/>
</nat>
</forward>
<bridge name='virbr0' stp='on' delay='0'/>
<mac address='52:54:00:18:ab:5d'/>
<ip address='192.168.122.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.122.2' end='192.168.122.254'/>
</dhcp>
</ip>
</network>
Создаваемые ВМ будем подключать к этой сети. Здесь можно обратить внимание
следующие параметры:
<forward mode='nat'> - для продвигаемых пакетов ВМ будет применяться NAT,
и благодаря этому ВМ будут иметь доступ в интеренет, если хост имеет доступ в интернет.
<bridge name='virbr0' stp='on' delay='0'/> <ip address='192.168.122.1' netmask='255.255.255.0'> -
на хосте настроен бридж virbr0 с IP адресом 192.168.122.1. Через этот бридж можно будет заходить на ВМ по ssh
<dhcp><range start='192.168.122.2' end='192.168.122.254'/></dhcp> -
в виртуальной сети настроен DHCP сервер, который будет раздавать IP адреса ВМ в подсети 192.168.122.0/24
Создание виртуальных машин
Всё готово, чтобы создать ВМ при помощи утилиты virt-install. Для этого воспользуемся следующей командой virt-install
virt-install --name=ubuntu-vm \
--ram=4096 \
--vcpus=4 \
--disk vol=tlakepro-pool/ubuntu-vm.qcow2 \
--cloud-init user-data=user-data,meta-data=meta-data \
--network default \
--import \
--noautoconsole \
--os-variant=ubuntu22.04
--name – имя создаваемой ВМ
--ram – количество оперативной памяти в создаваемой ВМ
--vcpu – количество виртуальных CPU в создаваемой ВМ
--disk – образ диска. Указывается в формате <pool>/<volume>
--cloud-init – пути к файлам которые будут добавлены в сгенерированый образ cd диска для cloud-init
--network – сеть, к которой будет подключена ВМ
--import флаг указывает на то, что мы работаем с образом, на котором уже установлена операционная система
--noautoconsole – отключение автоматического подключения к консоли создаваемой ВМ. К консоли можно будет подключиться позже при помощи команды virsh console
--os-variant - указывает, с какой операционной системой мы работаем. Флаг является обязательным, возможные значения можно посмотреть при помощи команды virt-install --osinfo list
Если конмада завершилась успешно, то созданную ВМ можно увидеть в списке запущенных ВМ
virsh list
Id Name State
---------------------------
2 ubuntu-vm running
Выданный ВМ IP адрес можно посмотреть при помощи команды virsh net-dhcp-leases
virsh net-dhcp-leases default
Expiry Time MAC address Protocol IP address Hostname Client ID or DUID
------------------------------------------------------------------------------------------------------------------------------------------------
2025-04-21 00:54:51 52:54:00:9d:1f:e1 ipv4 192.168.122.156/24 ubuntu-vm ff:56:50:4d:98:00:02:00:00:ab:11:92:9e:6c:a3:ce:5d:49:95
Далее можно подключиться к ВМ по ssh
ssh 192.168.60.156
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-134-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sun Apr 20 21:09:20 UTC 2025
System load: 0.0 Processes: 136
Usage of /: 1.6% of 96.73GB Users logged in: 0
Memory usage: 5% IPv4 address for enp1s0: 192.168.122.156
Swap usage: 0%
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
New release '24.04.2 LTS' available.
Run 'do-release-upgrade' to upgrade to it.
Last login: Sun Apr 20 20:54:12 2025 from 192.168.122.0
ubuntu-vm@tlakepro:~
Заключение
В статье рассмотрели создание одной ВМ из облачного образа. По такому же алгоритму можно создать ещё несколько ВМ и подключить их к одной виртуальной сети. В этом случае мы будем иметь полноценную облачную инфраструктуру, состоящую из нескольких ВМ, подключённых к одной сети, на локальной машине, на которой можно экспериментировать, например, с k8s. Если написать скрипты для всех описанных в статье команд, то подобную инфраструктуру можно будет создавать и удалять моментально.