Migrate Spring Boot applications to Azure Spring Cloud

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

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)

Inspect application components

Identify local state

On PaaS environments, no application is guaranteed to be running exactly once at any given time. Even if you configure an application to run in a single instance, a duplicate instance can be created in the following cases:

  • The application must be relocated to a physical host due to failure or system update.
  • The application is being updated.

In any of these cases, the original instance will remain running until the new instance has finished starting up. This has the following potentially significant implications for your application:

  • No singleton can be guaranteed to be truly single.
  • Any data that has not been persisted to outside storage will likely be lost far sooner than it would on a single physical server or VM.

Before migrating to Azure Spring Cloud, ensure that your code does not contain local state that must not be lost or duplicated. If local state exists, change the code to store that state outside the application. Cloud-ready applications typically store application state in locations such as the following:

Determine whether and how the file system is used

Find any instances where your services write to and/or read from the local file system. Identify where short-term/temporary files are written and read and where long-lived files are written and read.

Note

Azure Spring Cloud provides 5 GB of temporary storage per Azure Spring Cloud instance, mounted in /tmp. If temporary files are written in excess of that limit or into a different location, code changes will be required.

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.

Determine whether any of the services contain 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.

Switch to a supported platform

Azure Spring Cloud offers specific versions of Java and specific versions of Spring Boot and Spring Cloud. To ensure compatibility, first migrate your application to one of the supported versions of Java in its current environment, then proceed with the remaining migration 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

For supported versions of Java, Spring Boot, and Spring Cloud, as well instructions for updating, see Prepare a Java Spring application for deployment in Azure Spring Cloud.

Identify Spring Boot versions

Examine the dependencies of each application being migrated to determine its Spring Boot version.

Maven

In Maven projects, the Spring Boot version is typically found in the <parent> element of the POM file:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
Gradle

In Gradle projects, the Spring Boot version will typically be found in the plugins section, as the version of the org.springframework.boot plugin:

plugins {
  id 'org.springframework.boot' version '2.2.6.RELEASE'
  id 'io.spring.dependency-management' version '1.0.9.RELEASE'
  id 'java'
}

For any applications using Spring Boot 1.x, follow the Spring Boot 2.0 migration guide to update them to a supported Spring Boot version. For supported versions, see Prepare a Java Spring app for deployment.

Identify log aggregation solutions

Identify any log aggregation solutions in use by the applications you are migrating.

Identify application performance management (APM) agents

Identify any application performance monitoring agents in use with your applications (such as Dynatrace and Datadog). In place of such agents, Azure Spring Cloud offers deep integration with Azure Monitor for performance management and real-time response to aberrations. For more information, see Post-migration.

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.

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:

Identify any clients relying on a non-standard port

Azure Spring Cloud overwrites the server.port setting in the deployed application. If any clients of the clients rely on the application being available on a port other than 443, you will need to modify them.

All other external resources

It isn't feasible for this guide to document every possible external dependency. After the migration, it's your responsibility to verify that you can satisfy every external dependency of your application.

Inventory configuration sources and secrets

Inventory 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, you can typically find such strings in the application.properties or application.yml file.

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>

Inspect the deployment architecture

Document hardware requirements for each service

Document the following information for your Spring Boot application:

  • The number of instances running.
  • The number of CPUs allocated to each instance.
  • The amount of RAM allocated to each instance.

Document geo-replication/distribution

Determine whether your Spring Boot application instances are currently distributed among several regions or data centers. Document the uptime requirements/SLA for the applications you're migrating.

Migration

Create an Azure Spring Cloud instance and apps

Provision an Azure Spring Cloud instance in your Azure subscription, if one does not already exist. Then, create an application there. For more information, see Quickstart: Launch an existing Azure Spring Cloud application using the Azure portal.

Ensure console logging and configure diagnostic settings

Configure your logging so that all output is routed to the console and not to files.

After an application is deployed to Azure Spring Cloud, add a diagnostic setting to make logged events available for consumption, for example via Azure Monitor Log Analytics.

LogStash/ELK Stack

If you use LogStash/ELK Stack for log aggregation, configure the diagnostic setting to stream the console output to an Azure Event Hub. Then, use the LogStash EventHub plugin to ingest logged events into LogStash.

Splunk

If you use Splunk for log aggregation, configure the diagnostic setting to stream the console output to Azure Blob Storage. Then, use the Splunk Add-on for Microsoft Cloud Services to ingest logged events into Splunk.

Configure persistent storage

If any part of your application reads or writes to the local file system, you'll need to configure persistent storage to replace the local file system. For more information, see Use persistent storage in Azure Spring Cloud.

You should write any temporary files to the /tmp directory. For OS independence, you can get this directory by using System.getProperty("java.io.tmpdir"). You can also use java.nio.Files::createTempFile to create temporary files.

Migrate all certificates to KeyVault

Azure Spring Cloud doesn't provide access to the JRE keystore, so you must migrate certificates to Azure KeyVault, and change the application code to access certificates in KeyVault. For more information, see Get started with Key Vault certificates and Azure Key Vault Certificate client library for Java.

Remove application performance management (APM) integrations

Eliminate any integrations with APM tools/agents. For information on configuring performance management with Azure Monitor, see the Post-migration section.

Disable metrics clients and endpoints in your applications

Remove any metrics clients used or any metrics endpoints exposed in your applications.

Deploy the application

Deploy each of the migrated microservices (not including the Spring Cloud Config and Registry servers), as described in Quickstart: Launch an existing Azure Spring Cloud application using the Azure portal.

Configure per-service secrets and externalized settings

You can inject any per-service configuration settings into each service as environment variables. Use the following steps in the Azure portal:

  1. Navigate to the Azure Spring Cloud Instance and select Apps.
  2. Select the service to configure.
  3. Select Configuration.
  4. Enter the variables to configure.
  5. Select Save.

Spring Cloud App Configuration Settings

Migrate and enable the identity provider

If any of the Spring Cloud applications require authentication or authorization, ensure they're configured to access the identity provider:

  • 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.

Expose the application

By default, applications deployed to Azure Spring Cloud are not visible externally. You can expose your application by making it public with the following command:

az spring-cloud app update -n <application name> --is-public true

Skip this step if you are using or intend to use a Spring Cloud Gateway (more on this in the following section).

Post-migration

Now that you've completed your migration, verify that your application works as you expect. You can then make your application more cloud-native by using the following recommendations.

  • Consider enabling your application to work with Spring Cloud Registry. This will enable your application to be dynamically discovered by other deployed microservices and clients. For more information, see Tutorial: Prepare a Java Spring app for deployment. Then, modify any application clients to use the Spring Client Load balancer. This allows the client to obtain addresses of all the running instances of the application and find an instance that works if another instance become corrupted or unresponsive. For more information, see Spring Tips: Spring Cloud Load Balancer in the Spring Blog.

  • Instead of making your application public, consider adding a Spring Cloud Gateway instance. Spring Cloud Gateway provides a single endpoint for all applications/microservices deployed in your Azure Spring Cloud instance. If a Spring Cloud Gateway is already deployed, ensure that it's configured to route traffic to your newly deployed application.

  • Consider adding a Spring Cloud Config server to centrally manage and version-control configuration for all your Spring Cloud microservices. First, create a Git repository to house the configuration and configure the Azure Spring Cloud instance to use it. For more information, see Tutorial: Set up a Spring Cloud Config Server instance for your service. Then, migrate your configuration using the following steps:

    1. Inside the application's src/main/resources directory, create a bootstrap.yml file with the following contents:

        spring:
          application:
            name: <your-application-name>
      
    2. In the configuration Git repository, create a .yml file, where your-application-name is the same as in the preceding step. Move the settings from application.yml file in src/main/resources to the new file you just created. If the settings were previously in a .properties file, converted them to YAML first. You can find online tools or IntelliJ plugins to perform this conversion.

    3. Create an application.yml file in the directory above. You can use this file to define settings and resources that will be shared among all applications on the Azure Spring Cloud instance. Such settings typically include data sources, logging settings, Spring Boot Actuator configuration, and others.

    4. Commit and push these changes to the Git repository.

    5. Remove the application.properties or application.yml file from the application.

  • Consider adding a deployment pipeline for automatic, consistent deployments. Instructions are available for Azure Pipelines, for GitHub Actions, and for Jenkins.

  • Consider using staging deployments to test code changes in production before they're available to some or all of your end users. For more information, see Set up a staging environment in Azure Spring Cloud.

  • Consider adding service bindings to connect your application to supported Azure databases. These service bindings would eliminate the need for you to provide connection information, including credentials, to your Spring Cloud applications.

  • Consider using Distributed Tracing and Azure App Insights to monitor performance and interactions of your applications. For more information, see Use distributed tracing with Azure Spring Cloud.

  • Consider adding Azure Monitor alert rules and action groups to quickly detect and address aberrant conditions. For more information, see Tutorial: Monitor Spring Cloud resources using alerts and action groups.

  • Consider replicating the Azure Spring Cloud deployment in another region for lower latency and higher reliability and fault tolerance. Use Azure Traffic Manager to load balance among deployments or use Azure Front Door to add SSL offloading and Web Application Firewall with DDoS protection.

  • If geo-replication isn't necessary, consider adding an Azure Application Gateway to add SSL offloading and Web Application Firewall with DDoS protection.