Cloning a Virtual Machine

Cloning creates a full copy of an existing virtual machine — including its specification, disks, and network configuration — as a new virtual machine in the same namespace. ACP implements this with the KubeVirt VirtualMachineClone (clone.kubevirt.io/v1beta1) resource, which performs the copy asynchronously through an internal snapshot → restore.

This is different from cloning a bootable volume (a PVC or snapshot data source): a VM clone reproduces the whole machine, whereas a bootable-volume clone only duplicates a disk image.

Prerequisites

  • Snapshot-capable storage. Because the clone is implemented as an internal snapshot → restore, the source virtual machine's disks must reside on a StorageClass that supports volume snapshots (a matching VolumeSnapshotClass exists for that storage backend). If the storage cannot be snapshotted, the clone fails — check the VirtualMachineClone status.phase and status.conditions for the error. See Clone Virtual Machines on KubeVirt for the full prerequisite list.

Notes

  • Same namespace only. VirtualMachineClone.spec.target has no namespace field, so the new virtual machine is always created in the source's namespace. To copy a virtual machine to another namespace, export and re-import it instead.
  • The new virtual machine appears asynchronously. Submitting the clone returns immediately; the target is created as the snapshot → restore completes (status.phase progresses to Succeeded).
  • Cloning a stopped virtual machine is the most reliable, because the disk state is quiescent.
  • MAC addresses are reset by default so the clone does not conflict with the source on the network.
  • Kube-OVN networks: the clone always filters out the source ovn.kubernetes.io/* pod annotations so the new virtual machine requests a fresh IP instead of inheriting (and conflicting with) the source IP.
  • Permission: cloning is gated on the create verb for virtualmachineclones in the clone.kubevirt.io API group. This group is not part of the standard Virtual Machines function permission, so a user who holds only the Virtual Machines role sees the Clone action disabled. A platform or namespace administrator must grant an additional role/binding allowing create on virtualmachineclones.clone.kubevirt.io before that user can clone.

Clone a virtual machine

Create a VirtualMachineClone object in the source namespace. The example below clones web-01 to web-01-clone, resets MAC addresses (newMacAddresses: {}), and strips Kube-OVN annotations from the pod template so the clone gets a fresh IP:

apiVersion: clone.kubevirt.io/v1beta1
kind: VirtualMachineClone
metadata:
  name: web-01-clone
  namespace: demo
spec:
  source:
    apiGroup: kubevirt.io
    kind: VirtualMachine
    name: web-01
  target:
    apiGroup: kubevirt.io
    kind: VirtualMachine
    name: web-01-clone
  # Keep all VM-level labels and annotations. Interface MAC addresses are
  # regenerated by default; set newMacAddresses to pin specific MACs instead.
  labelFilters: ["*"]
  annotationFilters: ["*"]
  # Kube-OVN: keep every pod-template annotation EXCEPT the source's
  # ovn.kubernetes.io/* address bindings, so the clone gets a fresh IP instead of
  # inheriting the source's. Clone filters are whitelist-based: a bare pattern
  # keeps the matching keys (everything else is dropped) and a "!" prefix
  # excludes — so the "*" entry is required (a lone "!ovn.kubernetes.io/*" would
  # whitelist nothing and strip ALL pod-template annotations).
  template:
    annotationFilters:
      - "*"
      - "!ovn.kubernetes.io/*"

Apply it and watch the clone progress to Succeeded:

kubectl apply -f vmclone.yaml
kubectl get virtualmachineclone web-01-clone -n demo \
  -o jsonpath='{.status.phase}{"\n"}'

When status.phase is Succeeded, the new virtual machine web-01-clone exists in the demo namespace. status.restoreName and status.snapshotName reference the intermediate restore and snapshot objects created during the operation.

To copy only a subset of metadata, set the top-level labelFilters / annotationFilters (they filter the virtual machine object's own labels/annotations; template.* filters the pod template metadata):

spec:
  labelFilters:
    - "*"
    - "!some/transient-label"
  annotationFilters:
    - "*"

After the clone reaches Running, manage it like any other virtual machine — see Managing Virtual Machines. Because MAC addresses (and, on Kube-OVN, the IP) are regenerated, verify the new virtual machine's network configuration if your guest pins addresses internally.