# Migration Guide: Importing Workloads into Incus

This guide covers migrating virtual machines and containers from other
hypervisors into Incus. Each section documents a specific migration path
with tested procedures where available.

All commands tested with Incus 6.21 on IncusOS.

---

## Overview

Incus provides several ways to import workloads:

| Tool | Use case |
|------|----------|
| `incus-migrate` | Official migration tool. Imports disk images, running instances, or physical machines |
| `incus import` | Import from an Incus backup file (`.tar.gz`) |
| `incus storage volume import` | Import a raw/qcow2 disk as a storage volume |
| `qemu-img convert` | Convert between disk formats (vmdk, qcow2, raw, vdi) |

### General migration workflow

1. **Export** the VM disk from the source hypervisor
2. **Convert** the disk to raw or qcow2 format (if needed)
3. **Import** into Incus via `incus-migrate` or manual volume import
4. **Configure** the Incus instance (network, boot, etc.)
5. **Verify** the migrated workload boots and runs correctly

---

## Proxmox VE to Incus

**Status**: documented, can be tested with lab VMs.

### Method 1: Using qemu-img (recommended)

```bash
# 1. Identify the disk on Proxmox
ssh root@proxmox pvesm list local-lvm | grep vm-<VMID>

# 2. Export the VM disk as raw
ssh root@proxmox qm disk export <VMID> scsi0 /tmp/disk.raw --format raw

# 3. Copy to the Incus host
scp root@proxmox:/tmp/disk.raw /tmp/disk.raw

# 4. Import as a storage volume
incus storage volume import <remote>:local /tmp/disk.raw migrated-disk --type=block

# 5. Create an empty VM
incus init --empty --vm migrated-vm <remote>:

# 6. Attach the imported disk
incus config device add <remote>:migrated-vm root disk pool=local source=migrated-disk

# 7. Configure for boot
incus config set <remote>:migrated-vm security.secureboot=false  # if source lacks SB
incus start <remote>:migrated-vm
```

### Method 2: Using incus-migrate

```bash
# On the Incus host (or any machine with access to both)
incus-migrate

# Interactive prompts:
# 1. Select "Import from disk image"
# 2. Point to the exported raw/qcow2 file
# 3. Select target Incus server and storage pool
# 4. Choose VM instance type
```

### Notes

- Proxmox ZFS volumes can be exported with `zfs send` for faster transfer
- LVM-thin volumes: use `qm disk export` (abstracts the LVM details)
- UEFI VMs: ensure the Incus VM is configured with UEFI boot
  (`security.secureboot=false` if the source OS lacks Secure Boot support)
- Network: the VM will get a new MAC address in Incus. Update any static
  network config inside the VM after migration.
- Guest agent: install `incus-agent` inside the VM after migration for full
  management capabilities.

---

## UTM to Incus

**Status**: documented (theoretical). Testable when running on macOS.

UTM stores VMs as `.utm` bundles (directories) containing qcow2 disk images.

### Procedure

```bash
# 1. Locate the UTM VM bundle
ls ~/Library/Containers/com.utmapp.UTM/Data/Documents/*.utm/

# 2. Find the qcow2 disk inside the bundle
ls <vm-name>.utm/Data/*.qcow2

# 3. Convert to raw (if needed)
qemu-img convert -f qcow2 -O raw <vm>.utm/Data/disk.qcow2 /tmp/disk.raw

# 4. Transfer to Incus host (if remote)
scp /tmp/disk.raw user@incus-host:/tmp/

# 5. Import into Incus (same as Proxmox method)
incus storage volume import <remote>:local /tmp/disk.raw migrated-disk --type=block
incus init --empty --vm migrated-vm <remote>:
incus config device add <remote>:migrated-vm root disk pool=local source=migrated-disk
incus start <remote>:migrated-vm
```

### Notes

- UTM supports both Apple Virtualization (arm64 only) and QEMU backends.
  VMs from the QEMU backend are most compatible with Incus.
- Apple Virtualization VMs use a different format and may not be directly
  importable.
- arm64 VMs from UTM can be imported into arm64 Incus hosts.
- x86_64 VMs (via QEMU backend on Intel Macs) can be imported into x86_64
  Incus hosts.

---

## VMware Fusion to Incus

**Status**: documented (theoretical). Testable when VMware Fusion is available.

VMware Fusion stores VMs as `.vmwarevm` bundles containing `.vmdk` disk files.

### Procedure

```bash
# 1. Locate the VM bundle
ls ~/Virtual\ Machines.localized/*.vmwarevm/

# 2. Find the VMDK disk
ls <vm-name>.vmwarevm/*.vmdk

# 3. Convert VMDK to raw
qemu-img convert -f vmdk -O raw <vm>.vmwarevm/disk.vmdk /tmp/disk.raw

# 4. Transfer and import into Incus (same workflow)
scp /tmp/disk.raw user@incus-host:/tmp/
incus storage volume import <remote>:local /tmp/disk.raw migrated-disk --type=block
incus init --empty --vm migrated-vm <remote>:
incus config device add <remote>:migrated-vm root disk pool=local source=migrated-disk
incus start <remote>:migrated-vm
```

### OVA/OVF export (alternative)

```bash
# VMware Fusion can export VMs as OVA
# File -> Export to OVF...

# Extract VMDK from OVA (OVA is a tar archive)
tar xf machine.ova
ls *.vmdk

# Convert and import as above
qemu-img convert -f vmdk -O raw *.vmdk /tmp/disk.raw
```

### Notes

- Split VMDK files (multiple `.vmdk` files): use `qemu-img` which handles
  split VMDK chains automatically.
- VMware Tools: uninstall before migration if possible, or install
  `open-vm-tools` equivalent in the guest after migration.
- Network adapter type changes from vmxnet3 to virtio.

---

## Physical Machine to Incus

**Status**: documented. `incus-migrate` supports direct physical-to-virtual.

### Method 1: incus-migrate (recommended)

Run `incus-migrate` directly on the physical machine:

```bash
# On the physical machine (requires root)
sudo incus-migrate

# Interactive prompts guide you through:
# 1. Connect to Incus server
# 2. Select "Migrate this machine"
# 3. Choose instance type (container or VM)
# 4. incus-migrate streams the filesystem/disk to Incus
```

### Method 2: Disk image capture

```bash
# 1. Create a disk image from the physical machine
sudo dd if=/dev/sda of=/tmp/disk.raw bs=4M status=progress

# 2. Transfer to Incus host
scp /tmp/disk.raw user@incus-host:/tmp/

# 3. Import as usual
incus storage volume import <remote>:local /tmp/disk.raw migrated-disk --type=block
incus init --empty --vm migrated-vm <remote>:
incus config device add <remote>:migrated-vm root disk pool=local source=migrated-disk
```

### Notes

- `incus-migrate` is the cleanest approach for physical machines.
- Disk image capture preserves everything (bootloader, partitions) but
  creates very large files. Use compression: `dd | gzip > disk.raw.gz`
- Shrink the disk image after transfer: `qemu-img convert -O raw disk.raw
  disk-shrunk.raw` (removes trailing zeros).
- Hardware drivers: the guest may need to regenerate initramfs for the new
  virtual hardware (virtio drivers).

---

## Container Migration (Docker/Podman to Incus)

**Status**: documented. Container filesystem import is straightforward.

### Docker to Incus container

```bash
# 1. Export the container filesystem
docker export <container-id> > /tmp/container-fs.tar

# 2. Import into Incus as a container
incus import <remote>: /tmp/container-fs.tar imported-container

# 3. Start
incus start <remote>:imported-container
```

### Podman to Incus container

```bash
# Same approach -- podman export is compatible
podman export <container-id> > /tmp/container-fs.tar
incus import <remote>: /tmp/container-fs.tar imported-container
```

### Docker image to Incus

```bash
# Save image as tar
docker save <image-name> > /tmp/image.tar

# Note: docker save creates an OCI image archive, not a filesystem tar.
# incus import expects a filesystem tar. Use docker export (from a running
# container) instead.
```

### Notes

- Docker containers are typically single-process. Incus containers run a
  full init system. The imported container may need an init process
  (systemd, openrc) installed.
- Networking: Docker networking doesn't translate. The imported container
  gets Incus networking (bridge-based).
- Volumes: Docker volumes are NOT exported with `docker export`. Copy
  volume data separately.
- For complex Docker Compose stacks, consider running Docker inside an Incus
  VM instead of migrating individual containers.

---

## Disk Format Reference

| Format | Extension | Tools | Notes |
|--------|-----------|-------|-------|
| Raw | `.raw`, `.img` | `dd`, `qemu-img` | No overhead, largest size |
| QCOW2 | `.qcow2` | `qemu-img` | Sparse, snapshots, common in KVM/QEMU |
| VMDK | `.vmdk` | `qemu-img` | VMware format, may be split across files |
| VDI | `.vdi` | `qemu-img` | VirtualBox format |
| VHD/VHDX | `.vhd`, `.vhdx` | `qemu-img` | Hyper-V format |

### Converting between formats

```bash
# QCOW2 to raw
qemu-img convert -f qcow2 -O raw input.qcow2 output.raw

# VMDK to raw
qemu-img convert -f vmdk -O raw input.vmdk output.raw

# Raw to QCOW2 (for storage efficiency)
qemu-img convert -f raw -O qcow2 input.raw output.qcow2

# VDI to raw
qemu-img convert -f vdi -O raw input.vdi output.raw

# Check image info
qemu-img info disk.qcow2
```

---

## Post-Migration Checklist

After importing a workload into Incus:

- [ ] Verify the instance boots and runs correctly
- [ ] Update network configuration (new MAC address, new IP range)
- [ ] Install `incus-agent` inside VMs for full management
- [ ] Remove source-hypervisor-specific tools (VMware Tools, etc.)
- [ ] Regenerate initramfs if hardware changed significantly
- [ ] Update `/etc/fstab` if disk device names changed
- [ ] Test application functionality
- [ ] Set up backups in Incus (`incus export` or snapshots)

---

## References

- [incus-migrate documentation](https://linuxcontainers.org/incus/docs/main/howto/server_migrate/)
- [qemu-img manual](https://www.qemu.org/docs/master/tools/qemu-img.html)
- [Incus import/export](https://linuxcontainers.org/incus/docs/main/howto/instances_backup/)
