Migrate JBoss EAP applications to JBoss EAP on Azure App Service

This guide describes what you should be aware of when you want to migrate an existing JBoss EAP application to run on JBoss EAP in an Azure App Service instance.

Pre-migration

To ensure a successful migration, before you start, complete the assessment and inventory steps described in the following sections.

Inventory server capacity

Document the hardware (memory, CPU, disk) of the current production server(s) and the average and peak request counts and resource utilization. You'll need this information regardless of the migration path you choose. It's useful, for example, to help guide selection of the size of the VMs in your node pool, the amount of memory to be used by the container, and how many CPU shares the container would need.

Inventory all secrets

Check all properties and configuration files on the production server(s) for any secrets and passwords. Be sure to check jboss-web.xml in your WARs. Configuration files that contain passwords or credentials may also be found inside your application.

Consider storing those secrets in Azure KeyVault. For more information, see Azure Key Vault basic concepts.

You can use Key Vault secrets in your App Service instance with Key Vault references. Key Vault references allow you to use the secrets in your application while keeping them secured and encrypted at rest. For more information, see Use Key Vault references for App Service and Azure Functions.

Inventory all certificates

Document all the certificates used for public SSL endpoints. You can view all certificates on the production server(s) by running the following command:

keytool -list -v -keystore <path to keystore>

Validate that the supported Java version works correctly

JBoss EAP on Azure App Service requires a supported version of Java. For guidance on which version of the JDK to use, see Supported Configurations in the Red Hat documentation and the Show Java version section of Configure a Java app for Azure App Service.

Note

This validation is especially important if your current server is running on an unsupported JDK (such as Oracle JDK or IBM OpenJ9).

To obtain your current Java version, sign in to your production server and run the following command:

java -version

Inventory external resources

External resources, such as data sources, JMS message brokers, and others are injected via Java Naming and Directory Interface (JNDI). Some such resources may require migration or reconfiguration.

Inside your application

Inspect the WEB-INF/jboss-web.xml and/or WEB-INF/web.xml files. Look for <Resource> elements inside the <Context> element.

Datasources

Datasources are JNDI resources with the type attribute set to javax.sql.DataSource. For each datasource, document the following information:

  • What is the datasource name?
  • What is the connection pool configuration?
  • Where can I find the JDBC driver JAR file?

For more information, see About JBoss EAP Datasources in the JBoss EAP documentation.

All other external resources

It isn't feasible to document every possible external dependency in this guide. It's your team's responsibility to verify that you can satisfy every external dependency of your application after the migration.

Determine whether session replication is used

If your application relies on session replication, you'll have to change your application to remove this dependency. App Service does not allow instances to communicate directly with one another.

Determine whether and how the file system is used

Any usage of the file system on the application server will require reconfiguration or, in rare cases, architectural changes. The file system may be used by JBoss EAP modules or by your application code. You may identify some or all of the scenarios described in the following sections.

Read-only static content

If your application currently serves static content, you'll need an alternate location for it. You may wish to consider moving static content to Azure Blob Storage and adding Azure CDN for lightning-fast downloads globally. For more information, see Static website hosting in Azure Storage and Quickstart: Integrate an Azure storage account with Azure CDN.

Dynamically published static content

If your application allows for static content that is uploaded/produced by your application but is immutable after its creation, you can use Azure Blob Storage and Azure CDN as described above, with an Azure Function to handle uploads and CDN refresh. We've provided a sample implementation for your use at Uploading and CDN-preloading static content with Azure Functions.

Dynamic or internal content

For files that are frequently written and read by your application (such as temporary data files), or static files that are visible only to your application, you can use local file storage associated with your app service plan. For more information, see Operating system functionality on Azure App Service and Understanding the Azure App Service file system.

Determine whether your application relies on scheduled jobs

Scheduled jobs, such as Quartz Scheduler tasks or Unix cron jobs, should NOT be used with Azure App Service. Azure App Service will not prevent you from deploying an application containing scheduled tasks internally. However, if your application is scaled out, the same scheduled job may run more than once per scheduled period. This situation can lead to unintended consequences.

Inventory any scheduled tasks running on the production server(s), inside or outside your application code.

Determine whether a connection to on-premises is needed

If your application needs to access any of your on-premises services, you'll need to provision one of Azure's connectivity services. For more information, see Choose a solution for connecting an on-premises network to Azure. Alternatively, you'll need to refactor your application to use publicly available APIs that your on-premises resources expose.

Determine whether Java Message Service (JMS) Queues or Topics are in use

If your application is using JMS Queues or Topics, you'll need to migrate them to an externally hosted JMS server. Azure Service Bus and the Advanced Message Queuing Protocol (AMQP) can be a great migration strategy for those using JMS. For more information, see Use JMS with Azure Service Bus and AMQP 1.0.

If JMS persistent stores have been configured, you must capture their configuration and apply it after the migration.

Determine whether JCA connectors are in use

If your application uses JCA connectors, validate that you can use the JCA connector on JBoss EAP. If you can use the JCA connector on JBoss EAP, then for it to be available, you must add the JARs to the server classpath and put the necessary configuration files in the correct location in the JBoss EAP server directories.

Determine whether JAAS is in use

If your application is using JAAS, you'll need to capture how JAAS is configured. If it's using a database, you can convert it to a JAAS domain on JBoss EAP. If it's a custom implementation, you'll need to validate that it can be used on JBoss EAP.

Determine whether your application uses a Resource Adapter

If your application needs a Resource Adapter (RA), it needs to be compatible with JBoss EAP. Determine whether the RA works fine on a standalone instance of JBoss EAP by deploying it to the server and properly configuring it. If the RA works properly, you'll need to add the JARs to the server classpath of the App Service and put the necessary configuration files in the correct location in the JBoss EAP server directories for it to be available.

Determine whether your application is composed of multiple WARs

If your application is composed of multiple WARs, you should treat each of those WARs as separate applications and go through this guide for each of them.

Determine whether your application is packaged as an EAR

If your application is packaged as an EAR file, be sure to examine the application.xml file and capture the configuration.

Note

If you want to be able to scale each of your web applications independently for better use of your App Service resources you should break up the EAR into separate web applications.

Identify all outside processes and daemons running on the production servers

If you have any processes running outside the application server, such as monitoring daemons, you'll need to eliminate them or migrate them elsewhere.

Perform in-place testing

Before creating your container images, migrate your application to the JDK and JBoss EAP versions that you intend to use on App Service. Test the application thoroughly to ensure compatibility and performance.

JBoss EAP on App Service feature notes

When using JBoss EAP on App Service, be sure to take the following notes into consideration.

  • Server-to-server clustering: Due to network security constraints, application instances on App Service cannot communicate directly with one another. If your current JBoss deployment uses clustering, consider using JBoss EAP on virtual machine scale sets or externalizing the session and state information. For more information, see Configuring high availability and Infinispan and cache containers in the Red Hat documentation.
  • JBoss EAP management console: The JBoss web console isn't exposed on App Service. Instead, the Azure portal provides the management APIs for your application, and you should deploy using the Azure CLI, Azure Maven Plugin, or other Azure developer tools.
  • Transactions: The application instances are run in a stateless manner, so the Transactions API isn't currently supported. For more information, see Managing transactions on JBoss EAP in the Red Hat documentation.
  • Managed domain mode: In a multi-server production environment, Managed Domain mode in JBoss EAP offers centralized managed capabilities. However with JBoss EAP on App Service, the App Service platform assumes the responsibility for configuration and management of your server instances. App Service eliminates the need for JBoss EAP’s managed domain mode. Domain mode is a good choice for virtual machine-based multi-server deployments. For more information, see About managed domains in the Red Hat documentation.

Migration

Provision Azure App Service for JBoss EAP runtime

Use the following commands to create a resource group and an Azure App Service Plan. After the App Service Plan is created, a Linux web app plan is created using the JBoss EAP runtime. You can create JBoss EAP sites only on PremiumV3 and IsolatedV2 App Service Plan tiers.

Be sure the specified environment variables have appropriate values.

Note

PremiumV3 and IsolatedV2 are both eligible for Reserved Instance pricing, which can reduce your costs. For more information on App Service Plan tiers and Reserved Instance pricing, see App Service pricing.

az group create --resource-group $resourceGroup --location eastus
az acr create --resource-group $resourceGroup --name $acrName --sku Standard
az appservice plan create \
    --resource-group $resourceGroup \
    --name $jbossAppService \
    --is-linux \
    --sku P1V2
az webapp create \
    --resource-group $resourceGroup \
    --name $jbossWebApp \
    --plan $jbossAppServicePlan \
    --runtime "JBOSSEAP|7.2-java8"

Build the application

Build the application using the following Maven command.

mvn clean install -DskipTests

Deploy the application

If your application is built from a Maven POM file, use the Webapp plugin for Maven to create the Web App and deploy your application. For more information, see Quickstart: Create a Java app on Azure App Service.

To automate the deployment of JBoss EAP applications, you can use Azure Pipelines task for Web App or GitHub Action for deploying to Azure WebApp.

Set up data sources

There are three core steps when registering a data source with JBoss EAP: uploading the JDBC driver, adding the JDBC driver as a module, and registering the module. For more information, see Datasource Management in the JBoss EAP documentation. App Service is a stateless hosting service, so the configuration commands for adding and registering the data source module must be scripted and applied as the container starts.

To set up data sources, use the following steps.

  1. Obtain your database's JDBC driver.

  2. Create an XML module definition file for the JDBC driver. The example shown below is a module definition for PostgreSQL. Be sure to replace the resource-root path value with the path to the JDBC driver you use.

    <?xml version="1.0" ?>
    <module xmlns="urn:jboss:module:1.1" name="org.postgres">
        <resources>
        <!-- ***** IMPORTANT: REPLACE THIS PLACEHOLDER *******-->
        <resource-root path="/home/site/deployments/tools/postgresql-42.2.12.jar" />
        </resources>
        <dependencies>
            <module name="javax.api"/>
            <module name="javax.transaction.api"/>
        </dependencies>
    </module>
    
  3. Put your JBoss CLI commands into a file named jboss-cli-commands.cli. The JBoss commands must add the module and register it as a data source. The example below shows the JBoss CLI commands for PostgreSQL.

    #!/usr/bin/env bash
    module add --name=org.postgres --resources=/home/site/deployments/tools/postgresql-42.2.12.jar --module-xml=/home/site/deployments/tools/postgres-module.xml
    
    /subsystem=datasources/jdbc-driver=postgres:add(driver-name="postgres",driver-module-name="org.postgres",driver-class-name=org.postgresql.Driver,driver-xa-datasource-class-name=org.postgresql.xa.PGXADataSource)
    
    data-source add --name=postgresDS --driver-name=postgres --jndi-name=java:jboss/datasources/postgresDS --connection-url=${POSTGRES_CONNECTION_URL,env.POSTGRES_CONNECTION_URL:jdbc:postgresql://db:5432/postgres} --user-name=${POSTGRES_SERVER_ADMIN_FULL_NAME,env.POSTGRES_SERVER_ADMIN_FULL_NAME:postgres} --password=${POSTGRES_SERVER_ADMIN_PASSWORD,env.POSTGRES_SERVER_ADMIN_PASSWORD:example} --use-ccm=true --max-pool-size=5 --blocking-timeout-wait-millis=5000 --enabled=true --driver-class=org.postgresql.Driver --exception-sorter-class-name=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter --jta=true --use-java-context=true --valid-connection-checker-class-name=org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker
    
  4. Create a startup script called startup_script.sh that calls the JBoss CLI commands. The example below shows how to call your jboss-cli-commands.cli file. Later you will configure App Service to run this script when the instance starts.

    $JBOSS_HOME/bin/jboss-cli.sh --connect --file=/home/site/deployments/tools/jboss-cli-commands.cli
    
  5. Using an FTP client of your choice, upload your JDBC driver, jboss-cli-commands.cli, startup_script.sh, and the module definition to /site/deployments/tools/.

  6. Configure your site to run startup_script.sh when the container starts. In the Azure portal, navigate to Configuration > General Settings > Startup Command. Set the startup command field to /home/site/deployments/tools/startup_script.sh, then select Save.

  7. Restart the web app, which will cause it to run the configuration script.

  8. Update the JTA datasource configuration for your application. Open the src/main/resources/META-INF/persistence.xml file for your app and find the <jta-data-source> element. Replace its contents as shown here:

    <jta-data-source>java:jboss/datasources/postgresDS</jta-data-source>
    

Build the application

Build the application using the following Maven command.

mvn clean install -DskipTests

Deploy the application

If your application is built from a Maven POM file, use the Webapp plugin for Maven to create the Web App and deploy your application. For more information, see Quickstart: Create a Java app on Azure App Service.

To automate the deployment of JBoss EAP applications, you can use Azure Pipelines task for Web App or GitHub Action for deploying to Azure WebApp.

Post-migration

Now that you've migrated your application to Azure App Service, you should verify that it works as you expect. After you've done that, we have some recommendations for you that can make your application more cloud-native.

Recommendations