Export an OpenStack instance to VMware vSphere
Reverse migrations happen: a workload must join a vSphere estate after a merger, a partner only accepts VMDK images, or a hybrid landing zone runs both hypervisors. Two paths cover most cases: a Glance snapshot converted to a stream-optimized VMDK for isolated VMs, and a direct Ceph RBD to VMDK conversion for multi-terabyte disks. Illustrative commands, to adapt to your releases and network.
1. Prepare the guest before export
The guest leaves a KVM/VirtIO world for VMware paravirtual hardware. Before the last shutdown, install VMware Tools or open-vm-tools, make sure the initramfs (Linux) or the boot-critical drivers (Windows, LSI Logic SAS or PVSCSI) are present, remove the qemu-guest-agent, and record IP addresses, MACs and disk order. A guest exported without these drivers boots to a black screen on ESXi.
# Record what you will need to recreate the VM on vSphere
openstack server show vm-production-01 -c flavor -c addresses -c volumes_attached -c image
openstack server volume list vm-production-01
openstack port list --server vm-production-01 -c "MAC Address" -c "Fixed IP Addresses"
# Gracefully stop the source OpenStack VM
openstack server stop vm-production-01
2. Path A: Glance snapshot to stream-optimized VMDK
Simple path for an isolated VM without direct access to the Ceph backend. The instance is snapshotted into Glance, downloaded, then converted with qemu-img. The streamOptimized VMDK sub-format is designed for transfer and is suitable for OVF/OVA-style imports; validate the exact workflow against the target vSphere version.
2.1 Snapshot and download the image
# Create an image snapshot from the stopped instance (Nova + Glance)
openstack server image create --name snap-vm-prod-01 --wait vm-production-01
# Download the image (format is whatever Glance stores: raw with Ceph, often qcow2 elsewhere)
openstack image show snap-vm-prod-01 -c disk_format -c size
openstack image save --file vm-prod-01.img snap-vm-prod-01
2.2 Convert to a stream-optimized VMDK
# -f must match the downloaded format (raw or qcow2); read it from qemu-img JSON output
INPUT_FORMAT=$(qemu-img info --output=json vm-prod-01.img | jq -r '.format')
qemu-img convert -p -f "$INPUT_FORMAT" -O vmdk -o subformat=streamOptimized \
vm-prod-01.img vm-prod-01-esxi.vmdk
Boot-from-volume instances have no image to snapshot: use openstack volume snapshot create, clone the snapshot into a volume, then openstack image create --volume to obtain a Glance image, exactly as in the Cinder migration guide.
3. Path B: direct Ceph RBD to VMDK
High-volume approach for multi-terabyte Cinder volumes. qemu-img reads the RBD image through its native rbd: protocol and writes the VMDK in one pass, with no intermediate raw file. It needs a host with the Ceph client keyring and network access to the OSDs; qemu-img cannot read a raw image from a pipe, so rbd export | qemu-img is not an option.
# Identify the Cinder volume and its RBD image (volume must be detached: instance stopped and volume available)
openstack volume show <VOLUME_ID> -c status -c size
rbd -p cinder-volumes info volume-<VOLUME_ID>
# Convert the RBD image straight to a stream-optimized VMDK, no intermediate file
qemu-img convert -p -f raw -O vmdk -o subformat=streamOptimized \
rbd:cinder-volumes/volume-<VOLUME_ID>:id=cinder:conf=/etc/ceph/ceph.conf \
vm-heavy-disk.vmdk
# Alternative when the target datastore is mounted (NFS) or reachable over SSH: write the VMDK there directly
qemu-img convert -p -f raw -O vmdk -o subformat=streamOptimized \
rbd:cinder-volumes/volume-<VOLUME_ID> /mnt/datastore1/upload/vm-heavy-disk.vmdk
4. Register the VM in vCenter
govc import.vmdk uploads the disk into the datastore; it does not create a virtual machine. Create the VM powered off on the imported disk, then adjust the network, firmware and controller type before the first boot. On ESXi itself, vmkfstools converts an uploaded disk into the native thin-provisioned format.
# Import the VMDK into the vSphere datastore with govc
export GOVC_URL='https://<VCENTER_HOST>' GOVC_USERNAME='<VCENTER_USER>' GOVC_INSECURE=1
govc import.vmdk -pool=Cluster01/Resources -ds=datastore1 vm-prod-01-esxi.vmdk vm-prod-01/
# Create the VM on the imported disk (powered off, network and firmware to adjust)
govc vm.create -pool=Cluster01/Resources -ds=datastore1 -net="VM Network" \
-c 4 -m 8192 -g ubuntu64Guest -firmware efi \
-disk=vm-prod-01/vm-prod-01-esxi.vmdk -on=false vm-prod-01
# Re-apply the original MAC address when licences or firewall rules depend on it
govc vm.network.change -vm vm-prod-01 -net "VM Network" -net.address <OLD_MAC> ethernet-0
govc vm.power -on vm-prod-01
# ESXi shell alternative: convert an uploaded disk to thin provisioning in place
vmkfstools -i /vmfs/volumes/datastore1/upload/vm-heavy-disk.vmdk -d thin /vmfs/volumes/datastore1/vm-heavy/disk-final.vmdk
5. Pitfalls to check first
- ■Boot drivers: Linux guests need the SCSI controller module (mptsas, vmw_pvscsi) in the initramfs; Windows guests need the matching storage driver before the disk leaves OpenStack. Test on a clone first.
- ■Firmware: an instance booted with hw_firmware_type=uefi must be created with -firmware efi in vSphere; a BIOS guest created as EFI does not boot either.
- ■cloud-init: disable or reconfigure it before export, otherwise the guest may reset its network configuration or hostname on first boot in vSphere.
- ■Consistency: snapshot or convert only a stopped instance (or a detached volume). A live RBD export produces a crash-consistent disk at best.
- ■Throughput: size the window on a measured qemu-img run against a representative volume; datastore upload speed is usually the bottleneck, not Ceph.
- ■Rollback: keep the OpenStack instance stopped but intact until acceptance on vSphere is signed; openstack server start is the rollback.