Containerizing Legacy Applications: The Clean and the Dirty Approach!
Should you containerize legacy applications? And can you really do it effectively?
The answer to both questions is yes. Even if you have an application that was not originally designed to run inside a container, it’s possible to deploy it using a platform like Docker. And the effort required to do so is often well worth it.
In this post, we'll take a look at basic strategies for moving legacy apps into containers. We’ll also discuss which type of containerization strategy is likely to be best for your legacy apps, as well as what makes a legacy app suitable or unsuitable for containerization.
Why run legacy apps inside a container?
First, though, let’s make clear why you would want to containerize a legacy app.
Legacy apps can remain useful for years or even decades after their initial release. An older application may have a large and well-established user base, willing to pay for support and updates indefinitely, rather than adjust to new software. The useful lifetime of an application may be considerably longer than that of the platform on which it was originally developed or delivered.
If you have such an app, it makes sense to adapt it to current infrastructure platforms (such as containers) when possible. That’s more efficient than rewriting the entire application each time a new type of infrastructure becomes available.
Containerising legacy applications can also add much needed speed and agility to applications that still need to be changed.
The ‘clean’ approach to containerization
If you are containerising a legacy app, there are two general approaches you can take—one ‘clean’ and the other ‘dirty.’ We’ll discuss the clean strategy first before moving onto the dirty approach.
Keeping it Clean
What makes the ‘clean’ strategy for containerizing legacy apps clean in the first place? More than anything, it's about containerizing the app in such a way that you maintain the basic philosophy of containerization and microservices.
Most legacy apps in their original states are far from being microservice-oriented. Most well-designed container-based apps, on the other hand, are embodiments of microservice architecture. To containerize a legacy app the clean way, you must refactor it so that it is modular and can be inserted into a microservice architecture.
What's the best way to refactor a legacy app? There are times when the approach to refactoring will be suggested by the existing architecture of the app itself, and there are times when the nature and requirements of the app will impose design constraints which might not be present in a designed-from-scratch container app. But for the most part, you'll be faced with a few basic choices. They include:
- Break it down by function or responsibility. If the application is already organised into clearly defined sets of functions (or responsibilities, which are basically larger sets of functions, such as shopping cart checkout), you can use these as the basis for refactoring. Microservices might consist of single functions, or sets of closely connected functions and responsibilities.
- Break it down by resources. Microservices can be defined by their relationship to specific resources—accessing databases, communicating with other applications, or interfacing with peripherals. etc. You can refactor along these lines.
- Break it down by existing component and unit boundaries. This can be useful when the legacy app's existing architecture includes clearly defined boundaries, across which data moves by means of limited channels.
In practice, of course, you are likely to use a combination of each of these strategies in refactoring a typical legacy app. Functional boundaries, resource boundaries, and data boundaries often coincide to one degree or another, and sets of functions often interact with a limited set of resources. As you come to recognise these patterns of interaction, the natural boundaries that can be used to define microservices become more apparent.
This kind of refactoring takes time and effort, but the result is likely to be something very close to a native container app, which takes full advantage of the container system's features.
The dirty approach
What about the not-so-clean strategy for containerizing a legacy app?
Dirty containerization consists basically of taking the entire legacy app and stuffing it into a container, making the necessary adjustments required for it to operate in a container environment. An app that is containerized in this way can leverage some container features (those involving networking and system resources, for example), but without a full redesign, it won’t be a microservices-based app.
The resulting containerized app is likely to be bloated and not optimised to run as a container. Still, it will allow the application to run on next-generation containerized infrastructure, and allow us to secure the other benefits of Docker such as simplified deployments, consistent environments, and better resource consumption of infrastructure.
Needless to say, with legacy apps, this clean/dirty distinction may not always be so clear. It may be easier to refactor partially (in other words, to move some functions out to microservices, but keep large chunks of the original code intact). When this happens, the result may not be elegant in terms of containerization standards or microservices architecture, but it may make good use of most container features without requiring a level of refactoring effort that can't be justified by the value of the software.
And sometimes you just don’t...
And there are those legacy apps which are simply not suitable for containerization, either of the clean or dirty kind. This includes apps written in outdated programming languages (RPG and FORTRAN IV are happy at the retirement home, and don't need to be bothered with containerization, for instance).
Other apps that depend on resources—such as obsolete or arcane hardware, non-standard databases, or specialised peripherals—may not lend themselves well to containerization. In these cases, you would be better served by rewriting the app in a modern, container-friendly framework instead of trying to squeeze it into a container just to make it run on containerized infrastructure.
So, should you containerize legacy apps? Yes, as long as you understand what you're doing, why you're doing it, and what the limitations of the process are. You can teach old apps new tricks. And in those cases when a legacy app isn't up to learning new tricks, you can keep its existing user base happy by adapting the app so that users can deploy it via a container. The result may fall far short of being as elegant as a native container app, but more often than not, it's worth the effort.