|
| 1 | +--- |
| 2 | +title: Deploy Serverless Java Apps with Quarkus on Azure Functions |
| 3 | +description: Deploy Serverless Java Apps with Quarkus on Azure Functions |
| 4 | +ms.author: edburns |
| 5 | +ms.service: azure-functions |
| 6 | +ms.topic: how-to |
| 7 | +ms.date: 01/10/2023 |
| 8 | +ms.devlang: java |
| 9 | +ms.custom: devx-track-java, devx-track-javaee, devx-track-javaee-quarkus-functions, devx-track-javaee-quarkus-functions |
| 10 | +--- |
| 11 | + |
| 12 | +# Deploy Serverless Java Apps with Quarkus on Azure Functions |
| 13 | + |
| 14 | +In this article, you'll develop, build, and deploy a serverless Java app with Quarkus on Azure Functions. This article uses Quarkus Funqy and its built-in support for Azure Functions HTTP trigger for Java. Using Quarkus with Azure Functions gives you the power of the Quarkus programming model with the scale and flexibility of Azure Functions. When you're finished, you'll run serverless [Quarkus](https://quarkus.io) applications on Azure Functions and continuing to monitor the application on Azure. |
| 15 | + |
| 16 | +## Prerequisites |
| 17 | + |
| 18 | +* [Azure CLI](/cli/azure/overview), installed on your own computer. |
| 19 | +* [An Azure Account](https://azure.microsoft.com/) |
| 20 | +* [Java JDK 17](/azure/developer/java/fundamentals/java-support-on-azure) with JAVA_HOME configured appropriately. This article was written with Java 17 in mind, but Azure functions and Quarkus support older versions of Java as well. |
| 21 | +* [Apache Maven 3.8.1+](https://maven.apache.org) |
| 22 | +[!INCLUDE [quickstarts-free-trial-note](../../includes/quickstarts-free-trial-note.md)] |
| 23 | + |
| 24 | +## A first look at the sample application |
| 25 | + |
| 26 | +Clone the sample code for this guide. The sample is on [GitHub](https://github.com/Azure-Samples/quarkus-azure). |
| 27 | + |
| 28 | +```bash |
| 29 | +git clone https://github.com/Azure-Samples/quarkus-azure |
| 30 | +``` |
| 31 | + |
| 32 | +Explore the sample function. Open the file *functions-quarkus/src/main/java/io/quarkus/GreetingFunction.java*. The `@Funq` annotation makes your method (e.g. `funqyHello`) a serverless function. Azure Functions Java has its own set of Azure-specific annotations, but these annotations are not necessary when using Quarkus on Azure Functions in a simple capacity as we're doing here. For more information on the Azure Functions Java annotations, see [Azure Functions Java developer guide](/azure/azure-functions/functions-reference-java). |
| 33 | + |
| 34 | +```java |
| 35 | +@Funq |
| 36 | +public String funqyHello() { |
| 37 | + return "hello funqy"; |
| 38 | +} |
| 39 | +``` |
| 40 | + |
| 41 | +Unless you specify otherwise, the function's name is taken to be same as the method name. You can also define the function name with a parameter to the annotation, as shown here. |
| 42 | + |
| 43 | +```java |
| 44 | +@Funq("alternateName") |
| 45 | +public String funqyHello() { |
| 46 | + return "hello funqy"; |
| 47 | +} |
| 48 | +``` |
| 49 | + |
| 50 | +The name is important: the name becomes a part of the REST URI to invoke the function, as shown later in the article. |
| 51 | + |
| 52 | +## Test the Serverless Function locally |
| 53 | + |
| 54 | +Use `mvn` to run `Quarkus Dev mode` on your local terminal. Running Quarkus in this way enables live reload with background compilation. When you modify your Java files and/or your resource files and refresh your browser, these changes will automatically take effect. |
| 55 | + |
| 56 | +A browser refresh triggers a scan of the workspace. If any changes are detected, the Java files are recompiled and the application is redeployed. Your redeployed application services the request. If there are any issues with compilation or deployment an error page will let you know. |
| 57 | + |
| 58 | +Replace `yourResourceGroupName` with a resource group name. Function app names must be globally unique across all of Azure. Resource group names must be globally unique within a subscription. This article achieves the necessary uniqueness by prepending the resource group name to the function name. For this reason, consider prepending some unique identifier to any names you create that must be unique. A useful technique is to use your initials followed by today's date in `mmdd` format. The resourceGroup is not necessary for this part of the instructions, but it's required later. For simplicity, the maven project requires the property be defined. |
| 59 | + |
| 60 | +1. Invoke Quarkus dev mode. |
| 61 | + |
| 62 | + ```bash |
| 63 | + cd functions-azure |
| 64 | + mvn -DskipTests -DresourceGroup=<yourResourceGroupName> quarkus:dev |
| 65 | + ``` |
| 66 | + |
| 67 | + The output should look like this. |
| 68 | + |
| 69 | + ```output |
| 70 | + ... |
| 71 | + --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ |
| 72 | + -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \ |
| 73 | + --\___\_\____/_/ |_/_/|_/_/|_|\____/___/ |
| 74 | + INFO [io.quarkus] (Quarkus Main Thread) quarkus-azure-function 1.0-SNAPSHOT on JVM (powered by Quarkus xx.xx.xx.) started in 1.290s. Listening on: http://localhost:8080 |
| 75 | + |
| 76 | + INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated. |
| 77 | + INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, funqy-http, smallrye-context-propagation, vertx] |
| 78 | + |
| 79 | + -- |
| 80 | + Tests paused |
| 81 | + Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options> |
| 82 | + ``` |
| 83 | + |
| 84 | +1. Access the function using the `CURL` command on your local terminal. |
| 85 | + |
| 86 | + ```bash |
| 87 | + curl localhost:8080/api/funqyHello |
| 88 | + ``` |
| 89 | + |
| 90 | + The output should look like this. |
| 91 | + |
| 92 | + ```output |
| 93 | + "hello funqy" |
| 94 | + ``` |
| 95 | + |
| 96 | +### Add Dependency injection to function |
| 97 | + |
| 98 | +Dependency injection in Quarkus is provided by the open standard technology Jakarta EE Contexts and Dependency Injection (CDI). For a high level overview on injection in general, and CDI in specific, see the [Jakarta EE tutorial](https://eclipse-ee4j.github.io/jakartaee-tutorial/#injection). |
| 99 | + |
| 100 | +1. Add a new function that uses dependency injection |
| 101 | + |
| 102 | + Create a *GreetingService.java* file in the *functions-quarkus/src/main/java/io/quarkus* directory. Make the source code of the file be the following. |
| 103 | + |
| 104 | + ```java |
| 105 | + package io.quarkus; |
| 106 | +
|
| 107 | + import javax.enterprise.context.ApplicationScoped; |
| 108 | +
|
| 109 | + @ApplicationScoped |
| 110 | + public class GreetingService { |
| 111 | +
|
| 112 | + public String greeting(String name) { |
| 113 | + return "Welcome to build Serverless Java with Quarkus on Azure Functions, " + name; |
| 114 | + } |
| 115 | + |
| 116 | + } |
| 117 | + ``` |
| 118 | + |
| 119 | + Save the file. |
| 120 | + |
| 121 | + `GreetingService` is an injectable bean that implements a `greeting()` method returning a string `Welcome...` message with a parameter `name`. |
| 122 | +
|
| 123 | +1. Open the existing the *functions-quarkus/src/main/java/io/quarkus/GreetingFunction.java* file. Replace the class with the below code to add a new field `gService` and method `greeting`. |
| 124 | +
|
| 125 | + ```java |
| 126 | + package io.quarkus; |
| 127 | + |
| 128 | + import javax.inject.Inject; |
| 129 | + import io.quarkus.funqy.Funq; |
| 130 | + |
| 131 | + public class GreetingFunction { |
| 132 | + |
| 133 | + @Inject |
| 134 | + GreetingService gService; |
| 135 | + |
| 136 | + @Funq |
| 137 | + public String greeting(String name) { |
| 138 | + return gService.greeting(name); |
| 139 | + } |
| 140 | + |
| 141 | + @Funq |
| 142 | + public String funqyHello() { |
| 143 | + return "hello funqy"; |
| 144 | + } |
| 145 | + |
| 146 | + } |
| 147 | + ``` |
| 148 | +
|
| 149 | + Save the file. |
| 150 | +
|
| 151 | +1. Access the new function `greeting` using the `CURL` command on your local terminal. |
| 152 | +
|
| 153 | + ```bash |
| 154 | + curl -d '"Dan"' -X POST localhost:8080/api/greeting |
| 155 | + ``` |
| 156 | +
|
| 157 | + The output should look like this. |
| 158 | +
|
| 159 | + ```output |
| 160 | + "Welcome to build Serverless Java with Quarkus on Azure Functions, Dan" |
| 161 | + ``` |
| 162 | +
|
| 163 | + > [!IMPORTANT] |
| 164 | + > `Live Coding` (also referred to as dev mode) allows you to run the app and make changes on the fly. Quarkus will automatically re-compile and reload the app when changes are made. This is a powerful and efficient style of developing that you'll use throughout the tutorial. |
| 165 | +
|
| 166 | + Before moving forward to the next step, stop Quarkus Dev Mode by pressing `CTRL-C`. |
| 167 | +
|
| 168 | +## Deploy the Serverless App to Azure Functions |
| 169 | +
|
| 170 | +1. If you haven't already, sign in to your Azure subscription by using the [az login](/cli/azure/reference-index) command and follow the on-screen directions. |
| 171 | +
|
| 172 | + ```azurecli |
| 173 | + az login |
| 174 | + ``` |
| 175 | +
|
| 176 | + > [!NOTE] |
| 177 | + > If you've multiple Azure tenants associated with your Azure credentials, you must specify which tenant you want to sign in to. You can do this with the `--tenant` option. For example, `az login --tenant contoso.onmicrosoft.com`. |
| 178 | + > Continue the process in the web browser. If no web browser is available or if the web browser fails to open, use device code flow with `az login --use-device-code`. |
| 179 | +
|
| 180 | + Once you've signed in successfully, the output on your local terminal should look similar to the following. |
| 181 | +
|
| 182 | + ```output |
| 183 | + xxxxxxx-xxxxx-xxxx-xxxxx-xxxxxxxxx 'Microsoft' |
| 184 | + [ |
| 185 | + { |
| 186 | + "cloudName": "AzureCloud", |
| 187 | + "homeTenantId": "xxxxxx-xxxx-xxxx-xxxx-xxxxxxx", |
| 188 | + "id": "xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx", |
| 189 | + "isDefault": true, |
| 190 | + "managedByTenants": [], |
| 191 | + "name": "Contoso account services", |
| 192 | + "state": "Enabled", |
| 193 | + "tenantId": "xxxxxxx-xxxx-xxxx-xxxxx-xxxxxxxxxx", |
| 194 | + "user": { |
| 195 | + |
| 196 | + "type": "user" |
| 197 | + } |
| 198 | + } |
| 199 | + ] |
| 200 | + ``` |
| 201 | +
|
| 202 | +1. Build and deploy the functions to Azure |
| 203 | +
|
| 204 | + The *pom.xml* you generated in the previous step uses the `azure-functions-maven-plugin`. Running `mvn install` generates config files and a staging directory required by the `azure-functions-maven-plugin`. For `yourResourceGroupName`, use the value you used previously. |
| 205 | +
|
| 206 | + ```bash |
| 207 | + mvn clean install -DskipTests -DtenantId=<your tenantId from shown previously> -DresourceGroup=<yourResourceGroupName> azure-functions:deploy |
| 208 | + ``` |
| 209 | +
|
| 210 | +1. During deployment, sign in to Azure. The `azure-functions-maven-plugin` is configured to prompt for Azure sign in each time the project is deployed. Examine the build output. During the build, you'll see output similar to the following. |
| 211 | +
|
| 212 | + ```output |
| 213 | + [INFO] Auth type: DEVICE_CODE |
| 214 | + To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code AXCWTLGMP to authenticate. |
| 215 | + ``` |
| 216 | +
|
| 217 | + Do as the output says and authenticate to Azure using the browser and provided device code. Many other authentication and configuration options are available. The complete reference documentation for `azure-functions-maven-plugin` is available at [Azure Functions: Configuration Details](https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details). |
| 218 | +
|
| 219 | +1. After authenticating, the build should continue and complete. The output should include `BUILD SUCCESS` near the end. |
| 220 | +
|
| 221 | + ```output |
| 222 | + Successfully deployed the artifact to https://quarkus-demo-123451234.azurewebsites.net |
| 223 | + ``` |
| 224 | +
|
| 225 | + You can also find the `URL` to trigger your function on Azure in the output log. |
| 226 | +
|
| 227 | + ```output |
| 228 | + [INFO] HTTP Trigger Urls: |
| 229 | + [INFO] quarkus : https://quarkus-azure-functions-http-archetype-20220629204040017.azurewebsites.net/api/{*path} |
| 230 | + ``` |
| 231 | +
|
| 232 | + It will take a while for the deployment to complete. In the meantime, let's explore Azure Functions in the portal. |
| 233 | +
|
| 234 | +## Access and Monitor the Serverless Function on Azure |
| 235 | +
|
| 236 | +Sign in to the Portal and ensure you've selected the same tenant and subscription used in the Azure CLI. You can visit the portal at [https://aka.ms/publicportal](https://aka.ms/publicportal). |
| 237 | +
|
| 238 | +1. Type `Function App` in the search bar at the top of the Azure portal and press Enter. Your function should be deployed and show up with the name `<yourResourceGroupName>-function-quarkus`. |
| 239 | +
|
| 240 | + :::image type="content" source="media/functions-create-first-quarkus/azure-function-app.png" alt-text="The function app in the portal"::: |
| 241 | +
|
| 242 | + Select the `function name`. you'll see the function app's detail information such as **Location**, **Subscription**, **URL**, **Metrics**, and **App Service Plan**. |
| 243 | +
|
| 244 | +1. In the detail page, select the `URL`. |
| 245 | +
|
| 246 | + :::image type="content" source="media/functions-create-first-quarkus/azure-function-app-detail.png" alt-text="The function app detail page in the portal"::: |
| 247 | +
|
| 248 | + Then, you'll see if your function is "up and running" now. |
| 249 | +
|
| 250 | + :::image type="content" source="media/functions-create-first-quarkus/azure-function-app-ready.png" alt-text="The function welcome page"::: |
| 251 | +
|
| 252 | +1. Invoke the `greeting` function using `CURL` command on your local terminal. |
| 253 | +
|
| 254 | + > [!IMPORTANT] |
| 255 | + > Replace `YOUR_HTTP_TRIGGER_URL` with your own function URL that you find in Azure portal or output. |
| 256 | +
|
| 257 | + ```bash |
| 258 | + curl -d '"Dan on Azure"' -X POST https://YOUR_HTTP_TRIGGER_URL/api/greeting |
| 259 | + ``` |
| 260 | +
|
| 261 | + The output should look similar to the following. |
| 262 | +
|
| 263 | + ```output |
| 264 | + "Welcome to build Serverless Java with Quarkus on Azure Functions, Dan on Azure" |
| 265 | + ``` |
| 266 | +
|
| 267 | + You can also access the other function (`funqyHello`). |
| 268 | +
|
| 269 | + ```bash |
| 270 | + curl https://YOUR_HTTP_TRIGGER_URL/api/funqyHello |
| 271 | + ``` |
| 272 | +
|
| 273 | + The output should be the same as you observed above. |
| 274 | +
|
| 275 | + ```output |
| 276 | + "hello funqy" |
| 277 | + ``` |
| 278 | +
|
| 279 | + If you want to exercise the basic metrics capability in the Azure portal, try invoking the function within a shell for loop, as shown here. |
| 280 | +
|
| 281 | + ```bash |
| 282 | + for i in {1..100}; do curl -d '"Dan on Azure"' -X POST https://YOUR_HTTP_TRIGGER_URL/api/greeting; done |
| 283 | + ``` |
| 284 | +
|
| 285 | + After a while, you'll see some metrics data in the portal, as shown next. |
| 286 | +
|
| 287 | + :::image type="content" source="media/functions-create-first-quarkus/portal-metrics.png" alt-text="Function metrics in the portal"::: |
| 288 | +
|
| 289 | + Now that you've opened your Azure function in the portal, here are some more features accessible from the portal. |
| 290 | +
|
| 291 | + * Monitor the performance of your Azure function. For more information, see [Monitoring Azure Functions](/azure/azure-functions/monitor-functions). |
| 292 | + * Explore telemetry. For more information, see [Analyze Azure Functions telemetry in Application Insights](/azure/azure-functions/analyze-telemetry-data). |
| 293 | + * Set up logging. For more information, see [Enable streaming execution logs in Azure Functions](/azure/azure-functions/streaming-logs). |
| 294 | +
|
| 295 | +## Clean up resources |
| 296 | +
|
| 297 | +If you don't need these resources, you can delete them by running the following command in the Cloud Shell or on your local terminal: |
| 298 | +
|
| 299 | +```azurecli |
| 300 | +az group delete --name <yourResourceGroupName> --yes |
| 301 | +``` |
| 302 | +
|
| 303 | +## Next steps |
| 304 | +
|
| 305 | +In this guide, you learned how to: |
| 306 | +> [!div class="checklist"] |
| 307 | +> |
| 308 | +> * Run Quarkus dev mode |
| 309 | +> * Deploy a Funqy app to Azure functions using the `azure-functions-maven-plugin` |
| 310 | +> * Examine the performance of the function in the portal |
| 311 | +
|
| 312 | +To learn more about Azure Functions and Quarkus, see the following articles and references. |
| 313 | +
|
| 314 | +* [Azure Functions Java developer guide](/azure/azure-functions/functions-reference-java) |
| 315 | +* [Quickstart: Create a Java function in Azure using Visual Studio Code](/azure/azure-functions/create-first-function-vs-code-java) |
| 316 | +* [Azure Functions documentation](/azure/azure-functions/) |
| 317 | +* [Quarkus guide to deploying on Azure](https://quarkus.io/guides/deploying-to-azure-cloud) |
0 commit comments