Tutorials

A Step-by-Step Guide to Migrating Java EE Applications to DC/OS

Apr 12, 2018

Mark Johnson

D2iQ

9 min read

 
In the prior blog post we discussed the benefits of migrating legacy Java EE applications to a modern platform such as Mesosphere DC/OS. This blog post presents a set of concrete steps to make this possible.
For our migration we have a legacy Java EE application running on Oracle's WebLogic. We don't have time to re-code the application (although our team has already requested resources for a complete re-write to Spark or Node) and the application is currently chewing up a lot of CPU and memory resources running in a virtual machine.Our goal is to migrate the app to a modern platform quickly and without changes. This tutorial walks you through the steps needed to accomplish this:
 
Java EE App Migration: Planning and Resource Availability
Before we start the application migration process, we need to do some up-front information gathering and planning to make sure the process goes smoothly. Our migration checklist includes:
.blog-table td{ padding:5px 7px;}



































 
Check | Discovered Value
App Deployment Style | WAR file
App Server | WebLogic 12c
App Path | /benefits
External properties or Jar files | None (note: the approach described in this blog can be extended to support external properties and Jar files)
Total # Apps to Migrate | 100+
1st App to Migrate | Benefits
Resources to Migrate for 1st App | Benefits.war
For your application migration process, update the discovered values with your own values. For our checklist, let's walk through a step by step migration of our first app, Benefits.

 
After collecting data, we can start the migration process. Our first step is to check the Dashboard page in DC/OS for available cluster resources. We only need to account for the application resource requirement, not for any virtual machine system overhead since DC/OS runs directly on the bare-metal machine. Assuming we only need one or two cores per app, with roughly 24 free CPU cores and just under 100 GB RAM available, we have plenty of room to migrate the first group of apps.
Adding a Java EE App as a New Service in DC/OS
Now that we've confirmed we're good to go, let's add a new service by clicking the ‘+' icon at the top right side of the screen.
Then select ‘Single Container' mode so we can begin defining our new Java EE service.
Requirements:
 
  • This app is one of many assigned to the department ‘dept-a', one of many in the organization.
  • We need to deploy the application to Oracle WebLogic Server.
  • We must dynamically build and deploy our app. We have over 100 legacy apps and we don't want to manually manage and patch code in that many containers.
  • The application must be deployed in a manner to support scalability.
Mesosphere DC/OS supports the concept of Application Groups. For our migration, we will insert this application into an application group. To add our application to the ‘dept-a' application group we will specify the Service ID in the format of ‘/dept-a/weblogic-benefits-app'.
We review our app's past performance and see that the minimum requirements are 1 CPU core (the prior machine deployed with oversubscription had 4 cores allocated) and roughly 2GB of RAM. For most of the time, we will need only 1 instance, so let's specify 1 CPU, 1 Instance, and 2048 MB of RAM.
We have a choice of one of two container runtimes: the official Docker daemon runtime and the Mesos Universal Container Runtime (UCR). The choice is yours, but we'll select the Mesos UCR because it offers additional features, is fully compatible with Docker images, and anecdotally seems more reliable in our testing.
Do not to select the "Force Pull On Launch" option as this will degrade performance in production. Selecting this option favors flexibility over performance, causing DC/OS to re-pull the Docker image from the repository every time the app is restarted or re-scaled.
Instead, we can dynamically build and deploy our application using the DC/OS fetch capability while avoiding recurrent patching of hundreds of Docker images. The DC/OS fetcher downloads the resource specified in the ‘Artifact URI' into the container. For our migration, we can leverage this functionality by specifying the WAR file containing our application. In this manner we are only utilizing one ‘base' Docker image which in this case is ‘tkrausjr/1221-appdeploy:v2'. In this way, patching the OS or the WebLogic Application server requires modifying and updating only our base image.
We can enter any valid shell script command into the Command section. In this example, we enter env | sort && ls -lt /u01/oracle && pwd to provide us with debugging information relating to the active environment variables and the content of the directories of interest. The next part && mv /mnt/mesos/sandbox/benefits.war /u01/oracle/benefits.war of the command is where we move the benefits.war file which was fetched by the Artifact URI from the /mnt/mesos/sandbox directory into the /u01/oracle directory for the WebLogic WLST application's consumption.
Our next step is to run the WLST app-deploy script. This script takes some of the environmental variables (defined later) and deploys our benefits.war application into WebLogic using the command && wlst /u01/oracle/app-deploy.py. Assuming the app has properly deployed within WebLogic, we are ready to start WebLogic using the command && startWebLogic.sh
Configuring Networking and Load Balancing
Our legacy Java EE app now needs its networking settings specified, making sure to avoid host server port conflicts. We also need to set up load balancing to scale our app on its new platform. Select ‘Networking' from the left command bar to display our list of options as shown below.
Our application requires port 8001 and we want the flexibility for it to run on a private agent so we've specified ‘Bridge' networking and added a container port 8001 for mapping to the host. DC/OS will select the host port (the port running the actual server node for the cluster) in order to prevent contention.
Selecting ‘Enable Load Balance Service Address' allows us to support multiple application instances. This automatically creates a DNS address available to all permitted DC/OS services following the pattern of {Application name}.marathon.l4lb.thisdcos.directory:{load balance port number}. Now we can have services, jobs, and DC/OS tasks communicate with our migrated Java EE app without changing any code or worrying about which instance they are communicating with.
Configuring Health Checks for Java EE Apps in DC/OS
DC/OS offers a full suite of storage options, but as our application does not require storage at this time, the description of these storage options will have to wait for a future blog.  Instead our attention needs now to focus on the health check.
DC/OS health checks enable our ancient legacy application to enjoy the scalability and high-availability benefits of a modern platform. When an app is reported "healthy", DC/OS knows it can serve requests to it. When an app is reported "unhealthy", DC/OS knows that it needs to start up a new instance. If the server instance hosting the application fails, or undergoes any maintenance effort such as OS patching and restart, DC/OS will automatically restart the application on another server instance..
There are two types of DC/OS health checks: HTTP and Command. For our Java EE app, we choose the HTTP option because it is the simpler of the two and satisfies the app's availability requirements. Command allows for the use of sophisticated commands to fully validate the health of an application and should always be considered when high availability is required.
To enable the HTTP health check, select the HTTP option from the dropdown as shown in the image below:
Our next step is to select the service endpoint we defined earlier (‘weblogic-management-server') from the drop-down list. Enter ‘/benefits' as the health check path as that's how the app was referenced on the prior platform.
After entering our settings and accepting the other settings as their defaults, we see the following instructions defining our health check:
Defining Environmental Variables and Managing Secrets for Java EE Apps in DC/OS
Our next step is to define the environmental variables required for the WebLogic application deployer and the WebLogic application server. This method also works for the other common Java EE application servers. DC/OS allows you to define environmental variables in one place as part of the application definition that is reference by all container instances of our migrated app. This not only simplifies application deployment, but also allows you to change the environmental variables in a single location, as needed, without having to restart or rebuild a container.
At the bottom of the Environment screen are two interesting sections: Labels and Secrets. Labels is where we define meta information for the application. For example, specifying ‘HAPROXY_GROUP' with the value ‘external' relies on Marathon-lb to make your migrated Java EE app available outside the DC/OS cluster.
A major problem most legacy Java EE apps suffer from is a lack of security around the application server and database passwords. The people charged with maintaining the app need these passwords to fix problems as they come up and, because of the challenges associated with changing these passwords, they often go unchanged for years and even decades.
The DC/OS Secrets Manager solves the age-old problem of publicly known and static passwords. The DC/OS administrator can define any number of secrets containing the passwords to application servers, databases, LDAP servers, and any other secured resource.  The administrator then provides the application owner with the secret name and not the actual secret. The application owner then selects the secret for their application and a variable name, which in this case the WebLogic Application server will recognize.
We need the environmental variable "ADMIN_PASS' to provide the WLST application deploy script with sufficient permissions, and that password is contained in the secret ‘ADMIN_PASS'.
Administrators can now change the app server and database passwords and, when the migrated Java EE application is restarted, those passwords will take effect.
Launching the Migrated Java EE App
Our migration definition steps are now complete. All that's left is to click ‘Review & Run' and then click ‘Run Service'.
Once deployment commences, we can monitor our newly migrated Java EE app from the ‘Tasks' screen. As we see below, the deployment is currently ‘Staging', which means it is pulling down the Docker image. Staging takes a minute or so, a significant improvement over requesting a new server and installing it manually, because of the size of the WebLogic application server. The staging process can be decreased by removing unnecessary components from your base image.
Our Java EE app is now up and running in a healthy state. We have deployed a single instance (for now) to the host server 10.0.2.47.
Monitoring Java EE Apps in DC/OS
We can quickly check the WebLogic logs by clicking the icon that has the ‘View logs' callout (as shown above) without having to SSH into individual servers.
Once our application is running and healthy, it's time to check our Haproxy status page by opening the URL http://{public ip}:9090/haproxy?stats. Looking through the list, we see our app referenced in "dept-a_weblogic-benefits-app_10100". This tells us that the public port is "10100".
Success!
Knowing that the public IP address is "54.186.174.240", we can access our migrated Java EE app via http://54.186.174.240:10100, which provides the result as shown below. We have successfully migrated our legacy Java EE app to a modern platform with the ability to elastically scale and automatically recover from any form of application outage.
In the next blog post in this series, we will take our migrated application and explore more benefits of running it on a modern application platform like DC/OS. Please join our Painless Modernization of Java EE Applications webinar for more information.

Ready to get started?