Клонирование виртуальной машины в Virt-Manager с помощью virt-clone и virt-sysprep
Клонирование ВМ копирует байты, а не идентичность.
Virt-Manager (графический интерфейс для libvirt) копирует диск KVM и присваивает клону новый UUID и MAC-адрес. Гость сохраняет свой machine-id и ключи SSH-хоста, пока virt-sysprep не очистит их.
В данном руководстве используется гость на базе Ubuntu 26.04 и образ qcow2 размером 14 ГБ, хранящийся в /mnt/extra2/vms. Команды для работы с дисками такие же и для других гостевых систем Linux. virt-sysprep не работает с гостевыми системами Windows.

На хосте уже должны быть установлены KVM и libvirt. Инструкция Установка KVM на Ubuntu 24.04 описывает эту настройку, и она тянет за собой пакет virtinst, который предоставляет утилиту virt-clone. Утилиты virt-sysprep, virt-customize, virt-cat и guestfish входят в отдельный пакет:
sudo apt install -y libguestfs-tools
Что именно выполняет клонирование ВМ
libvirt распределяет задачи между тремя утилитами. virt-clone копирует образы дисков и определяет новый домен с тем же виртуальным оборудованием. Он изменяет имя домена, UUID и MAC-адрес на стороне хоста. Пароли, имя хоста, статические адреса и файлы внутри гостя не изменяются, что соответствует документации virt-clone(1).
virt-sysprep открывает диск через libguestfs и редактирует файловую систему гостя. Руководство virt-sysprep(1) прямо указывает, что редактирование происходит на месте (in-place): нет флажка вывода в новый файл, поэтому образ, который вы передаете в -a, является тем самым образом, который будет изменен. Если исходный образ еще нужен, сначала выполните копирование или клонирование.
qemu-img info сообщает, является ли этот файл самостоятельным или верхним звеном цепочки базовых образов. qemu-img convert записывает новый файл с разрешенной цепочкой.
Выполняйте «схлопывание» (flatten) перед sysprep, если присутствует строка о базовом файле. Применяйте sysprep к копии, а затем создавайте каждый работающий гость из этого файла.
Клонирование диска в Virt-Manager
Выключите гостя. virt-clone отклоняет работающий домен, и копия «живого» qcow2 не будет представлять собой согласованную файловую систему.
В Virt-Manager щелкните правой кнопкой мыши по гостю и выберите Клонировать. Установите новое имя. На шаге настройки хранилища задайте новый путь для каждого диска. Если оставить исходный путь, будет определен второй домен, открывающий тот же файл, и тогда оба гостя будут писать в одни и те же блоки.
Новый файл окажется рядом с исходным. Пул по умолчанию использует /var/lib/libvirt/images/. Диск, который уже находится в /mnt/extra2/vms, будет клонирован в этот каталог. Запишите путь, который выведет virt-clone, или прочтите его:
virsh domblklist ubuntu26.04-base14gb-clone
Эквивалент в командной строке, где имя и путь к диску указаны явно:
virt-clone --original ubuntu26.04-base14gb \
--name ubuntu26.04-base14gb-clone \
--file /mnt/extra2/vms/ubuntu26.04-base14gb-clone.qcow2
Флаг --auto-clone самостоятельно придумывает имя и путь к диску. Это удобно для временных копий. Если вы сами передаете --name и --file, проще сохранять путь как шаблон. Пропустите --mac или передайте --mac RANDOM, и virt-clone сгенерирует адрес в диапазоне QEMU 52:54:00:xx:xx:xx.
--reflink запрашивает легкое копирование. Руководство virt-clone для Ubuntu 26.04 ограничивает использование этого флага «сырыми» (raw) образами на одной и той же файловой системе btrfs, поэтому он пропускает эти файлы qcow2. Оверлей qcow2 — это отдельная настройка, описанная ниже с помощью qemu-img create -b.
Есть ли у вашего клона базовый файл?
Выполните эту команду на новом диске, прежде чем считать его независимым:
qemu-img info --backing-chain /mnt/extra2/vms/ubuntu26.04-base14gb-clone.qcow2
Самостоятельный образ содержит строки file format, virtual size и disk size. Оверлей также содержит строку backing file:, указывающую на образ, через который он читает данные. virtual size — это размер диска гостя, в данном случае около 14 ГБ. disk size — это занимаемое файлом место, которое небольшое для свежего оверлея и растет по мере записи гостем.
virt-clone — не обычный источник такой строки. Оверлей возникает из qemu-img create -b, из снимка только диска (disk-only snapshot) или из инструмента, который намеренно создал дельту qcow2. Именно проверка информации позволяет отличить эти случаи от полной копии.
Оставляйте оверлей только в том случае, если базовый образ останется на месте и больше не будет перезаписываться. Все записи от клона попадают в небольшой файл; чтения, которые не найдены в оверлее, берутся из базового. Перемещение или редактирование базового образа сломает всех гостей, ссылающихся на него.
Чтобы сделать самостоятельный файл, сконвертируйте оверлей. -p выводит прогресс. Файл назначения — это новый файл; оверлей и базовый остаются неизменными:
qemu-img convert -p -O qcow2 \
/mnt/extra2/vms/ubuntu26.04-base14gb-clone.qcow2 \
/mnt/extra2/vms/ubuntu26.04-base14gb-flat.qcow2
Выполните qemu-img info на «плоском» файле и убедитесь, что нет строки backing file:. Шаблон — это именно этот самостоятельный файл. Оверлеи — это способ «штамповать» гостей из него позже, а не сам шаблон.
Рефлинк btrfs — это третий случай. cp --reflink=auto может разделять физические экстенты между двумя файлами, и qemu-img info по-прежнему не показывает базовый файл, потому что каждый путь — это полный образ. Эта копия независима на уровне qcow2, даже если файловая система еще не продублировала каждый блок.
virt-sysprep: сброс идентичности
Скопируйте самостоятельный образ, затем выполните sysprep над копией. --reflink=auto разделяет экстенты, если файловая система это поддерживает, и иначе выполняет обычное копирование, включая ext4. -n — это пробный запуск (dry run), который отбрасывает свои записи:
cp --reflink=auto \
/mnt/extra2/vms/ubuntu26.04-base14gb-flat.qcow2 \
/mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2
virt-sysprep -n -a /mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2
virt-sysprep -a /mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2 \
--hostname ubuntu-template
В пуле Ubuntu по умолчанию образ часто имеет права 0600 и принадлежит пользователю libvirt-qemu. Руководство рекомендует предоставить вашему пользователю права на запись, а не запускаться от root. Если файлом владеет пользователь qemu, вызовом, который может его открыть, является sudo virt-sysprep -a .... Гость должен быть выключен, и ни один другой процесс не должен держать образ открытым.
--hostname — это опция кастомизации, а кастомизация входит в набор операций по умолчанию, поэтому она выполняется в том же вызове. Нет отдельной операции по умолчанию, которая очищала бы /etc/hostname сама по себе. --operations заменяет этот набор по умолчанию, когда передается; --operations defaults,-ssh-userdir сохраняет значения по умолчанию и отключает одну операцию.
Ниже приведены операции, которые определяют, будет ли клон конфликтовать с оригиналом. Этот список взят из актуального руководства virt-sysprep, который стоит прочитать, потому что короткий список --operations молча отбрасывает остальные:
| Операция | По умолчанию | Влияние на гостя |
|---|---|---|
| machine-id | да | Очищает идентификатор машины. systemd генерирует новый при следующей загрузке, если /etc/machine-id пуст. |
| ssh-hostkeys | да | Удаляет /etc/ssh/ssh_host_*. При следующей загрузке создаются новые ключи хоста. |
| ssh-userdir | да | Удаляет .ssh под /root и /home/*, включая authorized_keys и приватные ключи, хранящиеся в госте. |
| dhcp-client-state | да | Удаляет аренды клиента DHCP. |
| udev-persistent-net | да | Удаляет правила udev, которые сопоставляют старый MAC с фиксированным именем, таким как eth0. |
| net-hwaddr | да | Удаляет HWADDR из файлов ifcfg-* в Fedora и RHEL. Не редактирует netplan в Ubuntu. |
| lvm-uuids, lvm-system-devices | да | Присваивает новые UUID LVM и удаляет /etc/lvm/devices/system.devices, который иначе привязывает гостя к WWID исходного диска. |
| logfiles, bash-history, tmp-files | да | Удаляет журналы, историю командной строки и временные файлы. |
ssh-userdir — это та самая операция, которая удивляет людей, клонирующих машину, к которой они все еще подключаются. Шаблон не должен содержать приватных ключей источника, поэтому оставьте операцию включенной и вставляйте ключ для каждого экземпляра позже. Для одноразовой копии, которая должна сохранить существующие authorized_keys, передайте --operations defaults,-ssh-userdir.
user-account не входит в набор по умолчанию, и пароли остаются, если вы не передадите --password или --root-password. fs-uuids также отключено по умолчанию. В руководстве сказано, что он не обновляет все ссылки, включая /etc/fstab, и что включение его, вероятно, сделает гостя неустанавливаемым (unbootable).
Образы Ubuntu Server обычно содержат cloud-init, и у virt-sysprep нет операции для cloud-init. Старый идентификатор экземпляра в /var/lib/cloud заставляет клон пропускать настройку первой загрузки. Очистите его в шаблоне и сообщите cloud-init сохранить имя хоста, записанное через --hostname:
virt-customize -a /mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2 \
--run-command 'if command -v cloud-init >/dev/null 2>&1; then cloud-init clean --logs --seed; fi' \
--write '/etc/cloud/cloud.cfg.d/99-preserve-hostname.cfg:preserve_hostname: true'
То же руководство предупреждает о клонировании гостя, использующего внутреннее полное шифрование диска для распространения: каждая копия делит ключ тома. Также отмечено, что удаленные файлы удаляются по ссылке, а не очищаются. --scrub перезаписывает именованный файл, а virt-sparsify может удалить высвобожденное место из образа.
Как клон получает свой IP-адрес
У virt-sysprep нет операции, которая переписывает адрес. Гость, который использовал DHCP, запрашивает его снова. У клона новый MAC, пустой machine-id и нет старого файла аренды, поэтому сервер DHCP в сети default libvirt рассматривает его как нового клиента.
Блок статических addresses: в netplan копируется с диском, и тогда оба гостя претендуют на него. Прочитайте файлы перед первой загрузкой. virt-ls и virt-cat — это одноразовые утилиты; guestfish --ro -a <disk> -i — это тот же инспектор, что и в оболочке, после чего ls /etc/netplan и cat выполняются против гостя:
virt-ls -a /mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2 /etc/netplan
virt-cat -a /mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2 \
/etc/netplan/00-installer-config.yaml
Образы установщиков часто используют 00-installer-config.yaml или 01-netcfg.yaml. Облачные образы используют 50-cloud-init.yaml, который cloud-init пересоздаст, если конфигурация сети не отключена. Netplan объединяет все файлы YAML в каталоге, поэтому оставшийся статический файл все еще применяется, даже если вы добавите файл для DHCP.
Чтобы сделать шаблон клиентом DHCP, удалите эти файлы и загрузите один заменяющий. Используйте имя интерфейса, которое показала virt-cat. На госте, установленном под KVM, это имя часто ens3 или enp1s0, и virt-clone сохраняет тот же виртуальный слот PCI, поэтому имя остается действительным:
cat > /tmp/99-dhcp.yaml <<'EOF'
network:
version: 2
ethernets:
ens3:
dhcp4: true
EOF
virt-customize -a /mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2 \
--delete '/etc/netplan/*.yaml' \
--upload /tmp/99-dhcp.yaml:/etc/netplan/99-dhcp.yaml \
--write '/etc/cloud/cloud.cfg.d/99-disable-network.cfg:network: {config: disabled}'
Для статического адреса, шлюза и DNS используйте ту же загрузку с YAML из статьи Как изменить статический IP-адрес в Ubuntu Server. Тогда каждый экземпляр нуждается в своем собственном файле, применяемом к диску экземпляра, а не к шаблону.
Имя в YAML должно существовать внутри гостя. Диск, перемещенный с физического оборудования, часто называет сетевую карту enp2s0, тогда как та же система под virtio показывает другое имя, и тогда netplan настраивает интерфейс, которого нет. Для шаблона, который должен загружаться на разных типах машин, закрепите ядро за eth0 и используйте этот ключ в netplan. Ubuntu подключает /etc/default/grub.d/*.cfg при сборке grub.cfg:
virt-customize -a /mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2 \
--write '/etc/default/grub.d/99-eth0.cfg:GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX net.ifnames=0 biosdevname=0"' \
--run-command 'update-grub'
update-grub выполняется внутри приложения libguestfs. Если grub-probe не видит загрузочный диск там, команда завершается ошибкой, и командная строка остается неизменной. В этом случае задайте имя интерфейса в netplan такое же, как то, которое гость уже использует, и пропустите переключение на eth0.
Персонализация для каждого экземпляра с помощью virt-customize
Загружайте экземпляры из копий чистого файла. Не указывайте домену сам шаблон.
Полная копия не имеет временной зависимости от шаблона:
cp --reflink=auto \
/mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2 \
/mnt/extra2/vms/ubuntu26.04-vm1.qcow2
Оверлей хранит только те блоки, которые пишет vm1. -F qcow2 записывает формат базового файла, чтобы QEMU не пришлось его исследовать:
qemu-img create -f qcow2 \
-b /mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2 \
-F qcow2 \
/mnt/extra2/vms/ubuntu26.04-vm1.qcow2
Путь к базовому файлу хранится внутри оверлея. Он должен сохранять этот путь и оставаться в режиме только чтения для всех гостей, построенных таким образом.
Замечания о безопасности в virt-sysprep описывают второй проход на каждом новом диске. Sysprep записывает случайный сид (seed) в шаблон; гостям, клонированным из этого файла, иначе придется начинать с того же сида, что делает ключи SSH-хоста и номера последовательности TCP при первой загрузке предсказуемыми. --enable customize переписывает сид. --hostname и --ssh-inject — это опции кастомизации, поэтому они должны находиться в той же команде. Подставьте учетную запись, которая действительно существует в образе, вместо ubuntu:
virt-sysprep --enable customize \
-a /mnt/extra2/vms/ubuntu26.04-vm1.qcow2 \
--hostname vm1 \
--ssh-inject "ubuntu:file:${HOME}/.ssh/id_ed25519.pub"
Передайте файлу экземпляра libvirt, а не шаблону. Если вы создали его от своего пользователя вне пула хранилища, libvirt-qemu нужны права на чтение, иначе домен не запустится из-за ошибки разрешений на qcow2.
Импорт в Virt-Manager
Для каждого диска экземпляра откройте Virt-Manager, выберите Создать виртуальную машину и отметьте Импорт существующего образа диска. Укажите ubuntu26.04-vm1.qcow2. Запись ОС должна быть Ubuntu 26.04, если в базе данных osinfo хоста она имеется.
Совпадающий короткий идентификатор — ubuntu26.04. Проверьте базу данных хоста, прежде чем полагаться на него:
osinfo-query os | grep ubuntu26
Если это ничего не выведет, установленная база данных старше записи 26.04. --os-variant ubuntu24.04 по-прежнему выберет тип машины, дружелюбный к virtio, для уже установленного гостя. --import сообщает virt-install, что диск уже содержит ОС.
sudo virt-install --name ubuntu26.04-vm1 \
--memory 4096 --vcpus 2 \
--disk path=/mnt/extra2/vms/ubuntu26.04-vm1.qcow2,format=qcow2 \
--import \
--os-variant ubuntu26.04 \
--network network=default \
--noautoconsole
--network network=default подключает сеть NAT, экземпляр dnsmasq которой выдает аренду DHCP. После загрузки:
virsh domifaddr ubuntu26.04-vm1 --source lease
virsh dumpxml ubuntu26.04-vm1 | grep "<mac"
--source lease читает ту таблицу dnsmasq. Она остается пустой для статического адреса, для моста или для сетевой карты, не находящейся в виртуальной сети libvirt. Таким гостям нужен qemu-guest-agent в образе и virsh domifaddr ubuntu26.04-vm1 --source agent, либо ARP-поиск с --source arp. virsh net-dhcp-leases default перечисляет все аренды в сети NAT, если вам нужен общий вид пула, а не одного домена.
Выбор стратегии клонирования: полная копия, оверлей или рефлинк
| Стратегия | Место на VM | Время создания | Ограничение | Когда использовать |
|---|---|---|---|---|
Полная копия или cp --reflink=auto |
около 14 ГБ логически; рефлинк разделяет блоки, пока они не изменятся | минуты, или почти мгновенно с рефлинком | рефлинк требует поддержки файловой системой, такой как btrfs | гость, который должен пережить шаблон |
| Оверлей qcow2 | мегабайты в начале | секунды | путь к базе должен остаться, и база должна оставаться в режиме только чтения | много похожих гостей из одного запечатанного образа |
virt-clone --reflink |
«сырой» (raw) образ, общие экстенты | почти мгновенно | raw-диски на одной и той же ФС btrfs; qcow2 пропускаются | raw-образы, уже хранящиеся на btrfs |
Гость, который вы планируете держать несколько месяцев, — это полная копия или рефлинк. Кратковременный гость может быть оверлеем, при условии, что базовый файл все еще есть, когда он работает. Proxmox — это другой путь для самостоятельного хостинга, если вы хотите модель шаблонов и клонирования в стиле дата-центра в собственном веб-интерфейсе. Multipass запускает облачные образы Ubuntu для одного пользователя и сам применяет cloud-init, что является другим рабочим процессом, чем запечатывание диска, который вы уже установили.
Устранение неполадок: когда клон не загружается
Нет адреса. Выполните virt-cat для файла netplan и сравните ключ интерфейса с ip link в консоли. Запись match: macaddress, все еще установленная на исходный MAC, отбрасывает новую сетевую карту. Ключ, указывающий на интерфейс, которого нет в госте, делает то же самое. Исправьте файл на диске или примените командную строку eth0, описанную выше, и пересоздайте экземпляр из шаблона.
Адрес есть, такой же, как у оригинала. Статический блок addresses: все еще находится в одном из файлов netplan. virt-sysprep не удалил его. Загрузите заменяющий файл и удалите другие файлы YAML в /etc/netplan.
SSH говорит, что ключ хоста изменился, или принимает клон как оригинал. Ключи хоста общие, если операция ssh-hostkeys не выполнялась на файле, который открывает домен. Убедитесь с помощью virsh domblklist, что домен использует диск после sysprep, затем проверьте qemu-img info, чтобы убедиться, что вы не применили sysprep к оверлею, пока гость загружается с другого пути. Если клон намеренно сохранил оригинальный IP, клиенты, сохранившие старый ключ в known_hosts, будут предупреждать, пока эта строка не будет удалена. Это предупреждение — та самая регенерация, которую описывает руководство.
Вход по ключу не работает на клоне машины, к которой вы могли получить доступ раньше. Sysprep по умолчанию удалил .ssh из домашних каталогов. Вставьте ключ с помощью --ssh-inject или выполните снова с --operations defaults,-ssh-userdir, если эта копия должна была сохранить их.
Томи LVM отсутствуют после загрузки. У гостя есть /etc/lvm/devices/system.devices от источника, и WWID виртуального диска изменился. Операция lvm-system-devices по умолчанию удаляет этот файл. В вручную подобранном списке --operations она должна присутствовать, а также lvm-uuids, если гость использует LVM.
Один клон или шаблон
Одна дополнительная машина — это virt-clone, проверка базового файла и virt-sysprep на новом диске. Флот — это один запечатанный самостоятельный файл, затем копия или оверлей для каждого гостя, с --enable customize на собственном диске этого гостя перед его загрузкой.
Оверлеи делают запечатанный файл частью пути выполнения каждого гостя, который на него ссылается. Полные копии и рефлинки этого не делают. Выбирайте эту зависимость исходя из жизненного цикла гостя и оставляйте fs-uuids отключенным, чтобы загрузчик и /etc/fstab по-прежнему соответствовали файловой системе.
Полезные ссылки
- Инструменты разработчика: Полное руководство по современным рабочим процессам разработки
- Как установить Ubuntu 24.04 и полезные инструменты
- GNOME Boxes: возможности, преимущества, сложности и альтернативы
Ссылки
- virt-clone(1) в Ubuntu 26.04, включая
--auto-clone,--fileи--reflink - операции virt-sysprep(1), редактирование на месте и примечание о случайном сиде
- virt-customize(1) для
--hostname,--ssh-inject,--uploadи--run-command info,convertиcreate -b/-Fв qemu-img--importи--os-variantв virt-install(1)- запись Ubuntu 26.04 в osinfo-db, короткий идентификатор
ubuntu26.04 - machine-id(5) о том, как пустой
/etc/machine-idзаменяется при загрузке