Julien Dubois
Posted on November 28, 2019
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:
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.
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 theSPRING_PROFILES_ACTIVE
environment key. - Override the database configuration using environment variables for the
SPRING_DATASOURCE_URL
,SPRING_DATASOURCE_USERNAME
andSPRING_DATASOURCE_PASSWORD
keys.
This configuration should look like the screenshot below:
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>
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 calledazureWebAppPublishProfile
. 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'
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 theAzure Webapp Maven plugin
we detailed in the previous section, but this GitHub Action allows to better decouple the code (thepom.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.
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
September 4, 2019