Quickstart: Deploy your first Java Native Image application to Azure Spring Apps

Note

The Basic, Standard, and Enterprise plans will be deprecated starting from mid-March, 2025, with a 3 year retirement period. We recommend transitioning to Azure Container Apps. For more information, see the Azure Spring Apps retirement announcement.

The Standard consumption and dedicated plan will be deprecated starting September 30, 2024, with a complete shutdown after six months. We recommend transitioning to Azure Container Apps. For more information, see Migrate Azure Spring Apps Standard consumption and dedicated plan to Azure Container Apps.

This article applies to: ❌ Basic/Standard ✔️ Enterprise

This quickstart shows how to deploy a Spring Boot application to Azure Spring Apps as a Native Image.

Native Image capability enables you to compile Java applications to standalone executables, known as Native Images. These executables can provide significant benefits, including faster startup times and lower runtime memory overhead compared to a traditional JVM (Java Virtual Machine).

The sample project is the Spring Petclinic application. The following screenshot shows the application:

Screenshot of a Spring Petclinic application in Azure Spring Apps.

1. Prerequisites

2. Prepare the Spring Petclinic project

Use the following steps to clone and run the app locally.

  1. Use the following command to clone the Spring Petclinic project from GitHub:

    git clone https://github.com/Azure-Samples/spring-petclinic.git
    
  2. Use the following command to build the Spring Petclinic project:

    cd spring-petclinic
    ./mvnw clean package -DskipTests -Pnative package
    
  3. Use the following command to run the Spring Petclinic application by using Maven:

    java -jar target/spring-petclinic-3.1.0-SNAPSHOT.jar
    
  4. Go to http://localhost:8080 in your browser to access the Spring Petclinic application.

3. Prepare the cloud environment

The main resource required to run Spring Petclinic application is an Azure Spring Apps instance. This section provides the steps to create the resource.

3.1. Provide names for each resource

Create variables to hold the resource names by using the following commands. Be sure to replace the placeholders with your own values.

export RESOURCE_GROUP=<resource-group-name>
export LOCATION=<location>
export AZURE_SPRING_APPS_NAME=<Azure-Spring-Apps-service-instance-name>
export NATIVE_BUILDER=native-builder
export JAR_APP_NAME=jar-app
export NATIVE_APP_NAME=native-app
export JAR_PATH=target/spring-petclinic-3.1.0-SNAPSHOT.jar

3.2. Create a new resource group

Use the following steps to create a new resource group:

  1. Use the following command to sign in to the Azure CLI:

    az login
    
  2. Use the following command to set the default location:

    az configure --defaults location=${LOCATION}
    
  3. Use the following command to list all available subscriptions to determine the subscription ID to use:

    az account list --output table
    
  4. Use the following command to set the default subscription:

    az account set --subscription <subscription-ID>
    
  5. Use the following command to create a resource group:

    az group create --resource-group ${RESOURCE_GROUP}
    
  6. Use the following command to set the newly created resource group as the default resource group:

    az configure --defaults group=${RESOURCE_GROUP}
    

3.3. Create an Azure Spring Apps instance

Azure Spring Apps is used to host the Spring Petclinic app. Use the following steps to create an Azure Spring Apps instance and two applications inside it:

  1. Use the following command to create an Azure Spring Apps service instance. A native image build requires 16 Gi of memory during image build, so configure the build pool size as S7.

    az spring create \
        --name ${AZURE_SPRING_APPS_NAME} \
        --sku enterprise \
        --build-pool-size S7
    
  2. Create a builder-native.json file in the current directory and then add the following content:

    {
       "stack": {
         "id": "io.buildpacks.stacks.jammy",
         "version": "tiny"
       },
       "buildpackGroups": [
         {
           "name": "default",
           "buildpacks": [
             {
               "id": "tanzu-buildpacks/java-native-image"
             }
           ]
         }
       ]
     }  
    
  3. Use the following command to create a custom builder to build the Native Image application:

    az spring build-service builder create \
        --service ${AZURE_SPRING_APPS_NAME} \
        --name ${NATIVE_BUILDER} \
        --builder-file builder-native.json
    
  4. Use the following command to create an application in the Azure Spring Apps instance in which to deploy the Spring Petclinic application as a JAR file. Configure the memory limit to 1 Gi.

    az spring app create \
        --service ${AZURE_SPRING_APPS_NAME} \
        --name ${JAR_APP_NAME} \
        --cpu 1 \
        --memory 1Gi \
        --assign-endpoint true
    
  5. Use the following command to create an application in the Azure Spring Apps instance in which to deploy the Spring Petclinic application as a Native Image:

    az spring app create \
        --service ${AZURE_SPRING_APPS_NAME} \
        --name ${NATIVE_APP_NAME} \
        --cpu 1 \
        --memory 1Gi \
        --assign-endpoint true
    

4. Deploy the app to Azure Spring Apps

Now that the cloud environment is prepared, the applications are ready to deploy.

Use the following command to deploy the Spring Petclinic application as a JAR file:

az spring app deploy \
    --service ${AZURE_SPRING_APPS_NAME} \
    --name ${JAR_APP_NAME} \
    --artifact-path ${JAR_PATH} \
    --build-env BP_JVM_VERSION=17

Use the following command to deploy the Spring Petclinic application as a Native Image:

az spring app deploy \
    --service ${AZURE_SPRING_APPS_NAME} \
    --name ${NATIVE_APP_NAME} \
    --builder ${NATIVE_BUILDER} \
    --build-cpu 8 \
    --build-memory 16Gi \
    --artifact-path ${JAR_PATH} \
    --build-env BP_JVM_VERSION=17 BP_NATIVE_IMAGE=true

5. Validate Native Image App

Now you can access the deployed Native Image app to see whether it works. Use the following steps to validate:

  1. After the deployment has completed, you can run the following command to get the app URL:

    az spring app show \
        --service ${AZURE_SPRING_APPS_NAME} \
        --name ${NATIVE_APP_NAME} \
        --output table
    

    You can access the app with the URL shown in the output as Public Url. The page should appear as you saw it o localhost.

  2. Use the following command to check the app's log to investigate any deployment issue:

    az spring app logs \
        --service ${AZURE_SPRING_APPS_NAME} \
        --name ${NATIVE_APP_NAME}
    

6. Compare performance for JAR and Native Image

The following sections describe how to compare the performance between JAR and Native Image deployment.

Server startup time

Use the following command to check the app's log Started PetClinicApplication in XXX seconds to get the server startup time for a JAR app:

az spring app logs \
    --service ${AZURE_SPRING_APPS_NAME} \
    --name ${JAR_APP_NAME}

The server startup time is around 25 s for a JAR app.

Use the following command to check the app's log to get the server startup time for a Native Image app:

az spring app logs \
    --service ${AZURE_SPRING_APPS_NAME} \
    --name ${NATIVE_APP_NAME}

The server startup time is less than 0.5 s for a Native Image app.

Memory usage

Use the following command to scale down the memory size to 512 Mi for a Native Image app:

az spring app scale \
    --service ${AZURE_SPRING_APPS_NAME} \
    --name ${NATIVE_APP_NAME} \
    --memory 512Mi

The command output should show that the Native Image app started successfully.

Use the following command to scale down the memory size to 512 Mi for the JAR app:

az spring app scale \
    --service ${AZURE_SPRING_APPS_NAME} \
    --name ${JAR_APP_NAME} \
    --memory 512Mi

The command output should show that the JAR app failed to start due to insufficient memory. The output message should be similar to the following example: Terminating due to java.lang.OutOfMemoryError: Java heap space.

The following figure shows the optimized memory usage for the Native Image deployment for a constant workload of 400 requests per second into the Petclinic application. The memory usage is about 1/5th of the memory consumed by its equivalent JAR deployment.

Screenshot of the optimized memory usage of a Native Image deployment in Azure Spring Apps.

Native Images offer quicker startup times and reduced runtime memory overhead when compared to the conventional Java Virtual Machine (JVM).

7. Clean up resources

If you plan to continue working with subsequent quickstarts and tutorials, you might want to leave these resources in place. When you no longer need the resources, delete them by deleting the resource group. Use the following command to delete the resource group:

az group delete --name ${RESOURCE_GROUP}

8. Next steps

For more information, see the following articles: