How Migration Works
PodMotion migrates a running Kubernetes pod from one node to another without stopping it. It is the container-layer equivalent of hypervisor live VM migration: the live process tree is checkpointed with CRIU, its memory and open state are transferred to the destination node, and the pod is restored there — while the workload keeps serving.
This page is the conceptual on-ramp. It explains the shape of a migration, the two things that make live migration hard (in-flight TCP connections and attached storage), and — precisely — what has and has not been proven so far. For field-level detail, follow the links to the CRD Reference, Observability Reference, and Security Architecture.
PodMotion is alpha software (v0.1.0-alpha) and is not production-ready. The
claims on this page are scoped deliberately narrowly: read the
What is proven today and
What is not yet proven sections for the exact boundary.
The interface: one custom resource
The only supported interface in v0.1.0-alpha is the PodMigration custom
resource, applied with kubectl apply. There is no active kubectl podmotion
plugin — a plugin exists only as inactive scaffolding in a separate repository and
is not part of the supported v0.1.0-alpha interface. You describe the pod you
want to move; the controller drives the rest.
apiVersion: migration.podmotion.io/v1alpha1
kind: PodMigration
metadata:
name: migrate-my-app
namespace: default
spec:
podName: my-app-pod # required
podNamespace: default # required
targetNodeName: worker-a # optional; scheduler picks if empty
# tcpPreservationMode defaults to None. Opt in with Strict for TCP continuity.
See the CRD Reference for every field, and Getting Started to install and run your first migration.
The shape of a migration
A migration moves through a phase sequence. The connection-preserving path
(Strict or BestEffort) is, simplified:
Pending → SocketInventory → Validating → DestinationPrewarm → PreCopyMemory
→ ZeroWindowArm → FinalFreezeStateCapture → OverlayHandoff
→ RestoreSocketReattach → DisengageHold → TCPVerifying → ServiceVerifying
→ CutoverComplete → Complete
Every mode — None, BestEffort, and Strict — traverses all twelve pipeline
phases as status.phase transitions (the sequence above shows 14 states total:
the 12 pipeline phases bracketed by the starting Pending and terminal Complete
states), so this is the sequence you will see when you watch a migration with
kubectl get podmigration -w. What changes with the mode is
the work done inside those phases. In the default None mode (no TCP continuity),
the connection-preservation work inside several phases — SocketInventory,
DestinationPrewarm, ZeroWindowArm, OverlayHandoff, DisengageHold, and
TCPVerifying — is a no-op that advances immediately: the phase is still entered and
visible, but it does no TCP-specific work.
The load-bearing steps:
- Pre-copy. For
PreCopymode (the default), CRIU iteratively copies the pod's dirty memory pages to the destination while the pod keeps running, so the amount left to move at freeze time is small. - Freeze and checkpoint. The pod is briefly frozen and CRIU captures the final process state — memory, open file descriptors, and, for a connection-preserving migration, the state of established TCP sockets.
- Transfer. The checkpoint image is moved to the destination node.
- Restore. CRIU rebuilds the process tree on the destination node. This is the hardest step, and the one where environment-specific gaps show up first (see What is not yet proven).
- Verify, then cut over. The restored pod is probed; only after it is confirmed serving is traffic handed over.
The full phase vocabulary — 22 phase constants — together with the complete set of
status condition types lives in the CRD Reference and
Observability Reference. Status conditions on the
PodMigration CR are the primary way to observe progress: the controller-runtime
Prometheus /metrics endpoint is disabled by default (--metrics-bind-address
defaults to "0"), so in a default install the CR's status conditions are the
observability surface you read.
The source pod is never deleted early
Throughout a migration, the original pod stays alive. The controller only permits
the source pod to be deleted once a status condition confirms the destination pod
is verified serving traffic and healthy — the specific condition and its owning ADR
depend on mode (TrafficVerified / ADR-0012 outside Strict mode; ServiceContinuityVerified
/ ADR-0352 under Strict). See the CRD Reference for the exact
condition set per mode. If anything fails before that point, the migration rolls
back to the still-running source pod.
TCP connection continuity is opt-in
Moving a stateless pod is one thing. Moving a pod that is holding an established TCP connection — and keeping that connection alive across the move, with no reset visible to the client — is the hard case.
TCP continuity is off by default. spec.tcpPreservationMode defaults to
None, which skips TCP verification entirely. You opt in explicitly:
| Mode | Behavior |
|---|---|
None (default) | No TCP continuity; stateless workloads. |
Strict | Migration hard-fails and rolls back if TCP continuity cannot be verified. |
BestEffort | Attempts preservation; warns rather than rolling back on failure. |
When continuity is verified, the measure is the TCP sequence delta. A sequence
delta of zero (seq_delta=0) means the TCP sequence numbers on both ends of the
connection matched exactly — neither side saw a single byte of drift, and the
connection was never dropped.
What is proven today
Everything below is proven on one substrate only: a standing 3-node KVM/libvirt
kubeadm cluster, on amd64, running:
- Ubuntu 24.04
- Kubernetes v1.35.x
- Cilium CNI v1.17.6 — tunnel (geneve) encapsulation, with per-endpoint
/32routes (endpointRoutes) for preserved-IP cross-node reachability - CRIU 4.2 on every node
This KVM cluster is the current proven substrate. (An older Flannel VXLAN path is retained only as a rollback baseline; it is not the proven substrate, and earlier arm64 / Flannel figures do not describe this platform.)
On that cluster, in a single test run, two individual single-workload migrations were
demonstrated end-to-end, each moving from one worker node to another and reaching
phase=Complete:
- Redis, in
Strictmode, holding a live TCP connection under load. The held client connection continued across the cutover with no break, verified byte-exact (1 of 1 connections) with a send/receive sequence delta of0/0— zero sequence drift, no dropped connection. A canary value written before the move was read back correctly through the service afterward. Elapsed 33s; freeze window 602ms. - Postgres, under continuous write load, backed by shared (ReadWriteMany) storage.
The storage volume re-attached on the destination node and writes continued with
zero write loss: the row counter advanced normally (8 → 16) through the
migration window with 0 post-migration write errors. Elapsed 43s; freeze
window 766ms. This exercises ReadWriteMany re-attach only — it does not
exercise or imply live block-storage migration, which remains deferred to
v1.2.
Both workloads completed their migrations repeatedly and cleanly within that same run.
This is deliberately narrow. These are two individual, single-workload
migrations on the KVM cluster. PodMotion does not claim that live migration
reaches Complete reliably across arbitrary workloads, that a full connected
multi-tier application moves as a single unit, or that any substrate other than this
KVM cluster is proven. The scope is exactly the two cases above.
What is not yet proven
The KVM cluster is the only proven substrate. Other substrates — including
cloud-hosted kubeadm clusters — are not yet proven viable; the KVM result does
not carry over automatically. Restore is where substrate differences tend to show
up first (kernel, CNI, and storage-driver behavior on the destination node all
factor into it), which is part of why proving a new substrate takes dedicated work
rather than being assumed from the KVM result. Proving additional substrates is
ongoing, and this page will be updated as that work is verified.
See also
- Getting Started — install PodMotion and run a migration
- CRD Reference — the full
PodMigrationspec, phases, and conditions - Observability Reference — status conditions and freeze-window measurements
- Security Architecture — privilege posture and checkpoint threat model