Клонирование виртуальной машины в 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.

Клонирование диска qcow2 между двумя гостевыми системами KVM

На хосте уже должны быть установлены 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 записывает новый файл с разрешенной цепочкой.

flowchart LR A[гость выключен] -->|virt-clone| B[новый домен и диск] B -->|qemu-img info| C{есть базовый файл?} C -->|да| D[qemu-img convert] C -->|нет| E[самостоятельный qcow2] D --> E E -->|копирование, затем virt-sysprep| F[шаблон] F -->|персонализация для каждого экземпляра| G[импортированный гость]

Выполняйте «схлопывание» (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. Именно проверка информации позволяет отличить эти случаи от полной копии.

Оставляйте оверлей только в том случае, если базовый образ останется на месте и больше не будет перезаписываться. Все записи от клона попадают в небольшой файл; чтения, которые не найдены в оверлее, берутся из базового. Перемещение или редактирование базового образа сломает всех гостей, ссылающихся на него.

flowchart TB subgraph linked O[base.qcow2 только чтение] C1[vm1.qcow2 только дельты] C2[vm2.qcow2 только дельты] C1 -->|базовый файл| O C2 -->|базовый файл| O end subgraph flat F1[vm1-flat.qcow2 самостоятельный] F2[vm2-flat.qcow2 самостоятельный] end

Чтобы сделать самостоятельный файл, сконвертируйте оверлей. -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 по-прежнему соответствовали файловой системе.

Полезные ссылки

Ссылки

  • 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 заменяется при загрузке

Подписаться

Получайте новые материалы про системы, инфраструктуру и AI engineering.