virt-cloneとvirt-sysprepを使用してVirt-ManagerでVMをクローンする

VMのクローニングは、アイデンティティではなく、バイト単位のコピーを行う。

目次

Virt-Manager(libvirtのGUI)は、KVMディスクをコピーし、クローンにUUIDとMACアドレスを割り当てます。ゲストOSは、virt-sysprepがそれらをクリアするまで、machine-idとSSHホストキーを保持し続けます。

この手順書では、Ubuntu 26.04のゲストOSと、/mnt/extra2/vms に保存された14 GBのqcow2イメージを使用します。ディスク操作のコマンドは、その他のLinuxゲストでも同じです。virt-sysprepはWindowsゲストには適用できません。

2つのKVMゲスト間でqcow2ディスクをクローンする

ホストには、すでにKVMとlibvirtの導入が必要です。Ubuntu 24.04にKVMを導入する がそのセットアップであり、virtinst(virt-clone を提供)も一緒に導入されます。virt-sysprep、virt-customize、virt-cat、および guestfish は、別のパッケージから提供されます。

sudo apt install -y libguestfs-tools

VMを実際にクローンしているもの

libvirtはこの作業を3つのツールに分けて処理します。virt-clone はディスクイメージをコピーし、同じ仮想ハードウェアを持つ新しいドメインを定義します。ドメイン名、UUID、ホスト側のMACアドレスを変更します。パスワード、ホスト名、静的IPアドレス、ゲスト内のファイルは変更されません。これは virt-clone(1) に記載されている動作です。

virt-sysprep はlibguestfsでディスクを開き、ゲストのファイルシステムを編集します。virt-sysprep(1) マニュアルには、この編集がインプレース(in-place)であることが明確に記載されています。出力ファイルのフラグがないため、-a に渡したイメージが変更される対象です。ソースが必要な場合は、先にコピーまたはクローンを行ってください。

qemu-img info は、そのファイルが単体(standalone)か、バックチェーンのトップかを報告します。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[インポートされたゲスト]

バックファイル行が存在する場合は、sysprepの前にフラット化(展開)してください。コピーにsysprepを適用し、その後、そのファイルから各実行中のゲストを派生させます。

Virt-Managerでのディスククローン

ゲストをシャットダウンしてください。virt-clone は実行中のドメインを拒否します。また、ライブ状態のqcow2のコピーは、整合性のあるファイルシステムではありません。

Virt-Managerで、ゲストを右クリックし、クローン (Clone) を選択します。新しい名前を設定します。ストレージのステップで、各ディスクに新しいパスを指定します。元のパスのままにすると、同じファイルを開く2番目のドメインが定義され、両方のゲストが同じブロックに書き込みを行うことになります。

新しいファイルはソースの隣に配置されます。デフォルトのプールは /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 は軽量コピーを要求します。Ubuntu 26.04の virt-clone マニュアルでは、このフラグは同じbtrfsファイルシステム上のrawイメージに制限されているため、これらの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 GBです。disk size はファイルが現在占めている容量であり、新しいオーバーレイでは小さく、ゲストが書き込むにつれて大きくなります。

virt-clone は通常、その行のソースではありません。オーバーレイは qemu-img create -b、ディスクのみのスナップショット、または意図的にqcow2差分を作成したツールから発生します。完全コピーとそれらのケースを区別するのは、このinfoチェックです。

ベースがその場所に留まり、再度書き込まれない場合にのみ、オーバーレイを保持してください。クローンからのすべての書き込みは小さいファイルに蓄積され、オーバーレイで欠損した読み取りはベースから来ています。ベースの移動や編集は、それを参照するすべてのゲストを壊します。

flowchart TB subgraph linked O[base.qcow2 読み取り専用] C1[vm1.qcow2 差分のみ] C2[vm2.qcow2 差分のみ] C1 -->|backing file| O C2 -->|backing file| 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のreflinkは3つ目のケースです。cp --reflink=auto は2つのファイル間で物理的なエクステントを共有でき、qemu-img info にはバックファイルが表示されません。これは、各パスが完全なイメージだからです。ファイルシステムがすべてのブロックを複製していないにもかかわらず、そのコピーはqcow2レイヤーにおいて独立しています。

virt-sysprep: アイデンティティのリセット

単体イメージをコピーし、そのコピーにsysprepを適用します。--reflink=auto はファイルシステムがサポートする場合にエクステントを共有し、それ以外の場合はext4を含む通常のコピーを作成します。-n は書き込みを破棄するドライランです。

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 はデフォルトを維持し、1つの操作のみオフにします。

これらは、クローンが元と競合するかどうかを決定する操作です。リストは、現在の virt-sysprepマニュアル のものであり、短い --operations リストは残りを無言で削除するため、読む価値があります。

操作 デフォルト ゲストへの影響
machine-id はい machine IDをクリアします。/etc/machine-id が空の場合、次回起動時にsystemdが新しいものを生成します。
ssh-hostkeys はい /etc/ssh/ssh_host_* を削除します。次回起動時に新しいホストキーが作成されます。
ssh-userdir はい /root と /home/* 配下の .ssh を削除します。authorized_keys やゲスト内に保存されている秘密鍵を含む。
dhcp-client-state はい DHCPクライアントのリースを削除します。
udev-persistent-net はい 古いMACを eth0 のような固定名にマッピングするudevルールを削除します。
net-hwaddr はい FedoraおよびRHELの ifcfg-* ファイルから HWADDR を削除します。Ubuntuのnetplanは編集しません。
lvm-uuids, lvm-system-devices はい 新しいLVM UUIDを割り当て、/etc/lvm/devices/system.devices を削除します。これがないと、ゲストはソースディスクのWWIDに固定されます。
logfiles, bash-history, tmp-files はい ログ、シェル履歴、一時ファイルを削除します。

ssh-userdir は、まだログインしているマシンをクローンする人が驚くものです。テンプレートにはソースの秘密鍵を持たせるべきではないため、この操作はオンに保ち、後にインスタンスごとにキーを注入してください。既存の authorized_keys を保持しなければならない1回だけのコピーの場合は、--operations defaults,-ssh-userdir を渡してください。

user-account はデフォルトセットに含まれておらず、--password または --root-password を渡さない限りパスワードは変更されません。fs-uuids もデフォルトではオフです。マニュアルでは、/etc/fstab を含むすべての参照を更新しないため、これを有効にするとゲストが起動不可になる可能性が高いと記載されています。

Ubuntu Serverイメージには通常cloud-initが含まれており、virt-sysprepにはcloud-init用の操作はありません。/var/lib/cloud 以下の古いinstance idがあると、クローンは初回起動時のセットアップをスキップしてしまいます。テンプレートでそれらをクリアし、--hostname が書いたホスト名を残すようcloud-initに指示します。

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'

同じマニュアルでは、内部フルディスク暗号化を使用するゲストのクローンによる配布を警告しています。すべてのコピーがボリュームキーを共有するためです。また、削除されたファイルはunlinkされるだけで、消去(スクラブ)されるわけではないことにも言及しています。--scrub は名前付きファイルを上書きし、virt-sparsify はイメージから解放された空間を削除できます。

クローンがIPアドレスを取得する仕組み

virt-sysprep には、アドレスを書き換える操作はありません。DHCPを使用していたゲストは、再度問い合わせを行います。クローンには新しいMAC、空のmachine-id、古いリースファイルがないため、libvirtの default ネットワークのDHCPサーバーは、それを新しいクライアントとして扱います。

netplanの静的 addresses: ブロックはディスクとコピーされ、両方のゲストがそれを主張することになります。初回起動前にファイルを読んでください。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クライアントにするには、それらのファイルを削除し、1つの代替ファイルをアップロードします。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}'

静的IPアドレス、ゲートウェイ、DNSを使用する場合は、Ubuntu Serverで静的IPアドレスを変更する方法 のYAMLと同じアップロードを使用します。各インスタンスには独自のファイルが必要であり、テンプレートではなくインスタンスのディスクに適用されます。

YAML内の名前は、ゲスト内で存在するものでなければなりません。物理ハードウェアから移動されたディスクは、NICを enp2s0 などと呼ぶことがありますが、同じシステムがvirtio下では異なる名前で提示され、netplanが存在しないインターフェースを設定してしまうことがあります。複数のマシントタイプでブートできるべきテンプレートの場合は、カーネルを eth0 に固定し、netplanでそのキーを使用します。Ubuntuは grub.cfg を構築する際に /etc/default/grub.d/*.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のセキュリティ注記は、各新しいディスクに対する2回目のパスを説明しています。Sysprepはテンプレートにランダムシードを書き込みます。そのファイルからクローンされたゲストは、それがないと同じシードで起動し、初回ブート時の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を開き、新しい仮想マシン (New Virtual Machine) を選択し、既存のディスクイメージをインポート (Import existing disk image) を選択します。ubuntu26.04-vm1.qcow2 を指定します。ホストのosinfoデータベースにそれが含まれている場合、OSエントリはUbuntu 26.04であるべきです。

対応する短いIDは ubuntu26.04 です。頼りにする前にホストのデータベースを確認してください。

osinfo-query os | grep ubuntu26

何も出力されない場合、インストールされているデータベースは26.04エントリより古いバージョンです。--os-variant ubuntu24.04 でも、すでにインストールされたゲストに対してvirtio対応のマシントタイプを選択できます。--import は、ディスクにすでにOSが含まれていることを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 は、dnsmasqインスタンスがDHCPリースを配布するNATネットワークを接続します。ブート後:

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

--source lease はそのdnsmasqテーブルを読み取ります。静的アドレス、ブリッジ、またはlibvirt仮想ネットワーク上のNICではない場合は空のままです。そのようなゲストには、イメージ内に qemu-guest-agent が必要で、virsh domifaddr ubuntu26.04-vm1 --source agent または --source arp を使用したARP参照が必要です。1つのドメインではなくプールのビューが必要な場合は、virsh net-dhcp-leases default がNATネットワーク上のすべてのリースをリストします。

戦略 VMあたりの容量 作成時間 制約 使用時
完全コピー、または cp --reflink=auto 論理で約14 GB。reflinkは変更されるまでブロックを共有 数分、またはreflink使用時はほぼ即座 reflinkにはbtrfsのようにサポートするファイルシステムが必要 テンプレートよりも長生きする予定のゲスト
qcow2オーバーレイ 最初は数MB 数秒 ベースパスを維持し、ベースは読み取り専用でなければならない 1つの密閉イメージから多数の類似ゲスト
virt-clone --reflink rawイメージ、共有エクステント ほぼ即座 同じbtrfsファイルシステム上のrawディスク。qcow2はスキップ btrfsに保存されているrawイメージ

数ヶ月間保持される予定のゲストは、完全コピーまたはreflinkです。短命のゲストは、ベースファイルが存在する限りオーバーレイにしても構いません。Proxmox は、独自のWeb UIでデータセンター型のテンプレートとクローンモデルを望む場合の、もう一つのセルフホストされたパスです。Multipass は、単一ユーザー用にUbuntuクラウドイメージを起動し、cloud-initを自身で適用するため、すでにインストールしたディスクを密封するワークフローとは異なります。

トラブルシューティング: クローンがブートできない場合

アドレスがない。 virt-cat でnetplanファイルを確認し、コンソール上の ip link とインターフェースキーを比較してください。ソースMACに設定されたままの match: macaddress エントリは、新しいNICをドロップします。ゲストにないインターフェースの名前を付けたキーでも同じです。ディスク上のファイルを修正するか、上記の eth0 コマンドラインを適用し、テンプレートからインスタンスを再構築してください。

アドレスが上がっているが、元と同じ。 静的 addresses: ブロックがnetplanファイルの1つに残っています。virt-sysprep はそれを削除しませんでした。代替物をアップロードし、/etc/netplan 内の他のYAMLファイルを削除してください。

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を使用する場合、lvm-uuids も含める必要があります。

1つのクローンか、テンプレートか

単一の追加マシンは、virt-clone、バックファイルの確認、新しいディスクへの virt-sysprep です。フリート(多数のグループ)は、1つの密封された単体ファイル、その後、ゲストごとにコピーまたはオーバーレイ、そしてブート前にそのゲスト固有のディスクに対して --enable customize です。

オーバーレイは、密封ファイルがそれを参照するすべてのゲストのランタイムパスの一部になります。完全コピーとreflinkはそうではありません。その依存関係をゲストの寿命に合わせて選び、ブートローダーと /etc/fstab がファイルシステムと一致するように fs-uuids はオフのままにしてください。

関連リンク

参考文献

購読する

システム、インフラ、AIエンジニアリングの新記事をお届けします。