Migrating WebSphere Application Server Applications to Cloud Foundry
Migration of WebSphere Application Server apps to Cloud Foundry entails dissecting the app for API usage and then configuring the implementation of the same APIs on a servlet container or an alternate open source EE server. My app server of choice for Java EE APIs is Tomcat + Spring Framework or Apache TomEE.
Migrations of Java EE applications vary in complexity, depending on a series of factors that are identified during the migration:
- Source and target Java SE specification (JRE 1.5 to JRE 1.8)
- Source and target Java EE specifications (J2EE 1.4 to Java EE 7)
- Usage of specific Java components (EJB, JSPs, JSF, etc.,)
- Usage of proprietary code that is specific for an application server
- Vendor-specific deployment descriptors
- Extended capabilities
- Vendor-specific server configurations (JMS providers and JDBC connection pooling)
- Class loading issues .
- Integration with complex external systems such as a CRM or SAP
From a code perspective an application owner has to ask questions related to Java, EJB usage, Servlets & JSPs, Web Services, database access, JMS, JNDI naming, Application trace & logging, UI frameworks, Transactions, Threads, sockets and XML/REST/JSON. The configuration and usage of these technologies will affect the migration of the app to Cloud Foundry. From a deployment perspective the following areas need to be probed: Current hardware, current network edge load balancing solution and expectation around session affinity, expected downtime during upgrade, current administration constructs, Details of the HTTP Server/Proxy Tier. hardware details & security (How exactly is the security of the app and app-server managed). From an architectural perspective to understand the technical barriers and issues in porting apps to cloud native CF platform please read Roadblocks to PaaS.
- Get a lay of the land. Identify ALL the open source and proprietary APIs used by the app. Determine what modifications you will need to make to the app if the target runtime packaged by the buildpack does not include the said libraries.
- Make a list of all WebSphere Proprietary APIs used by your app,
- Make a list of all the Java EE APIs used by your app,
- Make a list of all Spring Framework APIs used the app,
- Make a list of all 3rd party open source frameworks used by the app,
- Leverage static analysis tools like FindBugs, Checkstyle, PMD, Coverity and SonarQube. Write custom rules that will provide a breakdown of the external api usage. From the The Wise Developers' Guide to Static Code Analysis - PMD is a very customizable tool, so the performance and installation outcome really depends on how one has instructed the tool to find problems. Coverity is a commercial tool that it does a much deeper analysis than other tools and it also keeps track of the issues that you’ve found and fixed. SonarQube gives the best combination of usefulness and transparency against the relative complexity of setting it up and solving weird configuration issues.
- Run Google code search on your app source repository. Code Search is a tool for indexing and then performing regular expression searches over large bodies of source code. It is a set of command-line programs written in Go.
- Use a modern IDE like Netbeans, Eclipse and IntelliJ to find usage and references of classes and packages in your app code.
- Look at all the XML files bundled within the app. These XML Deployment descriptors can be categorized into two categories. Standard discriptors and app-server specific ones. You will need to replace the vendor specific depkoyment descriptors with TomEE descriptors or Spring Beans in Tomcat.
- If possible disaggregate the EAR file into multiple war files and tie them together as one logical app. This will increase loose coupling and force you to disentangle a web of dependencies that will make the transition to a microservices architecture much easier. You can chose to lift and shift your ear file as-is too since some of the buildpacks below will allow the staging of ear files. Typically it is OK to duplicate code like utility jars across multiple war files it leads to loose coupling and better isolation of function. Note as of today only the Liberty buildpack supports the cf push of ear files. The Tomcat based Java buildpack does not support ear files.
- Look at shared libraries configured for the app server across apps. These server scoped shared libraries will need to be bundled in the app when it is pushed to CF.
- Take advantage of Java EE6 and collapse EJBs and Servlets in a single war file. No classloader boundaries between Servlets and EJBs. EJBs and Servlets can share all third-party libraries (like Spring!), Use annotations and free your code from deployment descriptor hell.
- Do not concern yourself with anything that deals with clustering, workload management, high availability, smart routing or proxying. These concerns are now taken care of by the underlying platform i.e. CF.
- Check if there is any native code and ensure that the native library is included with the app and built on the linuxfs32 file system. When porting across Java EE versions please consider the breaking changes across EE specifications detailed in 3.3 J2EE to Java EE migration considerations
- Address runtime Migration Concerns:
- A common issue in migrating JMS resources is that the way each application server configures JMS resources varies from vendor to vendor. Before migrating JMS definition to WebSphere, you should decide which messaging engine to use to exchange messages asynchronously. CF provides multiple JMS & AMQP messaging providers.
- Reconfiguring the JDBC resources is a common migration step. Use the appropriate JDBC driver to avoid problems with new implementations for new databases. Java Buildpack makes it easy to consume SQL and NoSQL data stores in the app running on the platform. You can auto-configure connections to back-end services or use spring-cloud-connectors to explictly control the JDBC connection to the persistence tier in the cloud.
- There are several areas where you configure security resources for your migrated applications and the administrative functions and roles, such as authentication mechanisms, authorization mechanisms, and security for web services. Configure the target app server in Cloud Foundry with the correct AAA mechanisms to port all your security apparatus. Apache Tomcat 8 Security Considerations
- Port JVM arguments, class path, and system properties to the buildpack and
cf pushmanifests in Cloud Foundry.
- Understand the external factors that affect migration like interaction with external CRM/ERP systems via XML or legacy web-service stacks.
- By default, the Tomcat instance provided by the Java Buildpack is configured to store all sessions and their data in memory. If your app relies on session persistence then configure session replication in CF by binding the app to a DB like redis session replication on Cloud Foundry. In some cases the configuration of the app to use the session database may need to be done explicitly based on the service variables injected via the
VCAP_SERVICESenvironment variable. CF by default supports sticky session i.e. honors the
- If the app does not run on WebSphere Liberty Profile then use the WebSphere Migration Toolkit to get the app running on the WebSphere Liberty Profile. The Liberty Tech Preview tool helps you move WebSphere Application Server full profile applications to Liberty profile, which can be running inside or outside of the cloud. Follow the steps outlined by Cindy High on moving applications to Liberty using the migration toolkit.
- You have now come to a fork in the road. You have multiple choices [AppServer(WebSphere | TomEE | JBOSS) * Cloud packager(Buildpack | Docker)] in deploying your app to CF.
- Run the app in Cloud Foundry using the WebSphere Liberty Profile Buildpack. WebSphere Liberty Profile provides production support for Java EE7 and requires zero-migration across versions of the app server. The licensing model of running Liberty in production are NOT clear. The way I read the license, is that WebSphere Liberty profile can be used in production on CF for JVM heaps <= 2GB. So this gives you the license to install Liberty and fixes thereafter; not entitlement to support. No serious enterprise can run all their business on 2GB JVM heap. The catch here is that all your apps in total across the org cannot exceed 2 GB in heap. You can share 2GB across as many instances of Liberty as you like as long as the total JVM heap space across the instances does not exceed 2GB. ;) . Basically the first instance is free and thereafter you pay. Of course this licensing does not apply to Bluemix where you can run as many instances as you like as long as you pay Bluemix GB/hr cost.
- Run the app in Cloud Foundry using TomEE. See this blog post from Romain Manni-Bucau that explains how to get the app running on Bluemix which is the IBM derivative of CF. The same technique will work on open source and other distributions of CF. This technique stages and runs the app as an embedded TomEE server within the app. 50 Shades of TomEE explains the many ways an executable fat jar can be cooked with your app and TomEE binaries. Another popular packaging option is to follow recipes and prepare a docker container of the app using the official TomEEDocker image from TomEETribe. Deployment of Docker image in Cloud Foundry is possible with the Diego BOSH release. Diego supports running of Docker images natively within CF. The recommendation here is to ONLY package the app in Docker and rely on the platform to inject service metadata. A great guide on packaging apps with Docker and keeping your docker images can be found in Adam Bien's blog JAVA EE 7 + THIN WARS + DOCKER = GREAT PRODUCTIVITY.
- Stage and run the app in JBoss now renamed as WildFly, JavaEE certified application server using the jboss-buildpack. Redhat has provided a detailed guide on How-to migrate application running on WebSphere to WildFly was2jboss. If your application is not cloud-native then package and deploy your app using the official WildFly Docker image.
- Refactor the app based on decomposition recipes outlined by Matt Stine in Migrating to Cloud-Native Application Architectures such as the anti-corruption layer and strangling the monolith. As you refactor the app to a microservices based architecture use SpringCloud OSS to implement the distributed services patterns necessary to overcome the fallacies of distributed computing. A playbook on app refactoring is provided by Josh Kruck here. Run the refactored slmmed down app on a specialized micro-server like Spring-Boot or DropWizard, What we want is a simple, lightweight, fire-and-forget packaging tool for server-side code taking advantage of executable JARs’ simplicity and platform independence. Merging all dependencies into a single JAR can be done with Tools like Maven’s Shade plugin or Gradle’s Shadow plugin. Before deciding on Spring Boot or DropWizard understand the tradeoffs as explained by the good folk at Takipi.
- If you do not want to put any effort in refactoring the app since it is of low strategic value and business impact then simply packing the app in a Docker container and pushing it to PCF will allow you to deploy the app to the platform and leverage the operational & cost benefits with very little development cost. Run the IBM WebSphere Application Server Full and Liberty profiles in a Docker Container following documentation in FullWasInDocker and LibertyInDocker. Again Licensing headaches apply :-(. To get started with running in WebSphere go through this IBM InterConnect 2015 session on WebSphere Application Server Liberty Profile and Docker.