Using Azure Pipelines to build, test and deploy a Spring Boot and Angular application (3/7)
Tags: spring, angular, azure, java
Published: 2019-05-27 21:52:10

---
title: Using Azure Pipelines to build, test and deploy a Spring Boot and Angular application (3/7)
published: true
description: In this series of blog posts, we are going to deploy a full-stack application to Azure, and learn how to set up many components efficiently, and in a cost-conscious way.
tags: spring, angular, azure, java
series: "Spring and Angular applications on Azure"
---
This blog post is part of a series on "deploying a Spring Boot and Angular application on Azure", here is the full list of posts:

- [Creating a Spring Boot and Angular application for Azure (1/7)](https://dev.to/jdubois/creating-a-spring-boot-and-angular-application-for-azure-1-7-2mb8)
- [Creating and configuring Azure Web App and MySQL to host a Spring Boot application (2/7)](https://dev.to/jdubois/creating-and-configuring-azure-web-app-and-mysql-to-host-a-spring-boot-application-2-7-1n13)
- Using Azure Pipelines to build, test and deploy a Spring Boot and Angular application (3/7)
- [Using Azure Application Insights with Spring Boot (4/7)](https://dev.to/azure/using-azure-application-insights-with-spring-boot-4-7-263i)
- [Using Azure Application Insights with Angular (5/7)](https://dev.to/azure/using-azure-application-insights-with-angular-5-7-4kej)
- [Configuring Azure CDN to boost Angular performance (6/7)](https://dev.to/azure/configuring-azure-cdn-to-boost-angular-performance-6-7-5ebe)
- [Configuring Azure Redis Cache to boost Spring Boot performance (7/7)](https://dev.to/azure/configuring-azure-redis-cache-to-boost-spring-boot-performance-7-7-52dl)

## Deploying a Spring Boot Application to Azure

There are several ways to deploy a Spring Boot application to Azure. One of the easiest way is to use the [Maven Plugin for Azure App Service](https://docs.microsoft.com/en-us/java/api/overview/azure/maven/azure-webapp-maven-plugin/readme?view=azure-java-stable&WT.mc_id=devto-blog-judubois). For our use-case, we want to go beyond the simple "Hello, world" application, and thus we are going to set up a full CI/CD (Continuous Integration/Continuous Deployment) solution using [Azure Pipelines](https://azure.microsoft.com/en-us/services/devops/pipelines/?WT.mc_id=devto-blog-judubois).

As always, we are budget-conscious here: Azure Pipelines provides a generous free tier which should be largely enough for us, so we shouldn't pay anything.

## Creating an azure-pipelines.yml file

In order to build and test our application with Azure Pipelines, we will need an `azure-pipelines.yml` file at the root of our project.

With JHipster, we're in luck, we just need to run `jhipster ci-cd` and answer a couple of questions to have a very complete Azure Pipelines configuration.

You can check the generated file on [this commit](https://github.com/jdubois/spring-on-azure/commit/9c53cd911001eee2a77daaf43f5f2398cd5c281f).

This pipeline will build and test the application (both the Spring Boot back-end and the Angular front-end), so it is a "Continuous Integration" pipeline. If you need more informations on Azure Pipelines tasks, you should refer to the [Azure Pipelines Documentation](https://docs.microsoft.com/en-us/azure/devops/pipelines/?view=azure-devops&WT.mc_id=devto-blog-judubois). Creating a simple Maven build is very easy, then doing more complex configurations like we do with JHipster might require a bit more time.

## Deploying automatically with Azure Pipelines to Azure Web App

In the previous section, we created an `azure-pipelines.yml` file: we are going to add a new task to it, in order to publish a production build, once all the tests have passed. As a result, it will not do only "Continuous Integration" anymore, but full "Continuous Deployment".

Open the `azure-pipelines.yml` file, and add at the end of it:

```
      - script: ./mvnw package -Pprod -DskipTests
        displayName: 'BUILD: creating production build'
      - task: CopyFiles@2
        inputs:
          SourceFolder: 'target'
          Contents: '*.jar'
          TargetFolder: '$(Build.ArtifactStagingDirectory)'
      - task: PublishBuildArtifacts@1
        inputs:
          pathtoPublish: '$(Build.ArtifactStagingDirectory)'
          artifactName: bugtracker
```

We are using 3 tasks in fact:

- One for doing a production build with JHipster. Please note that here we are skipping the tests are they are supposed to have passed before.
- Another one to copy the generated file JAR file to a directory where artifacts are being stored.
- And a last one to take that artifact and publish it.

This will automatically publish an artefact of your production build in Azure Pipelines.

__WARNING__ As Azure Web App uses an artefact which should be named `app.jar`, we're going to have to name our artefact correctly. The easiest way to do it, is to create it directly with the correct name, using the `finalName` attribute in your `pom.xml` :

```
    <build>
        <finalName>app</finalName>
        ...
    </build>
```

You can check the changes we just made to set up "Continuous Deployment" on [this commit](https://github.com/jdubois/spring-on-azure/commit/1bf7e3325aefb95c328b47150256a716217c7d04).

## Push the application to GitHub and set up Azure Pipelines

If you haven't done it yet, push your application to GitHub: if you don't want your application to be public, remember that GitHub provides free unlimited private repositories.

Once your application is on GitHub, go to the [GitHub marketplace](https://github.com/marketplace) to install and setup Azure Pipelines.

You can then log in to [Azure Devops](https://dev.azure.com/?WT.mc_id=devto-blog-judubois) to set up your Azure Pipelines:

- Create a new project.
- On the left-hand menu, select "Pipelines > Builds" and create a "new pipeline".
- Select "GitHub", and choose the GitHub project you have just created in the steps above.
- As we have created an `azure-pipelines.yml` file in the previous section, it will be automatically picked up, so you just need to "Run" it (using the button on the top right) to watch your application being built by Azure Pipelines.

As this build is a "full stack" build, it will compile, package and test all your Spring Boot and Angular code. As you can imagine, this is a rather complex, and this should take a bit more than 5 minutes to complete.

![](https://thepracticaldev.s3.amazonaws.com/i/q27e3nh7d72rnwmzgsm1.png)

## Deploy the application to Azure Web App

Once Azure Pipelines has built your application a first time, it will have published an artefact of the project. A new "Release" button will appear on the top right corner: click on it to create a new release.

You will see there your published artefact, and will be able to add new "stages" to it, in order to deploy it to production automatically.

Create a new "stage" and choose "Deploy a Java App to Azure App Service". Once this stage is created, open it and:

- Give it a meaningful name
- Connect it to your Azure subscription: you will need to click on the "Authorize" button and follow an authorization wizard
- Change the application type to "Web App on Linux" as this is what we created in the previous blog post
- Select your application service name

![](https://thepracticaldev.s3.amazonaws.com/i/rcmgox3wf7fpd10kf0zb.png)

Then, you need to modify the 2 tasks configured with this stage:

- Delete the first task, called "Deploy WAR to Azure App Service", as we are not deploying a WAR.
- Enable the second task, called "Deploy JAR to Azure App Service".

You can now go to the "Pipelines > Releases" and click on the "Create release" button. This should take the previously generated artefact (made by the `azure-pipelines.yml`), and deploy it automatically to your Azure Web App instance.

You can now connect to your application, and use it in production. As this is a JHipster application, here are a few tips to remember:

- There are 2 accounts by default, `admin` (with password `admin`), and `user` (with password `user`)
- The database schema is managed using [Liquibase](https://www.liquibase.org/), so when the application starts it automatically update the database schema. That schema was created in the previous blog post, using MySQL Workbench.
- If you ran the application in developement on your local computer, JHipster filled up your database with some dummy data using [faker.js](https://github.com/marak/Faker.js/). In production mode, as you are supposed to use some real data, your database will not have this data by default.

![](https://thepracticaldev.s3.amazonaws.com/i/5qd6s9271qoyq2z526xw.png)

Now, each time our build passes, our application will be automatically deployed to production, where it will be automatically managed by Azure Web Apps. No more production issues, just "git push" and you're done!

## Start-up time considerations, and budgets

You might have noticed that the application is a bit slow to start-up, it takes a bit more than 1 minute. Our worst-case scenario was 100 seconds, so it should be up under 2 minutes, but still that's a lot of time!

We have two culprits here: JHipster and the hardware. We can indeed make JHipster start in about one-third of that time, through various tunings (mostly disabling features like Liquibase). The performance gain can be important as here we are at the limit of the JVM memory, so the garbage collector is working hard, and removing a few features will help it a lot.

Then, the hardware selected isn't very good, as we wanted to be budget-conscious, and selected a "B1" box: it is free for the first month, and then very inexpensive (about $30 per month). This is why our memory is too limited, and also why our CPU is limited. Azure counts CPU power in "ACU", which means Azure Compute Units, and a B1 box as only 100 ACUs.

Testing a more powerful instance is surprisingly easy: in your Azure Web App, select "Scale up", and choose a "P2V2" instance. The upgrade is done on the fly! On this new hardware, which has 420 ACUs (so more than 4 times the compute power of a "B1"), start-up time is now only 15 seconds. Of course, you can scale down at any time and come back to the "B1" instance.