This guide describes how to migrate an existing virtual machine from VMware to Deckhouse Virtualization Platform (DVP).
The migration source can be:
- a virtual machine distribution (an
OVAfile, a tar archive with disk files invmdkformat, VM metadata inovfformat, and checksums inmfformat); - standalone
VMDKdisk files.
Migration approaches
Direct VMDK import
DVP supports importing disks in vmdk format.
You can upload a VMDK file from an OVA or vSphere export to a VirtualImage or ClusterVirtualImage, create a disk from the image, and then a virtual machine.
See Images for the upload procedure.
The platform imports the disk file as-is and does not adapt the guest OS for KVM. For disks from VMware this often causes problems: the VM fails to boot, cannot see the disk, or has no network (especially on Windows). Direct import is suitable only when the VMDK is already prepared for QEMU/KVM.
Recommended path
For typical VMs from VMware, use the virt-v2v utility: it converts VMDK to qcow2 and adapts the guest OS for KVM (virtio drivers, bootloader, replacement of VMware devices).
Upload the prepared disk directly to a VirtualDisk with type: Upload.
The volume is provisioned in the chosen StorageClass, bypassing DVCR.
The step-by-step instructions below cover this scenario.
Migration stages
Migrating a VM from VMware to DVP includes the following stages:
- Install the required tools.
- Convert the disk.
- Upload the disk to the cluster as a VirtualDisk resource.
- Create a virtual machine (VirtualMachine resource) that boots from this disk.
What you need for migration
Before you start the migration, make sure you have:
- access to the DVP cluster with the Deckhouse CLI utility (
d8) installed and permissions to create virtualization resources in the target namespace; - a Linux host with
virt-v2vandlibguestfsinstalled and enough disk space to unpack theOVA(or standaloneVMDKfiles) and store the conversion output; - the VMware export files (
OVAorVMDK).
For more details on uploading disks to the cluster, see Disks.
Install tools
On this step you prepare a conversion workstation. It does not have to be a DVP cluster node: any Linux host with internet access or a local package repository is sufficient.
The packages you need depend on the guest OS in the VM you are migrating:
- for Linux,
virt-v2vandlibguestfsare sufficient; - for Windows, you will additionally need a
virtio-winISO so the guest OS works correctly with virtual devices in KVM after migration.
Install the tools:
- Ubuntu/Debian workstation
- RHEL/AlmaLinux workstation
Run the following command:
sudo apt update
sudo apt install -y virt-v2v libguestfs-tools
If the VM being migrated runs Windows:
-
Download the VirtIO drivers from the
virtio-windistribution. -
Specify the path to the VirtIO drivers via an environment variable:
export VIRTIO_WIN=/path/to/virtio-win.iso
Without a valid virtio-win ISO for a Windows guest, conversion may fail, or the guest OS may not see disks or networking after the VM starts on DVP.
Run the following command:
sudo dnf install -y virt-v2v libguestfs-tools-c virtio-win
If the VM being migrated runs Windows, set the path to the ISO via an environment variable:
export VIRTIO_WIN=/path/to/virtio-win.iso
Then proceed to converting the disk.
Convert the disk
On this step you convert VMware data into one or more qcow2 files that DVP can use as virtual machine volumes.
If you already have a ready VMDK, go straight to Convert VMDK to qcow2 via virt-v2v.
If you are using a virtual machine OVA distribution, unpack it first.
Extract an OVA
An OVA file is a tar archive with a manifest, an OVF descriptor, and one or more VMDK images.
Unpacking gives you the disk file path for virt-v2v.
Keep the OVF file: you will use it later for CPU, memory, and bootloader settings in the VirtualMachine resource.
Extract everything if you want to verify checksums or inspect the OVF:
tar -xvf machine.ova
Typical contents:
machine.ova
├── machine.mf # checksums (SHA256)
├── machine.ovf # VM metadata (CPU, RAM, disks, networks)
└── machine-disk1.vmdk # disk image
If the archive is large, you can extract only the required VMDK listed in the OVF:
tar -xvf machine.ova machine-disk1.vmdk
Virtual machines with multiple disks contain several *.vmdk files. Convert each disk with the virt-v2v utility, create a matching VirtualDisk in DVP, then reference them from VirtualMachine in the desired boot order.
Convert VMDK to qcow2 via virt-v2v
With -i disk, virt-v2v processes a local VMDK and saves the result into the directory you specify.
To perform the conversion, run:
- For a Linux guest OS
- For a Windows guest OS
virt-v2v -i disk ./machine-disk1.vmdk \
-o local -os ./out -of qcow2
To convert a VMDK for a Windows guest, specify the path to virtio-win.iso in the command:
VIRTIO_WIN=/path/to/virtio-win.iso virt-v2v -i disk ./machine-disk1.vmdk \
-o local -os ./out -of qcow2
After the conversion, a file such as ./out/machine.qcow2 will appear under ./out (the basename often matches the original VM name from the metadata). That file is what you upload to the cluster next.
Upload the disk to the cluster
This section describes how to transfer the prepared qcow2 image to DVP through the Kubernetes API.
At this stage the file becomes a persistent volume in the cluster: create a VirtualDisk with type: Upload and transfer the qcow2 over HTTP.
The disk is provisioned in the chosen StorageClass, bypassing DVCR.
Uploading the disk image to the cluster includes the following steps:
- Choose a StorageClass.
- Create a VirtualDisk for upload.
- Get upload URLs.
- Upload the image.
- Check the status of the uploaded image.
Choose a StorageClass
StorageClass in Kubernetes defines where and how the volume is provisioned; in VMware terms this is closest to a datastore. Performance, replication type, and volume expansion policy depend on the class.
List classes available in your cluster:
d8 k get storageclass
Example:
NAME PROVISIONER VOLUMEBINDINGMODE AGE
rv-thin-r1 (default) replicated.csi.storage.deckhouse.io Immediate 48d
rv-thin-r2 replicated.csi.storage.deckhouse.io Immediate 48d
Select the class name that fits your storage requirements for VM disks.
Create a VirtualDisk for upload
Create the disk resource, specifying StorageClass and volume size.
spec.persistentVolumeClaim.size must be at least the actual size of the qcow2 you upload.
If unsure, leave margin: if the size is insufficient, recreate the resource with a larger PVC.
d8 k apply -f - <<EOF
apiVersion: virtualization.deckhouse.io/v1alpha2
kind: VirtualDisk
metadata:
name: uploaded-disk
spec:
persistentVolumeClaim:
storageClassName: rv-thin-r1
size: 10Gi
dataSource:
type: Upload
EOF
After creation the resource moves to WaitForUserUpload: the volume is allocated and you can start transferring the file.
Get upload URLs
The platform provides two URLs: internal (imageUploadURLs.inCluster) and external (imageUploadURLs.external). Use the address reachable from your network (from inside the cluster or from an administrator workstation).
Internal URL (use when uploading from a cluster node or from a pod):
d8 k get vd uploaded-disk -o jsonpath="{.status.imageUploadURLs.inCluster}"
External URL (use from an administrator workstation when access to DVP is configured):
d8 k get vd uploaded-disk -o jsonpath="{.status.imageUploadURLs.external}"
Both fields together (requires jq):
d8 k get vd uploaded-disk -o jsonpath="{.status.imageUploadURLs}" | jq
The URL string contains a secret path segment. Do not publish it in public channels.
Upload the image
Send the qcow2 image with an HTTP PUT request to the URL obtained in the previous step. The example below uses an external URL. Replace it with the address from your VirtualDisk status and the path to the converted file.
curl https://virtualization.example.com/upload/<secret-url> \
--progress-bar -T ./out/machine.qcow2 | cat
Wait until the transfer completes successfully without HTTP errors. The controller will process the image and transition the disk to Ready.
Check status
Verify that the disk resource is healthy and the volume size looks correct:
d8 k get vd uploaded-disk
Example:
NAMESPACE NAME PHASE CAPACITY AGE
default uploaded-disk Ready 10Gi 1m
If the phase stays on WaitForUserUpload for a long time or the resource enters Failed, check messages with d8 k describe vd uploaded-disk and events in the corresponding namespace.
Continue when the disk reaches Ready.
Create the virtual machine
The final step is to describe the VM that will boot from the migrated disk.
Specify how much CPU and memory to allocate, which network to attach, and which disk is bootable.
VMware configuration (OVF/VMX) is not imported directly: carry over parameters manually using the OVF file and the mapping table below.
VMware vs DVP terminology
If you know vSphere, the following table maps familiar VMware objects to Kubernetes and DVP virtualization resources.
| VMware | DVP | Description |
|---|---|---|
| Datastore | StorageClass | Disk backing storage |
| VMX | VirtualMachine.spec | VM specification |
| Virtual disk (VMDK) | VirtualDisk | VM disk |
| ISO image | VirtualImage (cdrom: true) |
Installation or driver ISO |
| Template | VirtualImage | Template for provisioning disks |
| Port group / VLAN | VirtualMachine (networks) |
Networking |
| Resource pool | Project and quotas | Resource limits per project |
| Snapshot | VirtualDiskSnapshot / VirtualMachineSnapshot | Disk and VM snapshots |
| Folder | Namespace | Namespace |
| Cluster / resource pool | Project | Namespace grouping |
| ESXi host | Node | Physical server |
| vCenter | Kubernetes API | Cluster management |
For more details on connecting VMs to networks, see Virtual machine networks.
VirtualMachine example
The VirtualMachine resource references the uploaded disk through blockDeviceRefs. Order in blockDeviceRefs determines boot order: the boot disk must be listed first.
Minimal Linux example after disk migration:
d8 k apply -f - <<EOF
apiVersion: virtualization.deckhouse.io/v1alpha2
kind: VirtualMachine
metadata:
name: my-vm
spec:
virtualMachineClassName: generic
osType: Generic
cpu:
cores: 2
memory:
size: 4Gi
networks:
- type: Main
blockDeviceRefs:
- kind: VirtualDisk
name: uploaded-disk
EOF
Set osType: Windows for Windows guests.
If the source VM in VMware used UEFI boot, add bootloader: EFI (see the parameter table below).
If additional networks and the SDN module are configured in the cluster, you can add interfaces alongside the primary network:
networks:
- type: Main
- type: Network
name: user-net
Additional capabilities (cloud-init, multiple disks, VM classes for production environments) are described in Virtual machines.
Common spec fields
The following table lists fields you most often need to verify after migration from VMware.
CPU, memory, and bootloader values can usually be taken from the unpacked OVF file.
| Field | Description |
|---|---|
virtualMachineClassName |
VM class, e.g. generic, serverful, high-performance |
osType |
Generic (Linux and others) or Windows |
bootloader |
Boot firmware: BIOS, EFI, or EFIWithSecureBoot; for UEFI VMs in VMware, set EFI |
cpu.cores |
Number of vCPUs |
memory.size |
RAM |
blockDeviceRefs |
Disks and images; list order is boot order |
provisioning.type: UserData |
cloud-init user data for first boot of the guest OS |
Check VM status
After applying the manifest, wait until the VM is running and has an address (when the primary network assigns IPs from virtualMachineCIDRs):
d8 k get vm my-vm
Example:
NAME PHASE NODE IPADDRESS AGE
my-vm Running virtlab-pt-2 10.66.10.12 2m
If the phase is Pending or startup fails, use d8 k describe vm my-vm, the serial console d8 v console my-vm (see Connect to the VM below), and review virtualization component logs in the cluster.
Connect to the VM
Choose an access method depending on whether the guest OS accepts SSH, you need a graphical console, or serial console is enough for boot troubleshooting.
| Method | Purpose | Command |
|---|---|---|
| Serial console | Bootloader and kernel output | d8 v console my-vm |
| VNC | Graphical console without SSH | d8 v vnc my-vm |
| SSH | Remote shell access to the guest | d8 v ssh cloud@my-vm --local-ssh |
The SSH username is defined in the guest OS; examples in the DVP documentation often create a cloud user via cloud-init.