Migrate Spring Boot applications to Azure App Service

This guide describes what you should be aware of when you want to migrate an existing Spring Boot application to Azure App Service.

Pre-migration

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

If you can't meet any of these pre-migration requirements, see the following companion migration guides:

  • Migrate executable JAR applications to containers on Azure Kubernetes Service (guidance planned)
  • Migrate executable JAR Applications to Azure Virtual Machines (guidance planned)

Switch to a supported platform

App Service offers specific versions of Java SE. To ensure compatibility, migrate your application to one of the supported versions of its current environment before you continue with any of the remaining steps. Be sure to fully test the resulting configuration. Use the latest stable release of your Linux distribution in such tests.

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

To obtain the current version used by Azure App Service, download Zulu 8 if you intend to use the Java 8 runtime or Zulu 11 if you intend to use the Java 11 runtime.

Inventory external resources

Identify external resources, such as data sources, JMS message brokers, and URLs of other services. In Spring Boot applications, you can typically find the configuration for such resources in the src/main/directory folder, in a file typically called application.properties or application.yml. Additionally, check the production deployment's environment variables for any pertinent configuration settings.

Databases

For any SQL database, identify the connection string.

For a Spring Boot application, connection strings typically appear in configuration files.

Here's an example from an application.properties file:

spring.datasource.url=jdbc:mysql://localhost:3306/mysql_db
spring.datasource.username=dbuser
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

Here's an example from an application.yaml file:

spring:
  data:
    mongodb:
      uri: mongodb://mongouser:deepsecret@mongoserver.contoso.com:27017

See Spring Data documentation for more possible configuration scenarios:

JMS message brokers

Identify the broker or brokers in use by looking in the build manifest (typically, a pom.xml or build.gradle file) for the relevant dependencies.

For example, a Spring Boot application using ActiveMQ would typically contain this dependency in its pom.xml file:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-activemq</artifactId>
</dependency>

Spring Boot applications using proprietary brokers typically contain dependencies directly on the brokers' JMS driver libraries. Here's an example from a build.gradle file:

    dependencies {
      ...
      compile("com.ibm.mq:com.ibm.mq.allclient:9.0.4.0")
      ...
    }

After you've identified the broker or brokers in use, find the corresponding settings. In Spring Boot applications, you can typically find them in the application.properties and application.yml files in the application directory.

Here's an ActiveMQ example from an application.properties file:

spring.activemq.brokerurl=broker:(tcp://localhost:61616,network:static:tcp://remotehost:61616)?persistent=false&useJmx=true
spring.activemq.user=admin
spring.activemq.password=tryandguess

For more information on ActiveMQ configuration, see the Spring Boot messaging documentation.

Here's an IBM MQ example from an application.yaml file:

ibm:
  mq:
    queueManager: qm1
    channel: dev.ORDERS
    connName: localhost(14)
    user: admin
    password: big$ecr3t

For more information on IBM MQ configuration, see the IBM MQ Spring components documentation.

Identify external caches

Identify any external caches in use. Frequently, Redis is used via Spring Data Redis. For configuration information, see the Spring Data Redis documentation.

Determine whether session data is being cached via Spring Session by searching for the respective configuration (in Java or XML).

Identity providers

Identify any identity provider(s) used by your application. For information on how identity providers may be configured, consult the following:

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 every external dependency of your application can be satisfied after an App Service migration.

Inventory secrets

Passwords and secure strings

Check all properties and configuration files and all environment variables on the production deployment(s) for any secret strings and passwords. In a Spring Boot application, such strings will likely be found in application.properties or application.yml.

Inventory certificates

Document all the certificates used for public SSL endpoints or communication with backend databases and other systems. You can view all certificates on the production server(s) by running the following command:

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

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. You may identify some or all of the following scenarios.

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.

Special Cases

Certain production scenarios may require additional changes or impose additional limitations. While such scenarios can be infrequent, it's important to ensure that they're either inapplicable to your application or correctly resolved.

Determine whether application relies on scheduled jobs

Scheduled jobs, such as Quartz Scheduler tasks or cron jobs, can't be used with App Service. App Service won't 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 jobs, inside or outside the application process.

Determine whether your application contains OS-specific code

If your application contains any code with dependencies on the host OS, then you'll need to refactor it to remove those dependencies. For example, you may need to replace any use of / or \ in file system paths with File.Separator or Paths.get.

Identify all outside processes/daemons running on the production server(s)

Processes running outside of Application Server, such as monitoring daemons, will need to be migrated elsewhere or eliminated.

Identify handling of non-HTTP requests or multiple ports

App Service supports only a single HTTP endpoint on a single port. If your application listens on multiple ports or accepts requests using protocols other than HTTP, don't use Azure App Service.

Migration

Parameterize the configuration

Ensure that all external resource coordinates (such as database connection strings) and other customizable settings can be read from environment variables. If you're migrating a Spring Boot Application, all configuration settings should already be externalizable. For more information, see Externalized Configuration in the Spring Boot documentation.

Here's an example that references a SERVICEBUS_CONNECTION_STRING environment variable from an application.properties file:

spring.jms.servicebus.connection-string=${SERVICEBUS_CONNECTION_STRING}
spring.jms.servicebus.topic-client-id=contoso1
spring.jms.servicebus.idle-timeout=10000

Provision an App Service plan

From the list of available service plans, select the plan whose specifications meet or exceed those of the current production hardware.

Note

If you plan to run staging/canary deployments or use deployment slots, the App Service plan must include that additional capacity. We recommend using Premium or higher plans for Java applications.

Create the App Service plan.

Create and Deploy Web App(s)

You'll need to create a Web App on your App Service Plan (choosing "Java SE" as the runtime stack) for every executable JAR file you intend to run.

Maven applications

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.

Non-Maven applications

If you can't use the Maven plugin, you'll need to provision the Web App through other mechanisms, such as:

Once the Web App has been created, use one of the available deployment mechanisms to deploy your application. If possible, your application should be uploaded to /home/site/wwwroot/app.jar. If you don't wish to rename your JAR to app.jar, you can upload a shell script with the command to run your JAR. Then paste the full path to this script in the Startup File textbox in the Configuration section of the portal. The startup script doesn't run from the directory into which it's placed. Therefore, always use absolute paths to reference files in your startup script (for example: java -jar /home/myapp/myapp.jar).

Migrate JVM runtime options

If your application requires specific runtime options, use the most appropriate mechanism to specify them.

Configure custom domain and SSL

If your application will be visible on a custom domain, you'll need to map your web application to it. For more information, see Tutorial: Map an existing custom DNS name to Azure App Service.

Then, you'll need to bind the SSL certificate for that domain to your App Service Web App. For more information, see Secure a custom DNS name with an SSL binding in Azure App Service.

Import backend certificates

All certificates for communicating with backend systems, such as databases, need to be made available to App Service. For more information, see Add an SSL certificate in App Service.

Migrate external resource coordinates and other settings

Follow these steps to migrate connection strings and other settings.

Note

For any Spring Boot application settings parameterized with variables in the Parameterize the configuration section, those environment variables must be defined in the application configuration. Any Spring Boot application settings not explicitly parameterized with environment variables can still be overridden by them via Application Configuration. For example:

spring.jms.servicebus.connection-string=${CUSTOMCONNSTR_SERVICE_BUS}
spring.jms.servicebus.topic-client-id=contoso1
spring.jms.servicebus.idle-timeout=1800000

App Service Application Configuration

Migrate scheduled jobs

To execute scheduled jobs on Azure, consider using a Timer trigger for Azure Functions. You don't need to migrate the job code itself into a function. The function can simply invoke a URL in your application to trigger the job. If such job executions have to be dynamically invoked and/or centrally tracked, consider using Spring Batch.

Alternatively, you can create a Logic app with a Recurrence trigger to invoke the URL without writing any code outside your application. For more information, see Overview - What is Azure Logic Apps? and Create, schedule, and run recurring tasks and workflows with the Recurrence trigger in Azure Logic Apps.

Note

To prevent malicious use, you'll likely need to ensure that the job invocation endpoint requires credentials. In this case, the trigger function will need to provide the credentials.

Migrate and enable the identity provider

If your application requires authentication or authorization, ensure they're configured to access the identity provider by using the following guidance:

  • If the identity provider is Azure Active Directory, no changes should be necessary.
  • If the identity provider is an on-premises Active Directory forest, consider implementing a hybrid identity solution with Azure Active Directory. For more information, see the Hybrid identity documentation.
  • If the identity provider is another on-premises solution, such as PingFederate, consult the Custom installation of Azure AD Connect topic to configure federation with Azure Active Directory. Alternatively, consider using Spring Security to use your identity provider through OAuth2/OpenID Connect or SAML.

Restart and smoke-test

Finally, you'll need to restart your Web App to apply all configuration changes. Upon completion of the restart, verify that your application is running correctly.

Post-migration

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

Recommendations