Most “lift the monolith into containers” projects stall for the same reason: the team treats it as one enormous cutover instead of a sequence of small, reversible moves. The application still has to serve real traffic the entire time, so the only migration that survives contact with production is the boring, incremental one. Here is the approach we use when the requirement is zero planned downtime.

Start by containerizing, not re-architecting

The first goal is narrow: get the existing application running inside a container that behaves identically to the VM it replaces. Resist every urge to “fix things while you’re in there.” A migration that also refactors business logic has two independent ways to fail and no way to tell them apart.

  • Pin the base image to the same OS and runtime version already in production.
  • Externalize configuration and secrets — nothing baked into the image.
  • Reproduce the health, readiness, and logging behavior the platform team expects.

When the containerized build passes the same smoke tests as the legacy host, you have earned the right to move on. Not before.

Route traffic with a strangler, not a switch

Rather than flipping DNS from old to new, put a reverse proxy in front and move one route at a time. The strangler fig pattern lets the containerized service take over a single endpoint while everything else keeps hitting the legacy stack. Each slice you migrate is independently testable and independently reversible.

The safest cutover is the one you can undo in seconds by changing a single weight in the load balancer.

Prove parity before you shift load

For each route, run the old and new implementations side by side and compare responses — status codes, payload shape, latency. Shadow traffic (mirroring live requests to the new service without serving its responses) catches the differences that staging never will. Only once parity holds for a representative window do you begin shifting real percentages of traffic: 1%, then 10%, then 50%.

Make rollback the default, not the emergency

Every step should have a documented, rehearsed way back. Keep the legacy path warm until the new one has held steady in production for longer than your typical incident-detection window. A migration is finished not when the container serves 100% of traffic, but when you have decommissioned the old path on purpose and nobody noticed.

Done this way, “containerize the legacy platform” stops being a high-risk weekend and becomes a series of quiet Tuesdays — which is exactly what you want from infrastructure work.