Thorntail as Azure App Service

Thomas Porocnik
5 min readJun 14, 2020

Recently I stumbled across Azure App Service. Basically this is a service that allows you to run your legacy web application code without fiddling much with infrastructure.

App Service basics

Currently the service supports:

  • ASP.NET Core
  • Node.js
  • PHP
  • Python
  • Java
  • Ruby
  • Docker

In the case of Java the simplest thing is to provide an executable jar. It’s that easy: Deploy a jar! As always there are some hidden pitfalls, but later on more about it.

Thorntail

Thorntail (formerly known as Wildfly swarm) is the lightweight brother of Wildfly. Thorntail supports the Microprofile standard and its a very productive approach to implement modern applications. Similar to Spring Boot it is deployed as a single uber-jar. This makes it an ideal candidate for trying out App Service. I know there is even a younger offspring of the application server family from Redhat, the increasingly popular Quarkus. But Quarkus doesn’t use the uber-jar approach by default, which has in general his advantages, but for our test use-case it may make things more complicated.

The sample application

The application used for the small test just consists of a Maven based project with a simple Jax-Rs annotated resource class, which produces a plain-text “Hello world!” message (you can find the complete code at Github).

@Path("/")
public class HelloWorldResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String helloWorld() {
return "Hello world!";
}
}

Now you need only to register the Jax-Rs context. This can be done with a initializer class:

@ApplicationPath("/hello")
public class HelloWorldApplication extends Application {
}

To have a static welcome page add a simple index.html to the webapp folder of the project.

The more interesting part comes with the pom.xml file. First you need the parts handling Thorntail (general stuff omitted):

...
<properties>
...
<!-- only 1.8 supported for App Service currently -->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!-- define thorntail version -->
<version.thorntail>2.7.0.Final</version.thorntail>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.thorntail</groupId>
<artifactId>bom-all</artifactId>
<version>${version.thorntail}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>io.thorntail</groupId>
<artifactId>thorntail-maven-plugin</artifactId>
<version>${version.thorntail}</version>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>io.thorntail</groupId>
<artifactId>jaxrs</artifactId>
</dependency>
</dependencies>

To build the artifacts you should now run Maven as usual:

mvn clean package

If you want to test it locally, run

java -jar -Dswarm.http.port=80 target/sample-thorntail.jar

Deploying to Azure

First of all you need an Azure account. This is not very complicated. Just register for a free subscribtion. This will basically allow you to play with Azure for one year.

Azure App Service monitoring

As usually for cloud environments you can configure a lot directly in the web-portal. This is also true for App Service. With a few clicks you can specify your Application - e.g. select the language (e.g Java), the OS (Linux vs. Windows) and so on. Now I thought I can upload somewhere directly the existing jar. But that seems not to be directly supported.

To deploy the code to App Service there are several options available (see more in the documentation). For our case it is the simplest way to use Azure WebApp Maven plugin. For this plugin you have to set some properties in the pom.xml. One of these is the resource group.

The resource group is a term used in Azure to define a logical group of dependent resources. So you can name them e.g. after your application in combination with a specific environment: “sample-app-dev”.

Because I created the resource group while clicking around in the Azure web-console I just had to refer it in the pom.xml later on (But I guess it would be created automatically if its not already existing). By the way, I deleted the first App Service app which I had created in the web-console later on. The deployment process via Maven will create it again from scratch.

Beside the resource group you must specify in addition:

  • App name (must be a unique name)
  • Region (Azure region e.g. “westeurope”)
  • Pricing tier (e.g. “P1V2”)
  • Java version (only JRE 8 supported currently)
  • Os (e.g. “linux”)

Additionally you have to define the jar which should be deployed and you can set some Java parameters which your app may need. So add the following lines to the plugins section in the pom.xml:

<plugin>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-webapp-maven-plugin</artifactId>
<version>1.9.1</version>
<configuration>
<schemaVersion>V2</schemaVersion>
<authType>azure_cli</authType>
<resourceGroup>sample-dev</resourceGroup>
<!-- unique name needed -->
<appName>app-name</appName>
<region>westeurope</region>
<pricingTier>P1V2</pricingTier>
<runtime>
<os>linux</os>
<javaVersion>jre8</javaVersion>
</runtime>
<appSettings>
<property>
<name>JAVA_OPTS</name>
<value>-Dswarm.http.port=80</value>
<value>-Dswarm.bind.address=0.0.0.0</value>
</property>
</appSettings>
<deployment>
<resources>
<resource>
<directory>${project.basedir}/target</directory>
<includes>
<include>*.jar</include>
</includes>
</resource>
</resources>
</deployment>

<!-- This is to make sure the jar file can be released at the server side -->
<stopAppDuringDeployment>true</stopAppDuringDeployment> </configuration>
</plugin>

With the following command you can deploy now your app to Azure:

mvn azure-webapp:deploy

Here it gets now a little bit tricky…

Dealing with some problems

If no specific authentication type is defined, the plugin will use the MAVEN_PLUGIN flow, which opens a browser window, where you can login with your Azure account. This works, but later on the plugin tells me:

No available subscription found in current account

After searching around on the internet I found out, that this is obviously a bug. The workaround is to use a different authentication method.

So I switched the method to AZURE_CLI. For this you have to download and install the Azure CLI. Now you can type:

az login

which again opens a browser window, where you can login with your credentials. After this the login method returns and prints some informations about your account in Json format.

Now I tried again to deploy with the Maven plugin.

Now it was telling me:

No executable jar found in target folder

But there was one! After debugging the plugin code, I saw that the code is testing for an executable jar via:

JarInputStream.getManifest()

This is only working, if the MANIFEST.MF is the first entry in the jar. Thorntail is ignoring this. On the other side you can consider this behaviour also as an existing JDK bug.

As a workaround I tried to manually add the entries (first one the META-INF/MANIFEST.MF) to the jar with 7zip, which took me a while to find out, that 7zip is constantly reordering the entries. So I gave up and did the same with built-in Windows zip functionality and this time it worked :-)

After the jar was fixed I could deploy it to Azure.

With calling following url (if you don’t spent money for your own domain name) you can see now your Thorntail app running on Azure App Service:

https://app-name.azurewebsites.net/

See also

Code at GitHub

App Service documentation

Azure Maven Plugin documentation

--

--

Thomas Porocnik

Software Architect. Trying to find out, why software is hard.