Originally sourced from enterprisersproject.com. Rewritten and expanded for a DevOps engineering audience.
Why Migrating to Containers Is Different from Building for Containers
Building a greenfield application with containers and Kubernetes in mind is a very different undertaking from migrating an existing application to that model. The architectural assumptions, the operational constraints, and the risk profile all differ. Yet many teams approach both problems the same way — and pay for it later.
As Chris Short, then Principal Technical Marketing Manager for Red Hat OpenShift, put it: “None of the abstractions that exist in Kubernetes today make the underlying systems any easier to understand. They only make them easier to use.” Expect your teams to learn from mistakes, and plan accordingly.
The five best practices below draw on advice from practitioners and DevOps advocates to help engineering teams navigate a migration that is realistic, deliberate, and sustainable.
1. Don’t Migrate Just Because You Can
The first question to answer is not how to containerize your application — it is whether you should. Technically, you can package almost any application in a container. That does not make it the right architectural decision.
Ravi Lachhman, DevOps advocate at Harness, frames it this way: “Moving to containers and Kubernetes just for the sake of doing it can actually introduce a lot more scope and technical challenges, depending on the applications and the teams running them. Migrating existing applications into a new platform with a long-term vision in mind helps teams focus on innovation and doing what’s right for the applications.”
A common scenario where this evaluation matters is the lift-and-shift from on-premises infrastructure to a public cloud. Ken Mugrage, Principal Technologist in the Office of the CTO at ThoughtWorks, cautions against treating containers as a default transport mechanism: “While you most likely can package that application in a single container and then run it in Kubernetes, it’s rarely the best way to get it to the cloud.”
Miles Ward, CTO at SADA, adds an important qualifier around stateful workloads: “The workloads that give us pause are those that require a disk to which they record important long-lived data.” For these cases, a managed database service or other purpose-built solution may be a better fit than Kubernetes persistent volumes.
Questions to Ask Before You Begin
- Does the application have stateful storage requirements that Kubernetes persistent volumes would struggle to satisfy cleanly?
- Is the primary goal faster deployment cycles, improved resilience, or cost reduction — and does containerization actually advance that goal?
- Does the team have the operational maturity to run and troubleshoot containerized workloads in production?
- Would a managed platform-as-a-service offering solve the same problem at lower complexity?
2. Seriously Consider Refactoring Before You Migrate
If the decision to migrate is sound, the next question is whether to containerize the application as-is or to refactor it first. In most cases, refactoring delivers significantly more value.
Rani Osnat, VP of Strategy at Aqua Security, explains the risk of skipping this step: “Containers can be used for ‘lifting and shifting’ existing applications, but in order to enjoy their benefits, you should consider refactoring them. Taking a 2GB monolithic application and containerizing it as is will create issues in deployment and runtime since the container stack wasn’t made for this use case.”
His recommendation: break the application into smaller, logical services. This enables the deployment speed, resilience, and independent updatability that Kubernetes is designed to provide.
Mugrage encourages teams to shift their mental model entirely: “Don’t think of it as moving to containers and Kubernetes; think of it as decomposing the application. The real gains to speed of delivery, allowing evolution of your architecture, and all of the other reasons for moving to containers and Kubernetes are realized not from that movement, but the architecture which enabled it.”
Practical Refactoring Guidance
- Start small: Identify one bounded context or service boundary within the monolith and extract it first.
- Avoid the “big bang” approach: Decomposing incrementally reduces risk and allows the team to validate the container strategy before full commitment.
- Apply the strangler fig pattern: Route traffic progressively to new containerized services while the legacy application remains operational.
- Twelve-factor principles matter here: Applications that externalise config, avoid local filesystem state, and log to stdout are far easier to containerize cleanly.
3. Consider Starting with an Older, More Painful Application
Instinct often leads teams to start by migrating their newest, cleanest applications — the ones that are already well-maintained and relatively easy to work with. This feels lower-risk, but it may also deliver the lowest return on investment.
Mugrage challenges this assumption: “You may have newer applications which are easier to maintain and update than some of your older applications. It’s natural to decide to move these newer ones first because it may be easier. While that may be true, the benefits aren’t as great.”
Older applications that are expensive to deploy, difficult to scale, or slow to change are often the ones that would benefit most from decomposition and containerisation. The operational pain they cause is precisely the signal that the architecture needs to change.
His recommendation is targeted and pragmatic: “Consider starting by decomposing parts of your older applications where you need to be able to react faster than you’re currently able.” You do not have to rewrite the entire application. Extracting a single high-churn component as a containerised service, while leaving the rest of the monolith intact, can deliver meaningful improvement without a full re-architecture.
How to Identify Good Candidates
- Services or modules with frequent, independent release cycles that are blocked by monolithic deployment pipelines.
- Components that require independent scaling (e.g., a report-generation module that spikes CPU under load).
- Modules with clear API boundaries that already communicate via HTTP or messaging rather than in-process calls.
- Parts of the system where a production incident would be isolated in impact — allowing safer experimentation.
4. Invest in Observability Before and After Migration
One area not explicitly covered in the original source, but universally agreed upon in the practitioner community, is the need for strong observability during and after a container migration. Kubernetes adds significant operational complexity — more moving parts, more network hops, more failure modes — and without visibility into what is happening, debugging production issues becomes exponentially harder.
Before migrating, ensure you have:
- Baseline metrics for the existing application (CPU, memory, latency, error rates) so you can validate parity post-migration.
- Structured logging configured so that container logs can be aggregated and queried centrally.
- Distributed tracing if you are decomposing the application into multiple services — request tracing across service boundaries is essential.
- Health check endpoints (
/healthz,/readyz) that Kubernetes liveness and readiness probes can use to manage pod lifecycle correctly.
5. Treat Team Readiness as a First-Class Requirement
Technology migration is only half the challenge. The other half is organisational. Kubernetes has a steep learning curve, and teams that are not prepared for it will struggle in production regardless of how well the initial migration was executed.
Chris Short’s observation bears repeating: the abstractions in Kubernetes make the underlying systems easier to use, not easier to understand. When something breaks — and it will — your engineers need to understand what is happening at the network, storage, and scheduling layer. A surface-level familiarity with kubectl commands is not sufficient.
Practical steps to close the readiness gap:
- Run failure exercises in non-production environments before going live — simulate pod evictions, node failures, and image pull errors so teams know how to respond.
- Document runbooks for common failure scenarios specific to your deployment.
- Assign clear ownership of cluster operations versus application operations — the boundary is often a source of friction without explicit definition.
- Start with a managed Kubernetes service (e.g., GKE, EKS, AKS) to reduce the operational burden of control plane management while teams are building fluency.
Summary
| Best Practice | Core Principle |
|---|---|
| 1. Evaluate before you migrate | Not every application benefits from containerisation — validate the fit first. |
| 2. Refactor, don’t just repackage | The architectural change unlocks the value; the container is just the delivery mechanism. |
| 3. Start where the pain is greatest | Older, harder-to-change applications often offer the highest return on migration investment. |
| 4. Build observability in from the start | You cannot debug what you cannot see — instrument before migrating. |
| 5. Prepare your team, not just your infrastructure | Kubernetes literacy and operational runbooks are prerequisites, not afterthoughts. |
Migrating to containers and Kubernetes is a strategic decision, not a technical checkbox. Done with intention — and with the right architectural and organisational groundwork — it can meaningfully accelerate delivery, improve resilience, and reduce operational toil. Done carelessly, it adds complexity without benefit.