Tutorial: Build a Java Spring Boot web app with Azure App Service on Linux and Azure Cosmos DB

This tutorial walks you through the process of building, configuring, deploying, and scaling Java web apps on Azure. When you are finished, you will have a Spring Boot application storing data in Azure Cosmos DB running on Azure App Service on Linux.

Spring Boot application storing data in Azure Cosmos DB

In this tutorial, you learn how to:

  • Create a Cosmos DB database.
  • Connect a sample app to the database and test it locally
  • Deploy the sample app to Azure
  • Stream diagnostic logs from App Service
  • Add additional instances to scale out the sample app

If you don't have an Azure subscription, create a free account before you begin.

Prerequisites

Clone the sample TODO app and prepare the repo

This tutorial uses a sample TODO list app with a web UI that calls a Spring REST API backed by Spring Data Azure Cosmos DB. The code for the app is available on GitHub. To learn more about writing Java apps using Spring and Cosmos DB, see the Spring Boot Starter with the Azure Cosmos DB SQL API tutorial and the Spring Data Azure Cosmos DB quick start.

Run the following commands in your terminal to clone the sample repo and set up the sample app environment.

git clone --recurse-submodules https://github.com/Azure-Samples/e2e-java-experience-in-app-service-linux-part-2.git
cd e2e-java-experience-in-app-service-linux-part-2
yes | cp -rf .prep/* .

Create an Azure Cosmos DB

Follow these steps to create an Azure Cosmos DB database in your subscription. The TODO list app will connect to this database and store its data when running, persisting the application state no matter where you run the application.

  1. Login your Azure CLI, and optionally set your subscription if you have more than one connected to your login credentials.

    az login
    az account set -s <your-subscription-id>
    
  2. Create an Azure Resource Group, noting the resource group name.

    az group create -n <your-azure-group-name> \
        -l <your-resource-group-region>
    
  3. Create Azure Cosmos DB with the GlobalDocumentDB kind. The name of Cosmos DB must use only lower case letters. Note down the documentEndpoint field in the response from the command.

    az cosmosdb create --kind GlobalDocumentDB \
        -g <your-azure-group-name> \
        -n <your-azure-COSMOS-DB-name-in-lower-case-letters>
    
  4. Get your Azure Cosmos DB key to connect to the app. Keep the primaryMasterKey, documentEndpoint nearby as you'll need them in the next step.

    az cosmosdb list-keys -g <your-azure-group-name> -n <your-azure-COSMOSDB-name>
    

Configure the TODO app properties

Open a terminal on your computer. Copy the sample script file in the cloned repo so you can customize it for your Cosmos DB database you just created.

cd initial/spring-todo-app
cp set-env-variables-template.sh .scripts/set-env-variables.sh

Edit .scripts/set-env-variables.sh in your favorite editor and supply Azure Cosmos DB connection info. For the App Service Linux configuration, use the same region as before (your-resource-group-region) and resource group (your-azure-group-name) used when creating the Cosmos DB database. Choose a WEBAPP_NAME that is unique since it cannot duplicate any web app name in any Azure deployment.

export COSMOSDB_URI=<put-your-COSMOS-DB-documentEndpoint-URI-here>
export COSMOSDB_KEY=<put-your-COSMOS-DB-primaryMasterKey-here>
export COSMOSDB_DBNAME=<put-your-COSMOS-DB-name-here>

# App Service Linux Configuration
export RESOURCEGROUP_NAME=<put-your-resource-group-name-here>
export WEBAPP_NAME=<put-your-Webapp-name-here>
export REGION=<put-your-REGION-here>

Then run the script:

source .scripts/set-env-variables.sh

These environment variables are used in application.properties in the TODO list app. The fields in the properties file set up a default repository configuration for Spring Data:

azure.cosmosdb.uri=${COSMOSDB_URI}
azure.cosmosdb.key=${COSMOSDB_KEY}
azure.cosmosdb.database=${COSMOSDB_DBNAME}
@Repository
public interface TodoItemRepository extends DocumentDbRepository<TodoItem, String> {
}

Then the sample app uses the @Document annotation imported from com.microsoft.azure.spring.data.cosmosdb.core.mapping.Document to set up an entity type to be stored and managed by Cosmos DB:

@Document
public class TodoItem {
    private String id;
    private String description;
    private String owner;
    private boolean finished;

Run the sample app

Use Maven to run the sample.

mvn package spring-boot:run

The output should look like the following.

bash-3.2$ mvn package spring-boot:run
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Building spring-todo-app 2.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 


[INFO] SimpleUrlHandlerMapping - Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
[INFO] SimpleUrlHandlerMapping - Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
[INFO] WelcomePageHandlerMapping - Adding welcome page: class path resource [static/index.html]
2018-10-28 15:04:32.101  INFO 7673 --- [           main] c.m.azure.documentdb.DocumentClient      : Initializing DocumentClient with serviceEndpoint [https://sample-cosmos-db-westus.documents.azure.com:443/], ConnectionPolicy [ConnectionPolicy [requestTimeout=60, mediaRequestTimeout=300, connectionMode=Gateway, mediaReadMode=Buffered, maxPoolSize=800, idleConnectionTimeout=60, userAgentSuffix=;spring-data/2.0.6;098063be661ab767976bd5a2ec350e978faba99348207e8627375e8033277cb2, retryOptions=com.microsoft.azure.documentdb.RetryOptions@6b9fb84d, enableEndpointDiscovery=true, preferredLocations=null]], ConsistencyLevel [null]
[INFO] AnnotationMBeanExporter - Registering beans for JMX exposure on startup
[INFO] TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path ''
[INFO] TodoApplication - Started TodoApplication in 45.573 seconds (JVM running for 76.534)

You can access Spring TODO App locally using this link once the app is started: http://localhost:8080/.

Access Spring TODO app locally

If you see exceptions instead of the "Started TodoApplication" message, check that the bash script in the previous step exported the environment variables properly and that the values are correct for the Azure Cosmos DB database you created.

Configure Azure deployment

Open the pom.xml file in the initial/spring-boot-todo directory and add the following Maven Plugin for Azure App Service configuration.

<plugins> 

    <!--*************************************************-->
    <!-- Deploy to Java SE in App Service Linux           -->
    <!--*************************************************-->
       
    <plugin>
        <groupId>com.microsoft.azure</groupId>
        <artifactId>azure-webapp-maven-plugin</artifactId>
        <version>1.8.0</version>
        <configuration>
            <schemaVersion>v2</schemaVersion>

            <!-- Web App information -->
            <resourceGroup>${RESOURCEGROUP_NAME}</resourceGroup>
            <appName>${WEBAPP_NAME}</appName>
            <region>${REGION}</region>

            <!-- Java Runtime Stack for Web App on Linux-->
            <runtime>
                 <os>linux</os>
                 <javaVersion>jre8</javaVersion>
                 <webContainer>jre8</webContainer>
             </runtime>
             <deployment>
                 <resources>
                 <resource>
                     <directory>${project.basedir}/target</directory>
                     <includes>
                     <include>*.jar</include>
                     </includes>
                 </resource>
                 </resources>
             </deployment>

            <appSettings>
                <property>
                    <name>COSMOSDB_URI</name>
                    <value>${COSMOSDB_URI}</value>
                </property> 
                <property>
                    <name>COSMOSDB_KEY</name>
                    <value>${COSMOSDB_KEY}</value>
                </property>
                <property>
                    <name>COSMOSDB_DBNAME</name>
                    <value>${COSMOSDB_DBNAME}</value>
                </property>
                <property>
                    <name>JAVA_OPTS</name>
                    <value>-Dserver.port=80</value>
                </property>
            </appSettings>

        </configuration>
    </plugin>           
    ...
</plugins>

Deploy to App Service on Linux

Use the azure-webapp:deploy Maven goal to deploy the TODO app to Azure App Service on Linux.


# Deploy
bash-3.2$ mvn azure-webapp:deploy
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Building spring-todo-app 2.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- azure-webapp-maven-plugin:1.8.0:deploy (default-cli) @ spring-todo-app ---
[INFO] Target Web App doesn't exist. Creating a new one...
[INFO] Creating App Service Plan 'ServicePlanb6ba8178-5bbb-49e7'...
[INFO] Successfully created App Service Plan.
[INFO] Successfully created Web App.
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource to /home/test/e2e-java-experience-in-app-service-linux-part-2/initial/spring-todo-app/target/azure-webapp/spring-todo-app-61bb5207-6fb8-44c4-8230-c1c9e4c099f7
[INFO] Trying to deploy artifact to spring-todo-app...
[INFO] Renaming /home/test/e2e-java-experience-in-app-service-linux-part-2/initial/spring-todo-app/target/azure-webapp/spring-todo-app-61bb5207-6fb8-44c4-8230-c1c9e4c099f7/spring-todo-app-2.0-SNAPSHOT.jar to app.jar
[INFO] Deploying the zip package spring-todo-app-61bb5207-6fb8-44c4-8230-c1c9e4c099f7718326714198381983.zip...
[INFO] Successfully deployed the artifact to https://spring-todo-app.azurewebsites.net
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:19 min
[INFO] Finished at: 2019-11-06T15:32:03-07:00
[INFO] Final Memory: 50M/574M
[INFO] ------------------------------------------------------------------------

The output contains the URL to your deployed application (in this example, https://spring-todo-app.azurewebsites.net ). You can copy this URL into your web browser or run the following command in your Terminal window to load your app.

open https://spring-todo-app.azurewebsites.net

You should see the app running with the remote URL in the address bar:

Spring Boot application running with a remote URL

Stream diagnostic logs

You can access the console logs generated from inside the container. First, turn on container logging by running the following command in the Cloud Shell:

az webapp log config --name <app-name> --resource-group myResourceGroup --docker-container-logging filesystem

Once container logging is turned on, run the following command to see the log stream:

az webapp log tail --name <app-name> --resource-group myResourceGroup

If you don't see console logs immediately, check again in 30 seconds.

Note

You can also inspect the log files from the browser at https://<app-name>.scm.azurewebsites.net/api/logs/docker.

To stop log streaming at any time, type Ctrl+C.

Scale out the TODO App

Scale out the application by adding another worker:

az appservice plan update --number-of-workers 2 \
   --name ${WEBAPP_PLAN_NAME} \
   --resource-group <your-azure-group-name>

Clean up resources

If you don't need these resources for another tutorial (see Next steps), you can delete them by running the following command in the Cloud Shell:    

az group delete --name <your-azure-group-name>

Next steps

Azure for Java Developers Spring Boot, Spring Data for Cosmos DB, Azure Cosmos DB and App Service Linux.

Learn more about running Java apps on App Service on Linux in the developer guide.