Klonowanie maszyny wirtualnej w Virt-Managerze za pomocą virt-clone i virt-sysprep

Klonowanie maszyny wirtualnej kopiuje bajty, nie tożsamość.

Page content

Virt-Manager (GUI dla libvirt) kopiuje dysk KVM i przypisuje klonowi UUID oraz adres MAC. Gość zachowuje swój machine-id oraz klucze SSH hosta, dopóki virt-sysprep ich nie wyczyści.

Ten przewodnik wykorzystuje gościa Ubuntu 26.04 oraz obraz qcow2 o pojemności 14 GB przechowywany w /mnt/extra2/vms. Polecenia dotyczące dysków są takie same dla innych gości Linux. virt-sysprep nie działa na gościach Windows.

Klonowanie dysku qcow2 między dwoma gośćmi KVM

Na hoście muszą już być zainstalowane KVM i libvirt. Jak zainstalować KVM na Ubuntu 24.04 to ten proces instalacji, który pociąga za sobą virtinst, dostarczając virt-clone. virt-sysprep, virt-customize, virt-cat oraz guestfish pochodzą z osobnego pakietu:

sudo apt install -y libguestfs-tools

Co faktycznie klonuje VM

libvirt dzieli tę pracę między trzy narzędzia. virt-clone kopiuje obrazy dysków i definiuje nową domenę z tym samym wirtualnym sprzętem. Zmienia nazwę domeny, UUID oraz adres MAC po stronie hosta. Hasła, nazwa hosta, statyczne adresy oraz pliki wewnątrz gościa pozostają niezmienione, co jest zachowaniem opisanym w dokumentacji virt-clone(1).

virt-sysprep otwiera dysk za pomocą libguestfs i edytuje system plików gościa. Manual virt-sysprep(1) jest jednoznaczny co do tego, że edycja następuje w miejscu (in place): nie ma flagi pliku wyjściowego, więc obraz przekazany do -a to ten, który ulega zmianie. Jeśli nadal potrzebujesz źródła, skopiuj lub sklonuj je najpierw.

qemu-img info raportuje, czy dany plik jest samodzielny, czy stanowi szczyt łańcucha plików bazowych (backing chain). qemu-img convert zapisuje nowy plik z rozwiązaniem łańcucha.

flowchart LR A[gość zatrzymany] -->|virt-clone| B[nowa domena i dysk] B -->|qemu-img info| C{plik bazowy?} C -->|tak| D[qemu-img convert] C -->|nie| E[samodzielny qcow2] D --> E E -->|kopia, a następnie virt-sysprep| F[szablon] F -->|indywidualna konfiguracja| [zaimportowany gość]

Wypłucz (flatten) obraz przed sysprep, gdy obecna jest linia pliku bazowego. Wykonaj sysprep na kopii, a następnie wyprowadzaj każdego działającego gościa z tego pliku.

Klonowanie dysku w Virt-Manager

Zatrzymaj gościa. virt-clone odrzuci działającą domenę, a kopia żywego dysku qcow2 nie będzie spójnym systemem plików.

W Virt-Managerze kliknij prawym przyciskiem myszy na gościa i wybierz Klonuj (Clone). Ustaw nową nazwę. Na etapie przechowywania nadaj każdemu dyskowi nową ścieżkę. Pozostawienie oryginalnej ścieżki w niezmienionym stanie zdefiniuje drugą domenę, która otworzy ten sam plik, w związku z czym obaj goście będą zapisywać te same bloki.

Nowy plik zostanie umieszczony obok źródła. Domyślna pula używa /var/lib/libvirt/images/. Dysk, który już znajduje się na /mnt/extra2/vms, zostanie sklonowany do tego katalogu. Zanotuj ścieżkę, którą wypisuje virt-clone, lub odczytaj ją ponownie:

virsh domblklist ubuntu26.04-base14gb-clone

Ekwivalent z linii poleceń, z jawnie wybraną nazwą i ścieżką dysku:

virt-clone --original ubuntu26.04-base14gb \
  --name ubuntu26.04-base14gb-clone \
  --file /mnt/extra2/vms/ubuntu26.04-base14gb-clone.qcow2

--auto-clone wymyśla nazwę i ścieżkę dysku. To wygodne w przypadku jednorazowej kopii. Ścieżka szablonu jest łatwiejsza do utrzymania, gdy sam przekazujesz --name i --file. Pomiń --mac lub przekaż --mac RANDOM, a virt-clone wygeneruje adres w zakresie QEMU 52:54:00:xx:xx:xx.

--reflink prosi o lekką kopię. Manual dla virt-clone na Ubuntu 26.04 ogranicza tę flagę do obrazów raw na tym samym systemie plików btrfs, dlatego pomija te pliki qcow2. Nakładka qcow2 (qcow2 overlay) to osobna konfiguracja, omówiona poniżej z qemu-img create -b.

Czy twój klon ma plik bazowy (backing file)?

Wykonaj to na nowym dysku, zanim potraktujesz go jako niezależny:

qemu-img info --backing-chain /mnt/extra2/vms/ubuntu26.04-base14gb-clone.qcow2

Samodzielny obraz wymienia file format, virtual size oraz disk size. Nakładka wymienia również linię backing file: wskazującą na obraz, przez który czyta. virtual size to rozmiar dysku gościa, tutaj około 14 GB. disk size to ilość miejsca, które plik zajmuje aktualnie, co jest małe dla nowej nakładki i rośnie w miarę, jak gość zapisuje dane.

virt-clone to nie jest typowe źródło tej linii. Nakładka pochodzi z qemu-img create -b, z samodzielnego snapshotu dysku lub z narzędzia, które celowo utworzyło deltę qcow2. To właśnie sprawdzanie informacjami (info check) pozwala odróżnić te przypadki od pełnej kopii.

Zachowuj nakładkę tylko wtedy, gdy plik bazowy pozostanie na swoim miejscu i nie będzie już do niego zapisywany. Każdy zapis z klona trafia do małego pliku; odczyty, które nie znajdą się w nakładce, pochodzą z pliku bazowego. Przeniesienie lub edycja pliku bazowego psuje każdego gościa, który go nazwał.

flowchart TB subgraph linked O[base.qcow2 tylko do odczytu] C1[vm1.qcow2 tylko delty] C2[vm2.qcow2 tylko delty] C1 -->|backing file| O C2 -->|backing file| O end subgraph flat F1[vm1-flat.qcow2 samodzielny] F2[vm2-flat.qcow2 samodzielny] end

Aby stworzyć samodzielny plik, przekonwertuj nakładkę. -p wypisuje postęp. Docelowo jest to nowy plik; nakładka i plik bazowy pozostają bez zmian:

qemu-img convert -p -O qcow2 \
  /mnt/extra2/vms/ubuntu26.04-base14gb-clone.qcow2 \
  /mnt/extra2/vms/ubuntu26.04-base14gb-flat.qcow2

Uruchom qemu-img info na spłaszczonym pliku i upewnij się, że nie ma linii backing file:. Szablonem jest ten samodzielny plik. Nakładki to sposób na “stemplowanie” (tworzenie instancji) gości z niego później, nie samym szablonem.

Reflink btrfs to trzeci przypadek. cp --reflink=auto może współdzielić fizyczne zakresy (extents) między dwoma plikami, a qemu-img info nadal nie pokaże pliku bazowego, ponieważ każda ścieżka to kompletny obraz. Ta kopia jest niezależna na poziomie qcow2, nawet jeśli system plików nie zdążył jeszcze zdublować każdego bloku.

virt-sysprep: resetowanie tożsamości

Skopiuj samodzielny obraz, a następnie wykonaj sysprep na kopii. --reflink=auto współdzieli zakresy, gdy system plików to wspiera, a w przeciwnym razie wykonuje zwykłą kopię, w tym na ext4. -n to przebieg na sucho (dry run), który odrzuca swoje zapisy:

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

W domyślnej puli Ubuntu obraz często ma uprawnienia 0600 i jest właścicielem libvirt-qemu. Manual zaleca nadanie użytkownikowi uprawnień do zapisu, zamiast uruchamiać jako root. Gdy użytkownik qemu jest właścicielem pliku, sudo virt-sysprep -a ... to wywołanie, które może go otworzyć. Gość musi być zatrzymany, a żaden inny proces nie może mieć obrazu otwartego.

--hostname to opcja konfiguracyjna (customize), a konfigurowanie jest częścią domyślnego zestawu operacji, więc wykonywane jest w tym samym wywołaniu. Nie ma osobnej domyślnej operacji, która samodziennie czyści /etc/hostname. --operations zastępuje ten domyślny zestaw, gdy go przekazasz; --operations defaults,-ssh-userdir zachowuje domyślne i wyłącza jedną operację.

Oto operacje, które decydują, czy klon nie będzie konfliktować z oryginałem. Lista ta pochodzi z aktualnego manuala virt-sysprep, co warto przeczytać, ponieważ krótka lista --operations cicho odrzuca resztę:

Operacja Domyślna Wpływ na gościa
machine-id tak Czyści machine ID. systemd wygeneruje nowy przy następnym uruchomieniu, gdy /etc/machine-id jest pusty.
ssh-hostkeys tak Usuwa /etc/ssh/ssh_host_*. Przy następnym uruchomieniu utworzy nowe klucze hosta.
ssh-userdir tak Usuwa .ssh pod /root i /home/*, w tym authorized_keys i klucze prywatne przechowywane w gościu.
dhcp-client-state tak Usuwa dzierżawy klienta DHCP.
udev-persistent-net tak Usuwa reguły udev, które mapują stary adres MAC na stałą nazwę, taką jak eth0.
net-hwaddr tak Usuwa HWADDR z plików ifcfg-* w systemach Fedora i RHEL. Nie edytuje netplan w Ubuntu.
lvm-uuids, lvm-system-devices tak Przypisuje nowe UUID LVM i usuwa /etc/lvm/devices/system.devices, które inaczej przypina gościa do WWID źródłowego dysku.
logfiles, bash-history, tmp-files tak Usuwa logi, historię powłoki i pliki tymczasowe.

ssh-userdir to ta operacja, która zaskakuje osoby klonujące maszynę, do której nadal się logują. Szablon nie powinien przenosić kluczy prywatnych źródła, więc pozostaw operację włączoną i wstrzykuj klucze per instancja później. Dla jednorazowej kopii, która musi zachować istniejące authorized_keys, przekaż --operations defaults,-ssh-userdir.

user-account nie znajduje się w domyślnym zestawie, a hasła pozostają, chyba że przekazasz --password lub --root-password. fs-uuids jest również domyślnie wyłączony. Manual informuje, że nie aktualizuje wszystkich odwołań, w tym /etc/fstab, i że włączenie go prawdopodobnie uczyni gościa nierozruchowym.

Obrazy Ubuntu Server zazwyczaj mają cloud-init, a virt-sysprep nie ma operacji cloud-init. Stary instance id pod /var/lib/cloud sprawia, że klon pomija konfigurację pierwszego uruchomienia. Wyczyść to na szablonie i powiedz cloud-init, by pozostawił nazwę hosta, którą napisał --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'

Ten sam manual ostrzega przed klonowaniem gościa, który używa wewnętrznej szyfrowania całego dysku w celu dystrybucji: każda kopia współdzieli klucz wolumenu. Wskazuje również, że usunięte pliki są tylko odłączane (unlink), a nie czyśczone (scrub). --scrub nadpisuje nazwany plik, a virt-sparsify może usunąć zwolnioną przestrzeń z obrazu.

Jak klon otrzymuje adres IP

virt-sysprep nie ma operacji, która przepisywałaby adres. Gość, który używał DHCP, zapyta ponownie. Klon ma nowy adres MAC, pusty machine-id i nie ma starego pliku dzierżawy, więc serwer DHCP w sieci default libvirt potraktuje go jako nowego klienta.

Statyczny blok addresses: w netplan jest kopiowany razem z dyskiem, a obaj goście następnie roszczą do niego roszczenia. Przeczytaj pliki przed pierwszym uruchomieniem. virt-ls i virt-cat to narzędzia jednorazowe; guestfish --ro -a <disk> -i to ta sama inspekcja w powłoce, po której ls /etc/netplan i cat działają na gościa:

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

Obrazy instalacyjne często używają 00-installer-config.yaml lub 01-netcfg.yaml. Obrazy chmurowe używają 50-cloud-init.yaml, które cloud-init odtworzy, chyba że konfiguracja sieci jest wyłączona. Netplan scala każdy plik YAML w katalogu, więc pozostały statyczny plik nadal się zastosuje, nawet po dodaniu pliku DHCP.

Aby uczynić szablon klientem DHCP, usuń te pliki i wgraj jeden zastępczy. Użyj nazwy interfejsu, którą pokazał virt-cat. W gościu zainstalowanym pod KVM ta nazwa to często ens3 lub enp1s0, a virt-clone zachowuje ten sam wirtualny slot PCI, więc nazwa pozostaje ważna:

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}'

Dla statycznego adresu, bramy i DNS użyj tego samego wgrywania z YAML-em z Jak zmienić statyczny adres IP w Ubuntu Server. Każda instancja będzie następnie potrzebować własnego pliku, zastosowanego do dysku instancji, a nie szablonu.

Nazwa w YAML musi istnieć wewnątrz gościa. Dysk przeniesiony ze sprzętu fizycznego często nazywa kartę sieciową enp2s0, podczas gdy ten sam system pod virtio prezentuje inną nazwę, a netplan konfiguruje wtedy interfejs, którego tam nie ma. Dla szablonu, który ma się uruchamiać na więcej niż jednym typie maszyny, przypnij kernela do eth0 i użyj tego klucza w netplan. Ubuntu wczytuje /etc/default/grub.d/*.cfg podczas budowania 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 działa wewnątrz aplikacji libguestfs. Jeśli grub-probe nie może zobaczyć tam dysku rozruchowego, polecenie się nie powiedzie i wiersz poleceń (cmdline) pozostanie bez zmian. W takim przypadku ustaw nazwę interfejsu w netplan na nazwę, którą gość już używa, i pomiń przełączenie na eth0.

Indywidualna konfiguracja instancji z virt-customize

Uruchamiaj instancje z kopii czystego pliku. Nie wskazuj domeny do samego szablonu.

Pełna kopia nie ma zależności operacyjnych od szablonu:

cp --reflink=auto \
  /mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2 \
  /mnt/extra2/vms/ubuntu26.04-vm1.qcow2

Nakładka przechowuje tylko bloki zapisywane przez vm1. -F qcow2 zapisuje format bazy, aby QEMU nie musiał go wykrywać (probe):

qemu-img create -f qcow2 \
  -b /mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2 \
  -F qcow2 \
  /mnt/extra2/vms/ubuntu26.04-vm1.qcow2

Ścieżka do bazy jest zapisana wewnątrz nakładki. Musi ona zachować tę ścieżkę i pozostawać tylko do odczytu, dla każdego gościa zbudowanego w ten sposób.

Uwagi bezpieczeństwa dotyczące virt-sysprep opisują drugi przebieg na każdym nowym dysku. Sysprep zapisuje losowy nasionnik (seed) do szablonu; goście sklonowani z tego pliku inaczej rozpoczynaliby się z tym samym nasionkiem, co czyni klucze hosta SSH i numery sekwencji TCP przy pierwszym uruchomieniu przewidywalnymi. --enable customize przepisuje nasionnik. --hostname i --ssh-inject to opcje konfiguracyjne, więc należy je umieścić w tym samym poleceniu. Podstaw konto, które faktycznie istnieje w obrazie, za ubuntu:

virt-sysprep --enable customize \
  -a /mnt/extra2/vms/ubuntu26.04-vm1.qcow2 \
  --hostname vm1 \
  --ssh-inject "ubuntu:file:${HOME}/.ssh/id_ed25519.pub"

Przekazuj plik instancji libvirt, nie szablon. Jeśli utworzyłeś go jako swój użytkownik poza pulą przechowywania, libvirt-qemu potrzebuje dostępu do odczytu, w przeciwnym razie domena nie uruchomi się z powodu błędu uprawnień na qcow2.

Importowanie do Virt-Manager

Dla każdego dysku instancji otwórz Virt-Manager, wybierz Nowa maszyna wirtualna (New Virtual Machine) i zaznacz Import istniejącego obrazu dysku (Import existing disk image). Wskaż go do ubuntu26.04-vm1.qcow2. Pozycja systemu operacyjnego powinna być Ubuntu 26.04, gdy baza osinfo na hoście go ma.

Pasujący krótki identyfikator to ubuntu26.04. Sprawdź bazę na hoście przed poleganiem na nim:

osinfo-query os | grep ubuntu26

Jeśli to nic nie wypisze, zainstalowana baza jest starsza niż wpis dla 26.04. --os-variant ubuntu24.04 nadal wybra typ maszyny przyjazny virtio dla już zainstalowanego gościa. --import mówi virt-install, że dysk już zawiera system operacyjny.

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 podłącza sieć NAT, której instancja dnsmasq wydaje dzierżawę DHCP. Po uruchomieniu:

virsh domifaddr ubuntu26.04-vm1 --source lease
virsh dumpxml ubuntu26.04-vm1 | grep "<mac"

--source lease odczytuje tabelę tego dnsmasq. Pozostaje pusty dla statycznego adresu, mostu (bridge) lub karty sieciowej, która nie jest na wirtualnej sieci libvirt. Ci goście potrzebują qemu-guest-agent w obrazie i virsh domifaddr ubuntu26.04-vm1 --source agent, lub przeszukiwania ARP z --source arp. virsh net-dhcp-leases default wymienia każdą dzierżawę w sieci NAT, gdy chcesz widok puli, a nie jednej domeny.

Strategia Przestrzeń na VM Czas tworzenia Ograniczenie Użyj, gdy
Pełna kopia, lub cp --reflink=auto około 14 GB logicznie; reflink współdzieli bloki, dopóki się nie zmienią minuty, lub natychmiastowo z reflinkiem reflink wymaga systemu plików, który go wspiera, takiego jak btrfs gość, który ma przetrwać dłużej niż szablon
Nakładka qcow2 megabajty na początku sekundy ścieżka bazy musi pozostać, a baza musi być tylko do odczytu wiele podobnych gości z jednego zamkniętego obrazu
virt-clone --reflink obraz raw, współdzielone zakresy natychmiastowo dyski raw na tym samym systemie plików btrfs; qcow2 jest pomijane obrazy raw już przechowywane na btrfs

Gość, który ma być utrzymywany przez miesiące, to pełna kopia lub reflink. Krótkotrwały gość może być nakładką, o ile plik bazowy jest nadal obecny podczas jego działania. Proxmox to inna ścieżka self-hosted, gdy chcesz modelu szablonu i klonowania w stylu centrum danych na własnym interfejsie sieciowym. Multipass uruchamia obrazy chmurowe Ubuntu dla pojedynczego użytkownika i sam aplikuje cloud-init, co jest innym workflow niż zamykanie (sealing) dysku, który już zainstalowałeś.

Rozwiązywanie problemów: gdy klon nie uruchamia się

Brak adresu. Sprawdź plik netplan virt-cat i porównaj klucz interfejsu z ip link na konsoli. Wpis match: macaddress nadal ustawiony na adres MAC źródła odrzuci nową kartę sieciową. Klucz nazywający interfejs, którego gość nie ma, robi to samo. Napraw plik na dysku lub zastosuj cmdline eth0 powyżej i przebuduj instancję z szablonu.

Adres jest, ale ten sam co w oryginale. Statyczny blok addresses: wciąż znajduje się w jednym z plików netplan. virt-sysprep go nie usunął. Wgraj zastępczy plik i usuń inne pliki YAML w /etc/netplan.

SSH mówi, że klucz hosta się zmienił, lub akceptuje klona jako oryginał. Klucze hosta są współdzielone, gdy ssh-hostkeys nie wykonał się na pliku, który otwiera domena. Potwierdź za pomocą virsh domblklist, że domena używa dysku po sysprep, a następnie sprawdź qemu-img info, aby upewnić się, że nie wykonałeś sysprep na nakładce, podczas gdy gość uruchamia się z innej ścieżki. Jeśli klon celowo zachował oryginalny IP, klienci, którzy przechowywali stary klucz w known_hosts, będą ostrzegać, dopóki ta linia nie zostanie usunięta. To ostrzeżenie to regeneracja opisana w manualu.

Logowanie kluczem nie działa na klonie maszyny, do której wcześniej można było uzyskać dostęp. Domyślny sysprep usunął .ssh z katalogów domowych. Wstrzyknij klucz za pomocą --ssh-inject lub przełącz ponownie z --operations defaults,-ssh-userdir, jeśli ta kopia powinna je zachować.

Wolumeny LVM brakują po uruchomieniu. Gość ma /etc/lvm/devices/system.devices ze źródła, a WWID wirtualnego dysku się zmienił. Domyślna operacja lvm-system-devices usuwa ten plik. Ręcznie dobrana lista --operations musi go zawierać, a także lvm-uuids, gdy gość używa LVM.

Jeden klon czy szablon

Pojedyncza dodatkowa maszyna to virt-clone, sprawdzenie pliku bazowego i virt-sysprep na nowym dysku. Flota to jeden zamknięty samodzielny plik, a następnie kopia lub nakładka per gość, z --enable customize na własnym dysku tego gościa przed uruchomieniem.

Nakładki czynią zamknięty plik częścią ścieżki operacyjnej każdego gościa, który go nazwał. Pełne kopie i reflinki tego nie robią. Wybierz tę zależność zgodnie z czasem życia gościa i pozostaw fs-uuids wyłączony, aby bootloader i /etc/fstab nadal pasowały do systemu plików.

Przydatne linki

Źródła

Subskrybuj

Otrzymuj nowe wpisy o systemach, infrastrukturze i inżynierii AI.