Migrate Spring Cloud applications to Azure Container Apps

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

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

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.

Azure Container Apps offers several types of storage. Ephemeral storage can read and write temporary data and be available to a running container or replica. Azure File provides permanent storage and can be shared across multiple containers. For more information, see Use storage mounts in Azure Container Apps.

Read-only static content

If your application currently serves static content, you need an alternate location for it. You might 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 supports static content, whether uploaded or generated by the application itself, that remains unchanged after its creation, you can integrate Azure Blob Storage and Azure CDN. You can also use an Azure Function to manage uploads and trigger CDN refreshes when necessary. 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 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 if your application is running on Windows.

Switch to a supported platform

If you create your Dockerfile manually and deploy containerized application to Azure Container Apps, you take full control over your deployment including JRE/JDK versions.

For deployment from artifacts, Azure Container Apps also offers specific versions of Java (8, 11, 17, and 21) and specific versions of Spring Boot and Spring Cloud components. 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 Java on Azure Container Apps overview.

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>3.3.3</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 '3.3.3'
  id 'io.spring.dependency-management' version '1.1.6'
  id 'java'
}

For any applications using Spring Boot versions prior to 3.x, follow the Spring Boot 2.0 migration guide or Spring Boot 3.0 Migration Guide to update them to a supported Spring Boot version. For supported versions, see the Spring Cloud documentation.

Identify Spring Cloud versions

Examine the dependencies of each application you're migrating to determine the version of the Spring Cloud components it uses.

Maven

In Maven projects, the Spring Cloud version is typically set in the spring-cloud.version property:

  <properties>
    <spring-cloud.version>2023.0.2</spring-cloud.version>
  </properties>
Gradle

In Gradle projects, the Spring Cloud version is typically set in the "extra properties" block:

ext {
  set('springCloudVersion', "2023.0.2")
}

You need to update all applications to use supported versions of Spring Cloud. For supported versions, see the Spring Cloud documentation.

Identify log aggregation solutions

Identify any log aggregation solutions in use by the applications you're migrating. You need to configure diagnostic settings in migration to make logged events available for consumption. For more information, see Ensure console logging and configure diagnostic settings section.

Identify application performance management (APM) agents

Identify any application performance management agents used by your applications. Azure Containers Apps doesn't offer built-in support for APM integration. You need to prepare your container image or integrate APM tool directly into your code. If you want to measure your application's performance but haven't integrated any APM yet, consider using Azure Application Insights. For more information, see the Migration section.

Inventory external resources

Identify external resources, such as data sources, JMS message brokers, and URLs of other services. In Spring Cloud applications, you can typically find the configuration for such resources in one of the following locations:

  • In the src/main/resources folder, in a file typically called application.properties or application.yml.
  • In the Spring Cloud Config Server repository that you identified in the previous step.

Databases

For a Spring Boot application, connection strings typically appear in configuration files when it depends on an external database. 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 commercial 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.4.0.5")
      ...
    }

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

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 all identity providers and all Spring Cloud applications that require authentication and/or authorization. For information on how you can configure identity providers, see the following resources:

Resources configured through VMware Tanzu Application Service (TAS) (formerly Pivotal Cloud Foundry)

For applications managed with TAS, external resources, including the resources described earlier, are often configured via TAS service bindings. To examine the configuration for such resources, use the TAS (Cloud Foundry) CLI to view the VCAP_SERVICES variable for the application.

# Log into TAS, if needed (enter credentials when prompted)
cf login -a <API endpoint>

# Set the organization and space containing the application, if not already selected during login.
cf target org <organization name>
cf target space <space name>

# Display variables for the application
cf env <Application Name>

Examine the VCAP_SERVICES variable for configuration settings of external services bound to the application. For more information, see the TAS (Cloud Foundry) documentation.

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 deployments for any secret strings and passwords. In a Spring Cloud application, you can typically find such strings in the application.properties or application.yml file in individual services or in the Spring Cloud Config Server repository.

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 Spring Cloud Vault is used

If you use Spring Cloud Vault to store and access secrets, identify the backing secret store (for example, HashiCorp Vault or CredHub). Then identify all the secrets used by the application code.

Locate the configuration server source

If your application uses a Spring Cloud Config Server, identify where the configuration is stored. You typically find this setting in the bootstrap.yml or bootstrap.properties file, or sometimes in the application.yml or application.properties file. The setting looks like the following example:

spring.cloud.config.server.git.uri: file://${user.home}/spring-cloud-config-repo

While git is most commonly used as Spring Cloud Config Server's backing datastore, as shown earlier, one of the other possible backends may be in use. Consult the Spring Cloud Config Server documentation for information on other backends, such as Relational Database (JDBC), SVN, and the local file system.

Inspect the deployment architecture

Document hardware requirements for each service

For each of your Spring Cloud services (not including the configuration server, registry, or gateway), document the following information:

  • 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 the Spring Cloud applications are currently distributed among several regions or data centers. Document the uptime requirements/SLA for the applications you're migrating.

Identify clients that bypass the service registry

Identify any client applications that invoke any of the services to be migrated without using the Spring Cloud Service Registry. After the migration, such invocations will no longer be possible. Update such clients to use Spring Cloud OpenFeign before migration.

Migration

Remove restricted configurations

The Azure Container Apps environment offers managed Eureka Server, Spring Cloud Config Server, and Admin. When an application is bound to the Java component, Azure Container Apps injects related properties as system environment variables. According to the Spring Boot Externalized Configuration design, application properties defined in your code or packaged in artifacts are overwritten by system environment variables.

If you set one of the following properties via command-line argument, a Java system property, or container's environment variable, you must remove it to avoid conflicts and unexpected behavior:

  • SPRING_CLOUD_CONFIG_COMPONENT_URI
  • SPRING_CLOUD_CONFIG_URI
  • SPRING_CONFIG_IMPORT
  • eureka.client.fetch-registry
  • eureka.client.service-url.defaultZone
  • eureka.instance.prefer-ip-address
  • eureka.client.register-with-eureka
  • SPRING_BOOT_ADMIN_CLIENT_INSTANCE_PREFER-IP
  • SPRING_BOOT_ADMIN_CLIENT_URL

Create an Azure Container Apps managed environment and apps

Provision an Azure Container Apps app in your Azure subscription on an existing managed environment or create a new one for every service you're migrating. You don't need to create apps running as Spring Cloud registry and Configuration servers. For more information, see Quickstart: Deploy your first container app using the Azure portal.

Prepare the Spring Cloud Config Server

Configure the Config server in your Azure Container Apps for Spring component. For more information, see Configure settings for the Config Server for Spring component in Azure Container Apps.

Note

If your current Spring Cloud Config repository is on the local file system or on premises, you first need to migrate or replicate your configuration files to a cloud-based repository, such as GitHub, Azure Repos, or BitBucket.

Ensure console logging and configure diagnostic settings

Configure your logging to ensure that all output is routed to the console rather than to files.

After an application is deployed to Azure Container Apps, you can configure the logging options within your Container Apps environment to define one or more destinations of the logs. These destinations can include Azure Monitor Log Analytics, Azure Event hub, or even other third-party monitoring solutions. You also have the option to disable log data and view logs only at runtime. For detailed configuration instruction, see Log storage and monitoring options in Azure Container Apps.

Configure persistent storage

If any part of your application reads or writes to the local file system, you need to configure persistent storage to replace the local file system. You can specify the path to mount in the container through the app settings and align it with the path your app is using. For more information, see Use storage mounts in Azure Container Apps.

Migrate Spring Cloud Vault secrets to Azure KeyVault

You can inject secrets directly into applications through Spring by using the Azure KeyVault Spring Boot Starter. For more information, see How to use the Spring Boot Starter for Azure Key Vault.

Note

Migration might require you to rename some secrets. Update your application code accordingly.

Migrate all certificates to KeyVault

Azure Containers Apps supports secure communication between apps. Your application doesn't need to manage the process of establishing secure communication. You can upload the private certificate to Azure Container Apps or use a free managed certificate provided by Azure Container Apps. Using Azure Key Vault to manage certificates is a recommended approach. For more information, see Certificates in Azure Container Apps.

Configure application performance management (APM) integrations

If you've already configured APM-related variables within the container, all you need to do is ensure that the connection to the target APM platform can be established. If the APM configuration references environment variables from the container, you need to set the runtime environment variables accordingly on Azure Container Apps. Sensitive information, such as the connection string, should be handled securely. You can either specify it as a secret or reference a secret stored in Azure Key Vault.

Configure per-service secrets and externalized settings

You can inject configuration settings into each container as environment variables. Any changes in the variables create a new revision for the existing app. Secrets are key-value pairs and remain valid across all revisions.

Migrate and enable the identity provider

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

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

Update client applications

Update the configuration of all client applications to use the published Azure Container Apps endpoints for migrated applications.

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 component enables your application to be dynamically discovered by other deployed Spring applications and clients. For more information, see Configure settings for the Eureka Server for Spring component in Azure Container Apps. Then, modify any application clients to use the Spring Client Load Balancer. The Spring Client Load Balancer enables the client to obtain addresses of all the running instances of the application and find an instance that works if another instance becomes 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 deployed in your Azure Container Apps environment. If a Spring Cloud Gateway is already deployed, ensure that a routing rule is 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 applications. First, create a Git repository to house the configuration and configure app instance to use it. For more information, see Configure settings for the Config Server for Spring component in Azure Container Apps. 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 <your-application-name>.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 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 are shared among all applications in the Azure Container Apps environment. 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 the Admin for Spring managed component to enable an administrative interface for Spring Boot web applications that expose actuator endpoints. For more information, see Configure the Spring Boot Admin component in Azure Container Apps.

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

  • Consider using container apps revisions, revision labels, and ingress traffic weights to enable blue-green deployment, which enables you to test code changes in production before they're made available to some or all of your end users. For more information, see Blue-Green Deployment in Azure Container Apps.

  • 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 enabling the Java development stack to collect JVM core metrics for your applications. For more information, see Java metrics for Java apps in Azure Container Apps.

  • Consider adding Azure Monitor alert rules and action groups to quickly detect and address aberrant conditions. For more information, see Set up alerts in Azure Container Apps.

  • Consider replicating your app across the zones in the region by enabling Azure Container Apps zone redundancy. Traffic is load balanced and automatically routed to replicas if a zone outage occurs. For more information on redundant settings, see Reliability in Azure Container Apps.

  • Consider protecting Azure Container Apps from common exploits and vulnerabilities by using Web Application Firewall on Application Gateway. For more information, see Protect Azure Container Apps with Web Application Firewall on Application Gateway.

  • If your applications use legacy Spring Cloud Netflix components, consider replacing them with current alternatives, as shown in the following table:

    Legacy Current
    Spring Cloud Eureka Spring Cloud Service Registry
    Spring Cloud Netflix Zuul Spring Cloud Gateway
    Spring Cloud Netflix Archaius Spring Cloud Config Server
    Spring Cloud Netflix Ribbon Spring Cloud Load Balancer (client-side load balancer)
    Spring Cloud Hystrix Spring Cloud Circuit Breaker + Resilience4J
    Spring Cloud Netflix Turbine Micrometer + Prometheus