VM-to-Kubernetes Migration Platform
Where we are, what we proved, and where we're going
No stage after 1I is defined.
Status above updated 2026-10-15. Everything below this line, including the 60-second questions, diagrams 01 to 12 and their captions, is a snapshot of the status recorded after Stage 1H (2026-09-28), before the migration. Where it says "not built", "designed only" or "nothing exists", that was true then. Stage 1I later built the target on a single-node kubeadm cluster on AWS EC2, migrated the VM, validated it and destroyed the target. See the Stage 1I visual guide and the Stage 1I record.
ANSWER THESE IN 60 SECONDS (AS AT END OF STAGE 1H)
Think of your answer, then click to check.
Stage 1H: the KubeVirt target is designed and awaiting your review. Stage 0 and 1A to 1G are complete. Stage 1I is not yet defined.
See diagram 02 →A real VMware VM, a cold byte-identical disk copy, qemu-img and virt-v2v conversions, and a UEFI + virtio boot under QEMU/KVM with nginx serving the same page (HTTP 200). All in our local lab.
See diagram 06 →On conversion-host-01, under /srv/migration-lab/stage-1g/: the qemu-img and virt-v2v outputs plus one network-fixed test copy. The golden VMDK is on Windows. None of it is in Git.
See diagram 05 →No. No cluster and no KubeVirt VM exist. The converted disks booted only in temporary QEMU/KVM test guests inside conversion-host-01, and those were deleted.
See diagram 07 →The NIC changes from VMXNET3 to virtio, so its name changes from ens192 to enp0s3. The old netplan still looks for ens192, so the guest boots with no network. Matching by driver virtio_net fixed it in 1G; the 1H design uses DHCP.
See diagram 09 →You review Stage 1H. Then Stage 1I has to be defined and approved (objective, scope, change boundary), and AWS credentials must work; they are BLOCKED today. Anything beyond that is a proposal.
See diagram 12 →The whole journey
Stage 0 and 1A-1G are done, 1H is designed, 1I is not defined. The rest is a proposal.
Why it matters: It keeps official status apart from ideas about the future.
The left column is the official record from the Stage 1 README. The right column is a proposed path drawn from existing designs; it has no stage numbers.
- Official: Stage 0 and 1A to 1G complete; 1H awaiting review.
- Stage 1I exists only as a name.
- The proposed path is not approved.
Where are we now?
We are at Stage 1H: the KubeVirt target is designed and awaiting review.
Why it matters: Get this right first; everything else depends on it.
Eight stages are complete and proven in the lab. Stage 1H is a design with no infrastructure. Stage 1I has a name but no definition.
- Stage 1H: H1 to H10 PASS as documentation gates.
- Stage 1I needs your review of 1H, your approval and AWS credentials.
- No stage numbers after 1I exist.
Our current lab
One laptop, one nested ESXi host, three VMs. Nothing in the cloud.
Why it matters: Everything proven so far happened inside this one box.
Windows runs VMware Workstation, which runs a nested ESXi 8.0.3 host. On it are the source VM, the conversion host and a KVM learning VM.
- Power states as recorded after Stage 1H (not re-observed).
- No Kubernetes, KubeVirt, CDI or AWS resource exists.
- No disk file is stored in Git.
Three VMs, three different jobs
Migrate this, convert here, learn there: three roles, not three copies.
Why it matters: Mixing up these VMs is the easiest way to misread the project.
legacy-source-vm is the VM we migrate, and it stays unchanged. conversion-host-01 holds the disk copies and the tools. kvm-learning-01 was only for learning KVM.
- The source VM was never pointed at a converted disk.
- Test boots ran inside conversion-host-01.
- kvm-learning-01 never touched the converted disk.
The disk journey
Source VMDK, then golden copy on Windows, then working copy, then converted qcow2 on conversion-host-01.
Why it matters: It answers the question: where is the migration disk right now?
Every copy is hashed and the original is never modified. The converted qcow2 files live on conversion-host-01. The path into Kubernetes (CDI, PVC, KubeVirt VM) is designed only.
- Golden copy: C:\VMs\legacy-source-vm\stage-1e\, read-only.
- Converted copies: /srv/migration-lab/stage-1g/ on conversion-host-01.
- Test guests were deleted. None of these files is in Git.
What we have actually proven
Source, disk copy, conversion, KVM boot and nginx are proven. KubeVirt is not.
Why it matters: Only proven items count as evidence.
Every green tick was observed in a PASS stage record from 1A to 1G. KubeVirt is the only area that is design only.
- UEFI boot proven with Secure Boot off; Secure Boot on is NOT TESTED.
- Network fix proven on an isolated test network; DNS not proven.
- libvirt proven only with the learning image.
Not built yet
AWS, Kubernetes, KubeVirt, CDI and the migration itself do not exist yet.
Why it matters: It stops a design from being mistaken for a deployment.
The first seven items are designed in Stage 1H but not started. The controller, GitOps and observability are deferred. Building on AWS is blocked until credentials work.
- AWS credentials: BLOCKED (U15).
- Controller: direction accepted, implementation deferred (ADR 005).
- Stage 1H record: "No migration occurred".
Two conversion paths (Stage 1G)
qemu-img changes the box. virt-v2v changes the box and what is inside.
Why it matters: Stage 1H chose the virt-v2v output as the base for the future import image.
Both converted the same protected working copy to qcow2, and both booted under QEMU/KVM with UEFI and virtio. Neither fixed the network; one netplan change did.
- qemu-img: 5 s, guest bytes identical.
- virt-v2v: 136 s; VMware Tools removed, initramfs rebuilt.
- virt-v2v -o kubevirt: NOT TESTED.
How the network changes
The NIC name changes, so the old netplan breaks. Matching by driver fixes it.
Why it matters: A VM that boots without a network is still a failed migration.
VMXNET3 becomes virtio-net, and ens192 becomes enp0s3. Netplan still looked for ens192, so the guest had no network until one netplan change. The KubeVirt design uses the same fix with DHCP behind masquerade.
- 192.168.50.31 is not preserved (ADR 008).
- Continuity = the same nginx page hash through a NodePort Service.
- DNS: not proven.
How the disk storage changes
qcow2 in transit, raw on a Block PVC at rest. The PVC part is design only.
Why it matters: Storage choices decide what the VM can do later.
The VMDK was copied cold and converted to qcow2 in the lab. The design uploads a qcow2 through CDI into a 40 GiB gp3 Block PVC, stored raw. No PVC or DataVolume exists.
- The DataVolume is standalone: deleting the VM keeps the disk.
- ReadWriteOnce: not live-migratable, accepted for a cold migration.
- Route for moving the qcow2 to AWS: DEFERRED to 1I.
The Stage 1H target (ADRs 007 to 010)
Every layer of the target is chosen on paper. None of it exists.
Why it matters: The build stage will not have to guess: the target is fully specified.
One EC2 m8i.xlarge node in ap-south-1 with nested virtualization, CentOS Stream 9, Kubernetes 1.36 by kubeadm, KubeVirt v1.9.0 and CDI v1.66.1. The migrated guest would run in a virt-launcher Pod on QEMU/KVM.
- CDI v1.66.1 is a candidate until the runtime gate passes.
- About USD 0.24 per hour while running; destroyed after each session.
- EKS deferred, not rejected (ADR 007).
Where we could go from here
Only 1I is an official name, and it is undefined. Everything else is a proposal.
Why it matters: It shows a direction without pretending decisions were made.
After 1H is reviewed, a likely next step is to define 1I around building the target and a first KubeVirt boot. Everything after that comes from existing designs and has no stage numbers.
- What 1I contains is your decision.
- The order follows the documented architecture.
- No stage numbers beyond 1I.
THE ONE SCREEN I SHOULD REMEMBER
THEN: Stage 1I — the design was built, the VM was migrated to KubeVirt and validated, and the target was destroyed (2026-10-01)
NO KUBERNETES / KUBEVIRT / CDI DEPLOYMENT EXISTS NOW: THE STAGE 1I TARGET WAS DESTROYED.
Go deeper
This page adds no facts. The records below are the source of truth.