Clona una VM in Virt-Manager con virt-clone e virt-sysprep
Clonare una VM duplica i byte, non l'identità.
Virt-Manager (la GUI di libvirt) copia un disco KVM e assegna al clone un UUID e un MAC. L’ospite mantiene il proprio machine-id e le chiavi host SSH finché virt-sysprep non li elimina.
Questa guida utilizza un ospite Ubuntu 26.04 e un’immagine qcow2 da 14 GB archiviata in /mnt/extra2/vms. I comandi per i dischi sono gli stessi per altri ospiti Linux. virt-sysprep non opera su ospiti Windows.

L’host deve già disporre di KVM e libvirt. Come installare KVM su Ubuntu 24.04 è quella configurazione, e include virtinst, che fornisce virt-clone. virt-sysprep, virt-customize, virt-cat e guestfish provengono da un pacchetto separato:
sudo apt install -y libguestfs-tools
Cosa clona effettivamente una VM
libvirt divide il lavoro in tre strumenti. virt-clone copia le immagini disco e definisce un nuovo dominio con lo stesso hardware virtuale. Modifica il nome del dominio, l’UUID e il MAC lato host. Le password, il hostname, gli indirizzi statici e i file all’interno dell’ospite non vengono modificati, che è il comportamento documentato da virt-clone(1).
virt-sysprep apre il disco con libguestfs e modifica il filesystem dell’ospite. Il manuale virt-sysprep(1) specifica che la modifica avviene in loco: non esiste un flag per il file di output, quindi l’immagine passata a -a è l’immagine che viene modificata. Esegui una copia o un clone prima, se hai ancora bisogno dell’originale.
qemu-img info riporta se quel file è autonomo o la cima di una catena di backing. qemu-img convert scrive un nuovo file con la catena risolta.
Appiattire prima di sysprep quando è presente una linea di backing. Eseguire sysprep sulla copia, poi derivare ogni ospite in esecuzione da quel file.
Clonazione del disco in Virt-Manager
Spegnere l’ospite. virt-clone rifiuta un dominio in esecuzione, e una copia di un qcow2 live non è un filesystem coerente.
In Virt-Manager, fare clic destro sull’ospite e scegliere Clone. Impostare il nuovo nome. Al passaggio di archiviazione, assegnare a ogni disco un nuovo percorso. Lasciare il percorso originale invariato definisce un secondo dominio che apre lo stesso file, quindi entrambi gli ospiti scrivono gli stessi blocchi.
Il nuovo file viene posizionato accanto alla sorgente. Un pool predefinito usa /var/lib/libvirt/images/. Un disco che si trova già in /mnt/extra2/vms viene clonato in quella directory. Prendere nota del percorso stampato da virt-clone, o rileggilo:
virsh domblklist ubuntu26.04-base14gb-clone
L’equivalente da riga di comando, con il nome e il percorso del disco scelti esplicitamente:
virt-clone --original ubuntu26.04-base14gb \
--name ubuntu26.04-base14gb-clone \
--file /mnt/extra2/vms/ubuntu26.04-base14gb-clone.qcow2
--auto-clone inventa il nome e il percorso del disco. È comodo per una copia temporanea. Un percorso template è più facile da mantenere quando si passano --name e --file manualmente. Omettere --mac, o passare --mac RANDOM, e virt-clone genera un indirizzo nell’intervallo QEMU 52:54:00:xx:xx:xx.
--reflink richiede una copia leggera. Il manuale di virt-clone per Ubuntu 26.04 limita quel flag alle immagini raw sullo stesso filesystem btrfs, quindi salta questi file qcow2. Un overlay qcow2 è una configurazione separata, coperta con qemu-img create -b di seguito.
Il tuo clone ha un file backing?
Eseguire questo sul nuovo disco prima di trattarlo come indipendente:
qemu-img info --backing-chain /mnt/extra2/vms/ubuntu26.04-base14gb-clone.qcow2
Un’immagine autonota elenca file format, virtual size e disk size. Un overlay elenca anche una linea backing file: che punta all’immagine da cui legge. virtual size è la dimensione del disco dell’ospite, qui circa 14 GB. disk size è lo spazio che il file occupa attualmente, che è piccolo per un overlay fresco e cresce man mano che l’ospite scrive.
virt-clone non è la solita fonte di quella linea. Un overlay proviene da qemu-img create -b, da uno snapshot solo-disco, o da uno strumento che ha creato intenzionalmente un delta qcow2. Il controllo info è ciò che distingue questi casi da una copia completa.
Conservare l’overlay solo quando la base rimarrà dove si trova e non verrà scritta di nuovo. Ogni scrittura dal clone finisce nel file piccolo; le letture che non trovano il dato nell’overlay provengono dalla base. Spostare o modificare la base rompe ogni ospite che la chiama.
Per creare un file autonomo, convertire l’overlay. -p stampa i progressi. La destinazione è un nuovo file; l’overlay e la base restano come sono:
qemu-img convert -p -O qcow2 \
/mnt/extra2/vms/ubuntu26.04-base14gb-clone.qcow2 \
/mnt/extra2/vms/ubuntu26.04-base14gb-flat.qcow2
Eseguire qemu-img info sul file piatto e confermare che non ci sia una linea backing file:. Un template è quel file autonomo. Gli overlay sono il modo per generare ospiti da esso in seguito, non il template stesso.
Un reflink btrfs è un terzo caso. cp --reflink=auto può condividere estensioni fisiche tra due file, e qemu-img info mostra ancora nessun file backing, perché ogni percorso è un’immagine completa. Quella copia è indipendente a livello qcow2 anche se il filesystem non ha ancora duplicato ogni blocco.
virt-sysprep: reimpostare l’identità
Copiare l’immagine autonota, poi eseguire sysprep sulla copia. --reflink=auto condivide le estensioni se il filesystem lo supporta e altrimenti fa una copia normale, incluso su ext4. -n è un dry run che scarta le sue scritture:
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
Su un pool Ubuntu predefinito l’immagine ha spesso modalità 0600 ed è di proprietà di libvirt-qemu. Il manuale raccomanda di dare al proprio utente accesso in scrittura piuttosto che eseguire come root. Quando l’utente qemu possiede il file, sudo virt-sysprep -a ... è l’invocazione che può aprirlo. L’ospite deve essere spento, e nulla di altro dovrebbe avere l’immagine aperta.
--hostname è un’opzione di personalizzazione, e la personalizzazione fa parte del set di operazioni predefinite, quindi viene eseguita nella stessa invocazione. Non c’è un’operazione predefinita separata che cancelli /etc/hostname da sola. --operations sostituisce quel set predefinito quando viene passato; --operations defaults,-ssh-userdir mantiene i predefiniti e disattiva un’operazione.
Queste sono le operazioni che decidono se il clone collide con l’originale. L’elenco è quello nel manuale virt-sysprep attuale, che vale la pena leggere perché un breve elenco --operations elimina silenziosamente il resto:
| Operazione | Predefinita | Effetto sull’ospite |
|---|---|---|
| machine-id | sì | Cancella il machine ID. systemd ne genera uno nuovo al prossimo avvio se /etc/machine-id è vuoto. |
| ssh-hostkeys | sì | Rimuove /etc/ssh/ssh_host_*. Il prossimo avvio crea nuove chiavi host. |
| ssh-userdir | sì | Rimuove .ssh sotto /root e /home/*, incluse authorized_keys e chiavi private conservate nell’ospite. |
| dhcp-client-state | sì | Rimuove i lease del client DHCP. |
| udev-persistent-net | sì | Rimuove le regole udev che mappano un vecchio MAC a un nome fisso come eth0. |
| net-hwaddr | sì | Rimuove HWADDR dai file ifcfg-* di Fedora e RHEL. Non modifica netplan di Ubuntu. |
| lvm-uuids, lvm-system-devices | sì | Assegna nuovi UUID LVM e rimuove /etc/lvm/devices/system.devices, che altrimenti fissa l’ospite ai WWID del disco sorgente. |
| logfiles, bash-history, tmp-files | sì | Rimuove log, cronologia shell e file temporanei. |
ssh-userdir è quella che sorprende chi clona una macchina a cui accede ancora. Il template non dovrebbe portare le chiavi private della sorgente, quindi lasciare l’operazione attiva e iniettare una chiave per istanza in seguito. Per una copia occasionale che deve mantenere le esistenti authorized_keys, passare --operations defaults,-ssh-userdir.
user-account non è nel set predefinito, e le password restano a meno che non si passi --password o --root-password. fs-uuids è anche disattivato predefinitamente. Il manuale dice che non aggiorna ogni riferimento, incluso /etc/fstab, e che abilitarlo potrebbe rendere l’ospite non avviabile.
Le immagini Ubuntu Server hanno di solito cloud-init, e virt-sysprep non ha un’operazione cloud-init. Un vecchio instance id sotto /var/lib/cloud fa sì che il clone salti la configurazione del primo avvio. Pulirlo nel template, e dire a cloud-init di mantenere l’hostname che --hostname ha scritto:
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'
Lo stesso manuale avverte contro la clonazione di un ospite che usa la crittografia interna full-disk per la distribuzione: ogni copia condivide la chiave del volume. Nota anche che i file eliminati sono unlinkati, non cancellati. --scrub sovrascrive un file specificato, e virt-sparsify può rimuovere lo spazio liberato dall’immagine.
Come il clone ottiene il suo indirizzo IP
virt-sysprep non ha un’operazione che riscriva un indirizzo. Un ospite che usava DHCP chiede di nuovo. Il clone ha un nuovo MAC, un machine-id vuoto e nessun file di lease vecchio, quindi il server DHCP sulla rete default di libvirt lo tratta come un nuovo client.
Un blocco statico addresses: in netplan viene copiato con il disco, e entrambi gli ospiti lo rivendicano. Leggere i file prima del primo avvio. virt-ls e virt-cat sono gli strumenti one-shot; guestfish --ro -a <disk> -i è la stessa ispezione come shell, dopo cui ls /etc/netplan e cat vengono eseguiti contro l’ospite:
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
Le immagini dell’installer usano spesso 00-installer-config.yaml o 01-netcfg.yaml. Le immagini cloud usano 50-cloud-init.yaml, che cloud-init ricreerà a meno che la configurazione di rete non sia disabilitata. Netplan unisce ogni file YAML nella directory, quindi un file statico residuo si applica ancora dopo aver aggiunto un file DHCP.
Per rendere il template un client DHCP, rimuovere quei file e caricarne uno sostitutivo. Usare il nome dell’interfaccia mostrato da virt-cat. Su un ospite installato sotto KVM quel nome è spesso ens3 o enp1s0, e virt-clone mantiene la stessa slot PCI virtuale, quindi il nome resta valido:
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}'
Per un indirizzo, gateway e DNS statici, usare lo stesso caricamento con lo YAML da Come modificare un indirizzo IP statico in Ubuntu Server. Ogni istanza ha poi bisogno del proprio file, applicato al disco dell’istanza piuttosto che al template.
Il nome nello YAML deve esistere all’interno dell’ospite. Un disco spostato da hardware fisico spesso nomina la NIC enp2s0, mentre lo stesso sistema sotto virtio presenta un nome diverso, e netplan configura allora un’interfaccia che non c’è. Per un template che dovrebbe avviarsi su più tipi di macchina, fissare il kernel su eth0 e usare quella chiave in netplan. Ubuntu importa /etc/default/grub.d/*.cfg durante la costruzione di 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 viene eseguito all’interno dell’appliance libguestfs. Se grub-probe non vede il disco di avvio lì, il comando fallisce e la cmdline non cambia. In tal caso, impostare il nome dell’interfaccia in netplan al nome che l’ospite usa già, e saltare l’interruttore su eth0.
Personalizzazione per istanza con virt-customize
Avviare le istanze da copie del file pulito. Non puntare un dominio al template stesso.
Una copia completa non ha dipendenze runtime dal template:
cp --reflink=auto \
/mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2 \
/mnt/extra2/vms/ubuntu26.04-vm1.qcow2
Un overlay conserva solo i blocchi scritti da vm1. -F qcow2 registra il formato della base così QEMU non deve esplorarlo:
qemu-img create -f qcow2 \
-b /mnt/extra2/vms/ubuntu26.04-base14gb-clean.qcow2 \
-F qcow2 \
/mnt/extra2/vms/ubuntu26.04-vm1.qcow2
Il percorso della base è conservato all’interno dell’overlay. Deve mantenere quel percorso, e deve restare solo-lettura, per ogni ospite costruito in questo modo.
Le note di sicurezza di virt-sysprep descrivono un secondo passaggio su ogni nuovo disco. Sysprep scrive un seed casuale nel template; gli ospiti clonati da quel file altrimenti partirebbero con lo stesso seed, il che rende prevedibili le chiavi host SSH del primo avvio e i numeri di sequenza TCP. --enable customize riscrive il seed. --hostname e --ssh-inject sono opzioni di personalizzazione, quindi appartengono allo stesso comando. Sostituire l’account che esiste effettivamente nell’immagine per ubuntu:
virt-sysprep --enable customize \
-a /mnt/extra2/vms/ubuntu26.04-vm1.qcow2 \
--hostname vm1 \
--ssh-inject "ubuntu:file:${HOME}/.ssh/id_ed25519.pub"
Passare il file dell’istanza a libvirt, non il template. Se l’hai creato come tuo utente fuori da un pool di archiviazione, libvirt-qemu ha bisogno di accesso in lettura o il dominio fallisce all’avvio con un errore di permesso sul qcow2.
Importazione in Virt-Manager
Per ogni disco di istanza, aprire Virt-Manager, scegliere New Virtual Machine, e selezionare Import existing disk image. Puntarlo a ubuntu26.04-vm1.qcow2. La voce OS dovrebbe essere Ubuntu 26.04 se il database osinfo dell’host lo ha.
L’id breve corrispondente è ubuntu26.04. Controllare il database dell’host prima di fare affidamento su di esso:
osinfo-query os | grep ubuntu26
Se non stampa nulla, il database installato è più vecchio della voce 26.04. --os-variant ubuntu24.04 seleziona comunque un tipo di macchina virtio-friendly per un ospite già installato. --import dice a virt-install che il disco contiene già un OS.
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 allega la rete NAT la cui istanza dnsmasq emette il lease DHCP. Dopo l’avvio:
virsh domifaddr ubuntu26.04-vm1 --source lease
virsh dumpxml ubuntu26.04-vm1 | grep "<mac"
--source lease legge quella tabella dnsmasq. Resta vuoto per un indirizzo statico, per un bridge, o per una NIC che non è su una rete virtuale libvirt. Quegli ospiti hanno bisogno di qemu-guest-agent nell’immagine e virsh domifaddr ubuntu26.04-vm1 --source agent, o una ricerca ARP con --source arp. virsh net-dhcp-leases default elenca ogni lease sulla rete NAT quando si vuole la vista del pool piuttosto che un dominio.
Scelta di una strategia di clonazione: copia completa, overlay, o reflink
| Strategia | Spazio per VM | Tempo di creazione | Vincolo | Usare quando |
|---|---|---|---|---|
Copia completa, o cp --reflink=auto |
circa 14 GB logici; reflink condivide blocchi finché non cambiano | minuti, o quasi istantaneo con reflink | reflink ha bisogno di un filesystem che lo supporta, come btrfs | un ospite che dovrebbe sopravvivere al template |
| overlay qcow2 | megabytes all’inizio | secondi | il percorso della base deve rimanere, e la base deve restare solo-lettura | molti ospiti simili da un’immagine sigillata |
virt-clone --reflink |
immagine raw, estensioni condivise | quasi istantaneo | dischi raw sullo stesso filesystem btrfs; qcow2 viene saltato | immagini raw già archiviate su btrfs |
Un ospite che si prevede di mantenere per mesi è una copia completa o un reflink. Un ospite di breve durata può essere un overlay, purché il file base ci sia ancora quando funziona. Proxmox è l’altra strada self-hosted quando si vuole un modello di template e clone di tipo datacenter con la propria UI web. Multipass avvia immagini cloud Ubuntu per un singolo utente e applica cloud-init da solo, che è un flusso di lavoro diverso dal sigillare un disco già installato.
Risoluzione dei problemi: quando il clone non si avvia
Nessun indirizzo. Eseguire virt-cat sul file netplan e confrontare la chiave dell’interfaccia con ip link sulla console. Un’ voce match: macaddress ancora impostata sul MAC della sorgente fa cadere la nuova NIC. Una chiave che nomina un’interfaccia che l’ospite non ha fa la stessa cosa. Correggere il file sul disco, o applicare la cmdline eth0 di cui sopra e ricostruire l’istanza dal template.
Indirizzo su, uguale all’originale. Il blocco statico addresses: è ancora in uno dei file netplan. virt-sysprep non lo ha rimosso. Caricare una sostituzione e eliminare gli altri file YAML in /etc/netplan.
SSH dice che la chiave host è cambiata, o accetta il clone come l’originale. Le chiavi host sono condivise quando ssh-hostkeys non è stato eseguito sul file che il dominio apre. Confermare con virsh domblklist che il dominio usa il disco sysprepped, poi controllare qemu-img info per assicurarsi di non aver sysprepped un overlay mentre l’ospite si avvia da un percorso diverso. Se il clone ha mantenuto l’IP originale intenzionalmente, i client che hanno memorizzato la vecchia chiave in known_hosts avviseranno finché quella linea non viene rimossa. Quel avvertimento è la rigenerazione descritta nel manuale.
Il login con chiave fallisce su un clone di una macchina a cui si poteva accedere prima. Il sysprep predefinito ha rimosso .ssh dalle directory home. Iniettare una chiave con --ssh-inject, o ri-eseguire con --operations defaults,-ssh-userdir se questa copia avrebbe dovuto mantenerle.
Volumi LVM mancanti dopo l’avvio. L’ospite ha /etc/lvm/devices/system.devices dalla sorgente, e il WWID del disco virtuale è cambiato. L’operazione predefinita lvm-system-devices rimuove quel file. Un elenco --operations scelto a mano deve includerlo, e lvm-uuids, quando l’ospite usa LVM.
Un clone o un template
Una singola macchina extra è virt-clone, un controllo del file backing, e virt-sysprep sul nuovo disco. Un’intera flotta è un file autonomo sigillato, poi una copia o un overlay per ospite, con --enable customize sul disco di quell’ospite prima che si avvia.
Gli overlay rendono il file sigillato parte del percorso runtime di ogni ospite che lo nomina. Le copie complete e i reflink non lo fanno. Scegliere quella dipendenza con la durata dell’ospite, e lasciare fs-uuids disattivato così il bootloader e /etc/fstab corrispondono ancora al filesystem.
Link utili
- Strumenti per sviluppatori: La guida completa ai flussi di lavoro di sviluppo moderni
- [Come installare Ubuntu 24.04 e strumenti utili](https://www.glukhov.org/it/developer-tools/local-dev-platforms/install-linux-ubuntu-24-04/ “Come installare Ubuntu 24.04 - passi e pacchetti e strumenti utili”})
- GNOME Boxes: Funzionalità, Vantaggi, Sfide e Alternative
Riferimenti
- virt-clone(1) su Ubuntu 26.04, incluso
--auto-clone,--filee--reflink - virt-sysprep(1) operazioni, modifiche in loco e la nota sul seed casuale
- virt-customize(1) per
--hostname,--ssh-inject,--uploade--run-command - qemu-img
info,convertecreate -b/-F - virt-install(1)
--importe--os-variant - Voce Ubuntu 26.04 di osinfo-db, id breve
ubuntu26.04 - machine-id(5) su come un
/etc/machine-idvuoto viene sostituito all’avvio