The IT industry media is full of successful reports of companies that have moved to cloud, with more new cloud-native applications being created every day. However, most applications that have been moved to the cloud are those that were already a good match for cloud environments. But there are many more applications that companies have invested significant effort to build over the past decades. The 2020 pandemic only serves to reinforce the importance of these existing assets to our society, needing these applications to adapt to new demands with minimal investment.
Companies want to reap the benefits of modern applications — to:
- Significantly decrease the time to market for new and innovative services
- Redefine customer experience by interacting with customers in real-time with minimal disruptions
- Optimize IT resources to reduce cost and complexity, and gain competitive advantage
- Improve security and protect sensitive data
To select the right approach to modernization and to deliver the right return on investment, you need to start with understanding the current state of each application and your business needs. The right approach to modernization for your applications might be to:
- Retain them on traditional architecture (not really modernization but a valid choice for some applications)
- Modernize, and potentially refactor, your existing applications (producing modern applications leveraging your existing investments)
- Build new replacement applications from scratch (valid in some circumstances)
This article briefly touches on the first and third options. This article discusses the second option in more detail, and what it means to modernize an existing application by modernizing your runtime, modernizing your operations, and modernizing your application architecture.
Choose the right modernization approach for your Java applications
The approach you take to modernization can vary for each application and should be based on a number of factors:
- The life-expectancy of the application
- Business needs of the application (for example, innovation, agility)
- Cost, whether the aim is to reduce cost or to invest for growth
- Technology skills and code reuse
While there is a lot of valid buzz around using a microservices architecture for applications running in containers, that doesn’t mean it’s the best choice for all of your applications, and your choice of architecture can greatly influence your choice of runtime. Ultimately, the goal is to have each application running in an environment that delivers the best return on investment for the business. The following diagram shows the main modernization choices available:
Let’s take a closer look at why you might choose each of the modernization options.
Retain on traditional architecture
You may choose to retain your applications on traditional architecture because the application is not strategic or, for various reasons, could have a limited lifespan. Investing time and resources to modernize the application might not be worth the cost right now. Retaining on traditional architectures can protect your investments while you possibly plan other modernization actions, such as re-architecting and re-writing the applications.
If you’re not moving, there’s nothing to do, especially if you are already on a supported infrastructure. If, however, the infrastructure is out of service and support, consider upgrading to a supported level. This is important in order to remain current with fixes to critical security vulnerabilities and to be able to get help when you encounter problems. You’ll also get access to new functionality and performance improvements.
If your runtime is traditional IBM WebSphere Application Server (Versions 8.5.5 and 9.0.5), support will be available through 2030 at least with no need to move off of Java 8. If you need to move to a new version, consider performing runtime modernization as an alternative. The cost savings from runtime modernization may make this a better return on investment, and it will enable further modernization in the future if necessary.
Modernize to cloud-native
For strategic applications, modernizing and moving them to the cloud helps reduce costs and improve agility. In many cases, the ultimate goal is to be able to rapidly update, re-use, and scale individual components of the application on modern cloud infrastructure and runtimes, greatly improving time-to-value. Getting there in one go can be challenging and risky, so we recommend considering three modernization steps, with each yielding value to the business, such as reducing technical debt and operating costs, and increasing agility:
- Runtime modernization (moving to a modern, cloud- and container-optimized runtime)
- Operational modernization (moving to a Kubernetes-based platform)
- Architecture modernization (refactoring into individually deployable and scalable microservices)
This order is the most common approach, but runtime and operational modernization can be done in either order or at the same time. Often, the choice to do runtime modernization first can come down to whether a company has already chosen and rolled out a container platform strategy, such as Red Hat OpenShift. If they haven’t, then runtime modernization is a great first step to being ready for containers.
Let’s take a look at each modernization step in more detail.
Step 1. Modernize runtime: Reduce operational cost and technical debt
Move your existing applications from a traditional runtime to a modern, cloud- and container-optimized runtime.
Your traditional application server scales very well for you and is highly available and reliable, so why modernize? The problem with traditional application servers is not these qualities — it’s the time and cost taken to get to the point where you have a workload in production and the efficiency of those workloads once in production.
Modern agile delivery best practices involve lightweight runtimes in container-based deployments driven by continuous integration (CI) and continuous delivery (CD) pipelines. These approaches drive out inefficiencies in application delivery. They:
- Reduce operational cost (lightweight runtimes consume fewer resources with higher throughput)
- Reduce technical debt (greater ability to deploy current, secure, and supported software)
Traditional application server runtimes are simply not designed for agility or the cloud, so they will ultimately inhibit your ability to deliver on the promise of cloud-native. Yes, you can modernize your operations by putting your existing application and runtime in containers (a valid step towards cloud-native), but, ultimately, you need to move to a modern runtime that’s designed for the agile delivery of modern applications.
Modernize your applications to run on Liberty (Open Liberty or, depending on the application, WebSphere Liberty, as WebSphere Liberty provides some older and traditional WebSphere-specific APIs that your applications may be using). Keep in mind where you want to get to with each application. You’ll probably want to operationally modernize to containers/Kubernetes and potentially modernize your architecture to microservices. You need to choose a runtime that supports this journey. A runtime for modernization needs to support monolithic applications, microservices, and the APIs required by both (Java EE, Jakarta EE, Eclipse MicroProfile, or Spring Boot). If you pick a runtime that doesn’t have these characteristics, then you’re not modernizing — you’re either moving sideways to another traditional runtime or rewriting, and rewriting is more than likely going to be higher risk and higher cost. Liberty, with its support for Java EE, Jakarta EE, MicroProfile, and Spring Boot, and the ability to tailor the runtime for specific workloads, is an ideal choice.
See “6 reasons why Open Liberty is an ideal choice for developing and deploying microservices” (IBM Developer, October 2020) to understand the benefits of using Liberty.
Of course, moving to a new runtime is not effortless, and this is why we recommend using IBM Cloud Transformation Advisor to help. Transformation Advisor can:
- Assess your existing applications, or even deployments
- Provide guidance on the areas requiring change and the effort required to make those changes
- Generate configuration to help with the migration
Step 2. Modernize operations: Reduce cost and complexity, and increase flexibility
Modernize operations through adoption of a Kubernetes-based container orchestration platform.
Adopting a container orchestration platform such as OpenShift enables you to move away from proprietary deployment and clustering approaches, such as traditional WebSphere Network Deployment cells. In doing so, you’ll gain a number of benefits:
- Reduced operational costs and complexity through technology and skill standardization. You’ll have a single approach to deploying, scaling, and monitoring applications, databases, caching, and messaging, all in containers.
- Increased operational portability across private and public clouds. It will be hard to find a cloud that doesn’t support Kubernetes, and all the major ones support OpenShift.
It’s worth noting that Kubernetes environments tend to differ from cloud to cloud, so while Kubernetes gives you some benefits within a single environment (for example, IBM Cloud Kubernetes Service), choosing a multi-cloud-managed Kubernetes solution such as OpenShift gives you these benefits across many clouds. You may not want to deploy to many clouds, or think that you need to, but regulatory reasons, such as GDPR, may cause you to do so.
Moving to a container orchestration platform requires you to start building best-practice container images that include your application and configuration, and build upon container images that provide common libraries, runtime, Java, and underlying OS.
If you’ve already performed runtime modernization to Liberty, then you’re on a runtime that’s ideal for moving to containers. The Transformation Advisor tools help with the creation of container images and advice on moving configuration from traditional WebSphere deployments to Kubernetes deployments. Additionally, each release of Liberty provides container images in Docker Hub:
- WebSphere Liberty container images on UBI
- WebSphere Liberty container images on Ubuntu
- Open Liberty container images on UBI
- Open Liberty container images on Ubuntu
The instructions, scripts, and Dockerfiles used to create these images are available in open source for you to build your own container images:
Finally, the Open Liberty Operator helps with Liberty deployment and management in Kubernetes environments. This operator works with both WebSphere Liberty and Open Liberty in Kubernetes-based platforms that support the Operator Framework, including OpenShift.
If you’ve chosen to do operational modernization ahead of runtime modernization, and so your applications are currently running on a traditional application server such as traditional WebSphere, you can deploy the application and server in a single container, and use OpenShift to scale it. Note, not all clustering capabilities available in WebSphere ND are available in Kubernetes/OpenShift (for example, remote EJB clustering), so care needs to be taken to ensure the application operates and scales correctly.
To aid with operational modernization with traditional WebSphere Applications Server, IBM maintains docker images for the versions currently in support.
Moving your traditional application server into containers should only be considered a stepping stone towards cloud-native. Traditional server runtimes were never designed for containers, modern DevOps practices, or cloud-native best practices, as exemplified by 12-factor applications. Longer-term you will be far better served by moving to a runtime designed for containers and microservices, with Liberty being an ideal choice.
Step 3. Modernize architecture: Achieve optimal scaling and cloud-native agility
Refactor a monolithic application into finer-grained cloud-native microservices.
You’ve modernized your operations to a Kubernetes-based platform and migrated your monolithic application to run on a runtime optimized for containers and the cloud. The next step is to start moving to microservices. In doing so, you’ll be able to truly unlock the full benefits of cloud-native microservices:
- Agile delivery of individual service updates through continuous integration, continuous delivery pipelines. No longer will the delivery of updates be bound by the delivery of the entire monolith.
- The ability to independently scale individual services to react to varying workload demands in a way that optimizes cloud usage and cost.
There are a number of facets to architecture modernization, but the first step is to identify capabilities within the monolithic application to refactor into microservices. A new AI-powered tool called IBM Mono2Micro (available in beta) can analyze your monolithic application and propose ‘partitions’ as candidates to separate into microservices. You don’t have to take a big-bang approach and break up the entire monolith. In fact, strategies such as the ‘strangler pattern‘ have successfully been applied as an incremental approach.
In breaking the monolith into microservices, you need to consider how to separate not only the business logic but also any associated data. Refactoring your applications into smaller deployable units has benefits and can be used as a step towards independent microservices, but if you still back all your services with a monolithic data store, then your services are still coupled. Data modernization ‘Strangler’-style strategies for decoupling data over time can successfully be employed. These include setting up a separate data store for the new service, batch data copying, dual writing, and proxying data requests from the monolith to bring the new store online and run the new service alongside the monolith.
Inherent in the move to loosely-coupled logic and data is the need to understand the impact on transactions. CAP theorem states that you can only simultaneously guarantee two of the qualities of Consistency, Availability, and Partition-tolerance. In traditional applications, distributed two-phase transaction managers are used to ensure consistency at all times. Breaking applications into tens or hundreds of microservices each backed by their own data store renders distributed transactions impractical. This has given rise to approaches that favor availability and embrace eventual consistency. Two approaches to achieve this are Sagas (for example, MicroProfile Long Running Actions) and Command Query Responsibility Separation (CQRS). At any point in time, the state of the systems can be inconsistent by-design — view data may not immediately reflect the latest updates, and activities ‘coordinated’ between microservices are permitted to complete independently.
Build new cloud-native
For particularly challenging applications where the cost to modernize outweighs the benefits, building new cloud-native applications from scratch is an option to consider. In doing so, you have the potential to achieve the benefits outlined in the previous modernization sections, such as reduced infrastructure costs and greater agility.
It’s important to choose a runtime to optimize across skills, technology, and cost. If you’re modernizing existing applications as well as rewriting or writing new applications, it makes sense to optimize the number of runtimes and APIs that you use. The runtime choice you make should favor using a runtime that supports new cloud-native APIs, such as MicroProfile, and existing APIs, such as Java EE, as well as the architecture styles you’re likely to use (for example, monolith, microservices). Also consider the infrastructure as well as license costs associated with using the runtime. Don’t assume that all new applications should be implemented as microservices, as the benefits and costs of doing so may not align with your goals for the application.
The importance of DevOps
If you’re already doing DevOps, continuous integration, and continuous delivery, you’ll need to consider the impact of modernization at each stage. Each type of modernization discussed in this article affects your DevOps work: building, testing, and deploying on a new runtime with new operational capabilities.
If you’re not already doing DevOps, continuous integration, or continuous delivery, you’ll need to factor this into your modernization strategy. There are advantages to adopting DevOps early in your modernization journey, but it is absolutely mandatory when you move to microservices (for example, as part of architecture modernization or building new applications). Your microservices strategy will not succeed with manual, labor-intensive delivery processes and siloed organizations.
License flexibility aids modernization
Whichever modernization strategy you adopt, your software infrastructure needs will evolve. While you may begin with running your existing applications on traditional WebSphere Application Server, as you progress, some workloads will move to Liberty with, potentially, new architectures such as containerized microservices running on Kubernetes.
IBM provides flexible licensing options to help with this journey. Each individual edition of WebSphere Application Server includes entitlement to Liberty. So, for example, you can choose to use your WebSphere Application Server Network Deployment entitlements for traditional WebSphere or Liberty. If you want to re-balance across editions, then offerings such was IBM WebSphere Application Server Family Edition enable you to do that, too. You can begin with running WebSphere Application Server Network Deployment then, when it comes time to deploy to Liberty on Kubernetes, just scale back on the number of deployed WebSphere Application Server Network Deployment servers that you have, and instead use those entitlements to deploy Liberty.
This article has provided a framework for choosing the appropriate modernization approach for each of your applications. The article outlined how modernization can be broken down into three steps, with value delivered by each, and how tools such as Transformation Advisor and Mono2Micro help:
- Runtime modernization: Moving to a modern, microservice- and container-optimized runtime to reduce infrastructure costs and technical debt.
- Operational modernization: Moving to a Kubernetes-based platform to reduce operational costs and complexity, and increase portability across public and private clouds.
- Architecture modernization: Decomposing into individually deployable and scalable microservices to increase delivery agility and optimize cloud resource usage.
This article has described the importance of choosing the right runtime for modernization: a runtime that supports monolithic applications and microservices, and the APIs required by both, and how that runtime is Liberty. This article also described the benefits of Kubernetes as a common cloud infrastructure but how a platform such as OpenShift truly enables the freedom of deployment across public and private clouds.
We hope you find this information helpful as you plan and execute your modernization journey.
- Video: App modernization and the case for microservices
- Article: Modernize your valuable Java applications (this article)
- Article: Challenges and patterns for modernizing a monolithic application into microservices
- Podcast: The Application Modernization Series: Architecture
- Article: Architectural considerations for event-driven microservices-based systems