Migrate Spring Boot applications to Azure Kubernetes Service
This guide describes what you should be aware of when you want to migrate an existing Spring Boot application to run on Azure Kubernetes Service (AKS).
Pre-migration
To ensure a successful migration, before you start, complete the assessment and inventory steps described in the following sections.
Validate that the supported Java version works correctly
We recommend using a supported version of Java when running a Spring Boot application on AKS. Confirm that your application runs correctly using that supported version.
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
Determine whether and how the file system is used
Any usage of the file system by your Spring Boot application will require reconfiguration or, in rare cases, architectural changes. 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 mount Azure Storage shares as persistent volumes. For more information, see Dynamically create and use a persistent volume with Azure Files in Azure Kubernetes Service.
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 Kubernetes Service (AKS). Azure Kubernetes 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.
To execute scheduled jobs on your AKS cluster, define Kubernetes CronJobs as needed. For more information, see Running Automated Tasks with a CronJob.
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 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 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.
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.
Review your database properties
If your application uses a database, review the database properties in your application.properties file to make sure your Spring Boot application can still access the database after you migrate to AKS. If your database is on-premise, you'll need to either migrate it to the cloud, or establish connectivity to your on-premise database.
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). You will need to reconfigure these APM agents to be included in a Dockerfile or Jib configuration, or to use the Application Insights in-process Java agent.
Identify Zipkin dependencies
Determine whether your application has explicit dependencies on Zipkin. Look for dependencies on the io.zipkin.java
group in your Maven or Gradle dependencies.
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 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.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).
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.
Identity providers
Identify all identity providers and all Spring Boot applications that require authentication and/or authorization. For information on how identity providers may be configured, consult the following:
- For OAuth or OAuth2 Spring Security configuration, see Spring Security.
- For Auth0 Spring Security configuration, see the Auth0 Spring Security documentation.
- For PingFederate Spring Security configuration, see the Auth0 PingFederate instructions.
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.
In-place testing
Before you create container images, migrate your application to the JDK and Spring Boot version that you intend to use on AKS. Test your application thoroughly to ensure compatibility and performance.
Migration
Provision Azure Container Registry and Azure Kubernetes Service
Use the following commands to create a container registry and an Azure Kubernetes cluster with a Service Principal that has the Reader role on the registry. Be sure to choose the appropriate network model for your cluster's networking requirements.
az group create -g $resourceGroup -l eastus
az acr create -g $resourceGroup -n $acrName --sku Standard
az aks create -g $resourceGroup -n $aksName --attach-acr $acrName --network-plugin azure
Create a Docker image for Spring Boot
To create a Dockerfile, you'll need the following prerequisites:
- A supported JDK.
- Your JVM runtime options.
- A way to pass in environment variables (if applicable).
You can then do the steps described in the following sections, where applicable. You can use the Spring Boot Container Quickstart repo as a starting point for your Dockerfile and your Spring Boot application.
Configure Azure Key Vault Provider for Secrets Store CSI Driver
Create an Azure KeyVault and populate all the necessary secrets. For more information, see Quickstart: Set and retrieve a secret from Azure Key Vault using Azure CLI. Then, configure the Azure Key Vault Provider for Secrets Store CSI Driver to make those secrets accessible to pods.
You'll also need to update the startup script used to bootstrap your Spring Boot application. This script must import the certificates into the keystore used by Spring Boot before starting the application.
Build and push the Docker image to Azure Container Registry
After you've created the Dockerfile, you'll need to build the Docker image and publish it to your Azure container registry.
If you used our Spring Boot Container Quickstart GitHub repo, the process of building and pushing your image to your Azure container registry would be the equivalent of invoking the following three commands.
In these examples, the MY_ACR
environment variable holds the name of your Azure container registry and the MY_APP_NAME
variable holds the name of the web application you want to use on your Azure container registry.
Build the deployment file:
mvn package
Log into your Azure container registry:
az acr login -n ${MY_ACR}
Build and push the image:
az acr build -t ${MY_ACR}.azurecr.io/${MY_APP_NAME} .
Alternatively, you can use Docker CLI to first build and test the image locally, as shown in the following commands. This approach can simplify testing and refining the image before initial deployment to ACR. However, it requires you to install the Docker CLI and ensure the Docker daemon is running.
Build the image:
docker build -t ${MY_ACR}.azurecr.io/${MY_APP_NAME}
Run the image locally:
docker run -it -p 8080:8080 ${MY_ACR}.azurecr.io/${MY_APP_NAME}
You can now access your application at http://localhost:8080
.
Log into your Azure container registry:
az acr login -n ${MY_ACR}
Push the image to your Azure container registry:
docker push ${MY_ACR}.azurecr.io/${MY_APP_NAME}
For more in-depth information on building and storing container images in Azure, see the Learn module Build and store container images with Azure Container Registry.
If you used our Spring Boot Container Quickstart GitHub repo, you can also include a custom keystore that will be added to your JVM upon startup. This addition will occur if you put the keystore file at /opt/spring-boot/mycert.crt. You can do so by adding the file directly to the Dockerfile, or by using the Azure Key Vault Provider for Secrets Store CSI Driver, as mentioned previously.
If you used our Spring Boot Container Quickstart GitHub repo, you can also enable Application Insights by setting the APPLICATIONINSIGHTS_CONNECTION_STRING
environment variable in your Kubernetes deployment file (the value of the environment variable should look InstrumentationKey=00000000-0000-0000-0000-000000000000
). For more information, see Java codeless application monitoring Azure Monitor Application Insights.
If you don't require any customization of your Docker image, you could alternatively explore the use of the Maven Jib plugin or deploy to AKS. For more information, see Deploy Spring Boot Application to the Azure Kubernetes Service.
Provision a public IP address
If your application is to be accessible from outside your internal or virtual network(s), you'll need a public static IP address. You should provision this IP address inside your cluster's node resource group, as shown in the following example:
nodeResourceGroup=$(az aks show -g $resourceGroup -n $aksName --query 'nodeResourceGroup' -o tsv)
publicIp=$(az network public-ip create -g $nodeResourceGroup -n applicationIp --sku Standard --allocation-method Static --query 'publicIp.ipAddress' -o tsv)
echo "Your public IP address is ${publicIp}."
Deploy to AKS
Create and apply your Kubernetes YAML file(s). For more information, see Quickstart: Deploy an Azure Kubernetes Service cluster using the Azure CLI. If you're creating an external load balancer (whether for your application or for an ingress controller), be sure to provide the IP address provisioned in the previous section as the LoadBalancerIP
.
Include externalized parameters as environment variables. For more information, see Define Environment Variables for a Container.
Be sure to include memory and CPU settings when creating your deployment YAML so your containers are properly sized.
Ensure console logging and configure diagnostic settings
Configure your logging so that all applications log to the console and not to files.
After an application is deployed to Azure Kubernetes Service, you can see the logs by using kubectl
.
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.
Migrate and enable the identity provider
If any of the Spring Boot 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 guidance, 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.
Configure persistent storage
If your application requires non-volatile storage, configure one or more Persistent Volumes.
Migrate scheduled jobs
To execute scheduled jobs on your AKS cluster, define Kubernetes CronJobs as needed. For more information, see Running Automated Tasks with a CronJob.
Post-migration
Now that you've migrated your application to AKS, 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
Consider adding a DNS name to the IP address allocated to your ingress controller or application load balancer. For more information, see Create an ingress controller with a static public IP address in AKS.
Consider adding HELM charts for your application. A helm chart allows you to parameterize your application deployment for use and customization by a more diverse set of customers.
Design and implement a DevOps strategy. In order to maintain reliability while increasing your development velocity, consider automating deployments and testing with Azure Pipelines. For more information, see Build and deploy to AKS.
Enable Azure Monitoring for the cluster to allow the collection of container logs, track usage, and so on.
Consider exposing application-specific metrics via Prometheus. Prometheus is an open-source metrics framework broadly adopted in the Kubernetes community. You can configure Prometheus Metrics scraping in Azure Monitor instead of hosting your own Prometheus server to enable metrics aggregation from your applications and automated response to or escalation of aberrant conditions.
Design and implement a business continuity and disaster recovery strategy. For mission-critical applications, consider a multi-region deployment architecture.
Review the Kubernetes Version Support policy. It's your responsibility to keep updating your AKS cluster to ensure it's always running a supported version.
Have all team members responsible for cluster administration and application development review the pertinent AKS best practices.
Make sure your deployment file specifies how rolling updates are done. For more information, see Rolling Update Deployment in the Kubernetes documentation.
Set up auto scaling to deal with peak time loads. For more information, see Automatically scale a cluster to meet application demands on AKS.
Consider monitoring the code cache size and adding the parameters
-XX:InitialCodeCacheSize
and-XX:ReservedCodeCacheSize
to theJAVA_OPTS
variable in the Dockerfile to further optimize performance.
Feedback
Indsend og få vist feedback om