The easy way to deploy a Spring Boot application to production on Azure

jdubois

Julien Dubois

Posted on November 28, 2019

The easy way to deploy a Spring Boot application to production on Azure

In this blog post, we are going to deploy a classical Spring Boot application to production on Azure, with a strong focus on ease-of-use, both from a developer and operations perspective.

Why "the easy way"?

While it is fun to use Kubernetes the hard way, if your goal is to deploy and host a Spring Boot application in production, your customer probably doesn't have the time and money to let you work like this.

We are aiming here at deploying and maintaining a production application with as little work as possible:

  • As a developer, our goal is just to git push to production and not worry about anything else.
  • As an ops engineer, our goal is to do the easiest setup possible, and not have any maintenance or scalability work.

The sample application

For this blog post we will use a fork of the famous Spring Petclinic. This is a well-known and well-documented sample Spring Boot application, and we will detail the choices that were made in order to deploy it easily.

There is nothing specific about this application, so if you use a Spring Boot application (or even better, a JHipster application!), you should be able to follow the next steps and be in the cloud very quickly.

Azure App Service overview

There are many ways to deploy a Spring Boot application to Azure. You can obviously use a virtual machine (VM): you'll need to set up everything manually, take care of the OS and JVM maintenance, handle HTTPS and scalability yourself... So while it looks easy at first sight, it's time consuming and the maintenance is going to be a big issue.

We are going to use Azure App Service, which is a Platform-as-a-Service solution. It supports different languages, as well as Docker images, so it can effectively host any kind of application. It is also very cost-efficient.

As a managed service, there is much less maintenance overhead than with a VM, and scalability is already included, which makes it a great way to host monolithic Spring Boot applications. If you have more complex needs, we recommend using Azure Spring Cloud, which shares many similar concepts, but which targets microservices architectures.

Jar or Docker?

Azure App Service supports both Jar deployments and Docker deployments, which are both well-documented and popular ways to deploy Spring Boot applications.

We recommend using Jar deployment here: both the OS and the JVM will be managed (and supported!) by Microsoft, which means you will have far less maintenance work to do. For example, if a security vulnerability is discovered in the JVM, it will be automatically patched without any manual intervention.

Azure App Service setup

First, we'll create an Azure resource group in which we will work:

  • Go to the Azure portal.
  • In the search box, look for "Resource groups".
  • Create a new resource group called spring-petclinic.

Then, create the Azure App Service instance:

  • In the Azure portal search box, look for "App Services".
  • Create a new Web App in the spring-petclinic resource group, using Java 11 on Linux, as in the screenshot below:

Creating App Service

MySQL setup

Like many Spring Boot applications, the Spring Petclinic uses the MySQL database: if you are using another database, like PostgreSQL, your setup should be similar.

Azure App Service has a feature called "MySQL in-app", that you can use to lower your hosting costs, as MySQL will run inside your Azure App Service instance. While this can be used in development, it comes with several important limitations and is not a production-grade database, so we are not going to use it here.

  • Go to the Azure portal.
  • In the search box, look for "Azure Database for MySQL".
  • Create a MySQL server (and be careful to select the correct pricing tier for your usage!).
  • Note your database name, your username and password, as we will need them later.

In your MySQL database, go to "Connection security", and select "Allow access to Azure services". You should also click on the "Add client IP" button to automatically add your current IP to the firewall rules, so you can access it from your current machine.

MySQL firewall rules

Environment variables

The Spring Petclinic is configured using properties files, which are located in the src/main/resources directory. One of them is called application-mysql.properties, which means it will be used when the mysql Spring Boot profile will be triggered.

In the Azure App Service we created above, select the Settings > Configuration menu on the left.

We need to configure two different settings here:

  • Set Spring Boot to use the mysql profile, using the SPRING_PROFILES_ACTIVE environment key.
  • Override the database configuration using environment variables for the SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME and SPRING_DATASOURCE_PASSWORD keys.

This configuration should look like the screenshot below:

Environment variables

As we are handling secrets here, another solution it to use Azure Key Vault. With Spring Boot, this can be configured using the Azure Key Vault Secrets Spring Boot Starter. This adds some complexity to the project, and isn't more secure than environment variables in our particular use-case (in the end, both become Spring Boot properties, and can be read from the code), so for just storing one secret this is outside of the scope of this "deploy the easy way" article.

Deploying using the Azure Webapp Maven plugin

Now that our App Service is configured, all we need to do is deploy our application. In this first solution, we are going to use the Azure Webapp Maven plugin. This is what most developers would use, as it's easily integrated inside their IDEs.

Inside your pom.xml file, add the following Maven plugin:

      <plugin>
        <groupId>com.microsoft.azure</groupId>
        <artifactId>azure-webapp-maven-plugin</artifactId>
        <version>1.8.0</version>
          <configuration>
            <schemaVersion>V2</schemaVersion>
            <resourceGroup>spring-petclinic</resourceGroup>
            <appName>jdubois-petclinic</appName>
            <region>westeurope</region>
            <pricingTier>B1</pricingTier>
            <runtime>
              <os>linux</os>
              <javaVersion>java11</javaVersion>
              <webContainer>java11</webContainer>
            </runtime>
            <deployment>
              <resources>
                <resource>
                  <directory>${project.basedir}/target</directory>
                  <includes>
                    <include>*.jar</include>
                  </includes>
                </resource>
              </resources>
            </deployment>
          </configuration>
      </plugin>
Enter fullscreen mode Exit fullscreen mode

Of course, you will need to configure the correct parameters for your resourceGroup, appName, region and pricingTier.

This solution is very easy to use for developers, but it has a few drawbacks:

  • Its configuration is stored inside the project's pom.xml, including configuration that should change depending on environments.
  • It requires a local build and a manual work for the developer.

Automating deployment with a GitHub Action

A newer alternative to the Azure Webapp Maven plugin is to use a GitHub Action.

You will need to authorize your GitHub Action to publish applications on Azure, here is how to do this:

  • In the Azure portal, select your App Service and in the overview panel, click on Get publish profile. You will download a .PublishSettings file.
  • In your GitHub project, go to Settings > Secrets and create a new secret called azureWebAppPublishProfile. Paste the content of the previous .PublishSettings file into that secret.

Then, add the following GitHub Action to your project. Create a file called .github/workflows/build-and-deploy.yml and paste the following content in it:

name: Build and deploy to Azure App Service

on:
  push:
    branches:
      - master

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Set up JDK 11
        uses: actions/setup-java@v1
        with:
          java-version: 11
      - name: Cache Maven archetypes
        uses: actions/cache@v1
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: |
            ${{ runner.os }}-maven-
      - name: Build with Maven
        run: mvn clean package
      - uses: azure/webapps-deploy@v1
        with:
          app-name: spring-petclinic
          publish-profile: ${{ secrets.azureWebAppPublishProfile }} # See https://github.com/Azure/actions-workflow-samples/tree/master/AppService
          package: '${{ github.workspace }}/target/*.jar'
Enter fullscreen mode Exit fullscreen mode

Here is a brief description of this GitHub Action:

  • It publishes an updated Azure App Service application as soon as code is pushed to the master branch. You can do a similar GitHub Action for other branches: you could have this setup for each project developer, or for each environment.
  • It checks the latest code and installs Java 11.
  • It uses the actions/cache GitHub Action to cache Maven archetypes: this considerably improves build times, so it is highly recommended.
  • It builds and tests the application using Maven.
  • It deploys the final application using the azure/webapps-deploy GitHub Action. This deployment could also have been made using the Azure Webapp Maven plugin we detailed in the previous section, but this GitHub Action allows to better decouple the code (the pom.xml doesn't have any specific Azure configuration or library), and it's also faster to execute.

Final thoughts

Our two goals are fulled reached:

  • Developers only need to git push to deploy their Spring Boot application, without even needing to know anything about Azure App Services.
  • Operations engineers had to do a minimal setup (creating the MySQL and App Service instances, and configuring 4 environment variables), but now the application can run in production without much maintenance. The OS and the JVM will be automatically patched and supported by Microsoft, and scalability is included.

In order to achieve those goals, we didn't have to modify any code in our Spring Boot application. Using GitHub Actions to deploy, all we needed to do is add a hidden file inside the .github repository.

If you want to have a closer look at the final application, my fork of Spring Petclinic is available here.

💖 💪 🙅 🚩
jdubois
Julien Dubois

Posted on November 28, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related