|
| 1 | +--- |
| 2 | +title: 'Tutorial: Linux Java app with Quarkus and PostgreSQL' |
| 3 | +description: Learn how to get a data-driven Linux Quarkus app working in Azure App Service, with connection to a PostgreSQL running in Azure. |
| 4 | +author: denvermb |
| 5 | +ms.author: dbrittain |
| 6 | +ms.devlang: java |
| 7 | +ms.topic: tutorial |
| 8 | +ms.date: 5/27/2022 |
| 9 | +ms.custom: mvc |
| 10 | +--- |
| 11 | + |
| 12 | +# Tutorial: Build a Quarkus web app with Azure App Service on Linux and PostgreSQL |
| 13 | + |
| 14 | +This tutorial walks you through the process of building, configuring, deploying, and scaling Java web apps on Azure. |
| 15 | +When you are finished, you will have a [Quarkus](https://quarkus.io) application storing data in [PostgreSQL](/azure/postgresql) database running on [Azure App Service on Linux](overview.md). |
| 16 | + |
| 17 | + |
| 18 | + |
| 19 | +In this tutorial, you learn how to: |
| 20 | + |
| 21 | +> [!div class="checklist"] |
| 22 | +> * Create a App Service on Azure |
| 23 | +> * Create a PostgreSQL database on Azure |
| 24 | +> * Deploy the sample app to Azure App Service |
| 25 | +> * Connect a sample app to the database |
| 26 | +> * Stream diagnostic logs from App Service |
| 27 | +> * Add additional instances to scale out the sample app |
| 28 | +
|
| 29 | +[!INCLUDE [quickstarts-free-trial-note](../../includes/quickstarts-free-trial-note.md)] |
| 30 | + |
| 31 | +## Prerequisites |
| 32 | + |
| 33 | +* [Azure CLI](/cli/azure/overview), installed on your own computer. |
| 34 | +* [Git](https://git-scm.com/) |
| 35 | +* [Java JDK](/azure/developer/java/fundamentals/java-support-on-azure) |
| 36 | +* [Maven](https://maven.apache.org) |
| 37 | + |
| 38 | +## Clone the sample app and prepare the repo |
| 39 | + |
| 40 | +This tutorial uses a sample Fruits list app with a web UI that calls a Quarkus REST API backed by [Azure Database for PostgreSQL](/azure/postgresql). The code for the app is available [on GitHub](https://github.com/quarkusio/quarkus-quickstarts/tree/main/hibernate-orm-panache-quickstart). To learn more about writing Java apps using Quarkus and PostgreSQL, see the [Quarkus Hibernate ORM with Panache Guide](https://quarkus.io/guides/hibernate-orm-panache) and the [Quarkus Datasource Guide](https://quarkus.io/guides/datasource). |
| 41 | + |
| 42 | + |
| 43 | +Run the following commands in your terminal to clone the sample repo and set up the sample app environment. |
| 44 | + |
| 45 | +```bash |
| 46 | +git clone https://github.com/quarkusio/quarkus-quickstarts |
| 47 | +cd quarkus-quickstarts/hibernate-orm-panache-quickstart |
| 48 | +``` |
| 49 | + |
| 50 | +## Create an App Service on Azure |
| 51 | + |
| 52 | +1. Sign in to your Azure CLI, and optionally set your subscription if you have more than one connected to your sign-in credentials. |
| 53 | + |
| 54 | + ```azurecli |
| 55 | + az login |
| 56 | + az account set -s <your-subscription-id> |
| 57 | + ``` |
| 58 | +
|
| 59 | +2. Create an Azure Resource Group, noting the resource group name (referred to with `$RESOURCE_GROUP` later on) |
| 60 | +
|
| 61 | + ```azurecli |
| 62 | + az group create \ |
| 63 | + --name <a-resource-group-name> \ |
| 64 | + --location <a-resource-group-region> |
| 65 | + ``` |
| 66 | +3. Create an App Service Plan. The App Service Plan is the compute container, it determines your cores, memory, price, and scale. |
| 67 | +
|
| 68 | + ```azurecli |
| 69 | + az appservice plan create \ |
| 70 | + --name "quarkus-tutorial-app-service-plan" \ |
| 71 | + --resource-group $RESOURCE_GROUP \ |
| 72 | + --sku B2 \ |
| 73 | + --is-linux |
| 74 | + ``` |
| 75 | +4. Create an app service within the App Service Plan. |
| 76 | +
|
| 77 | + ```azurecli |
| 78 | + WEBAPP_NAME=<a unique name> |
| 79 | + az webapp create \ |
| 80 | + --name $WEBAPP_NAME \ |
| 81 | + --resource-group $RESOURCE_GROUP \ |
| 82 | + --runtime "JAVA|11-java11" \ |
| 83 | + --plan "quarkus-tutorial-app-service-plan" |
| 84 | + ``` |
| 85 | +> [!IMPORTANT] |
| 86 | +> The `WEBAPP_NAME` must be **unique across all Azure**. A good pattern is to use a combination of your company name or initials of your name along with a good webapp name, for example `johndoe-quarkus-app`. |
| 87 | +
|
| 88 | +## Create an Azure PostgreSQL Database |
| 89 | +
|
| 90 | +Follow these steps to create an Azure PostgreSQL database in your subscription. The Quarkus Fruits app will connect to this database and store its data when running, persisting the application state no matter where you run the application. |
| 91 | +
|
| 92 | +1. Create the database service. |
| 93 | +
|
| 94 | + ```azurecli |
| 95 | + DB_SERVER_NAME='msdocs-quarkus-postgres-webapp-db' |
| 96 | + ADMIN_USERNAME='demoadmin' |
| 97 | + ADMIN_PASSWORD='<admin-password>' |
| 98 | +
|
| 99 | + az postgres server create \ |
| 100 | + --resource-group $RESOURCE_GROUP \ |
| 101 | + --name $DB_SERVER_NAME \ |
| 102 | + --location $LOCATION \ |
| 103 | + --admin-user $DB_USERNAME \ |
| 104 | + --admin-password $DB_PASSWORD \ |
| 105 | + --sku-name GP_Gen5_2 |
| 106 | + ``` |
| 107 | +
|
| 108 | + The following parameters are used in the above Azure CLI command: |
| 109 | +
|
| 110 | + * *resource-group* → Use the same resource group name in which you created the web app, for example `msdocs-quarkus-postgres-webapp-rg`. |
| 111 | + * *name* → The PostgreSQL database server name. This name must be **unique across all Azure** (the server endpoint becomes `https://<name>.postgres.database.azure.com`). Allowed characters are `A`-`Z`, `0`-`9`, and `-`. A good pattern is to use a combination of your company name and server identifier. (`msdocs-quarkus-postgres-webapp-db`) |
| 112 | + * *location* → Use the same location used for the web app. |
| 113 | + * *admin-user* → Username for the administrator account. It can't be `azure_superuser`, `admin`, `administrator`, `root`, `guest`, or `public`. For example, `demoadmin` is okay. |
| 114 | + * *admin-password* Password of the administrator user. It must contain 8 to 128 characters from three of the following categories: English uppercase letters, English lowercase letters, numbers, and non-alphanumeric characters. |
| 115 | +
|
| 116 | + > [!IMPORTANT] |
| 117 | + > When creating usernames or passwords **do not** use the `$` character. Later you create environment variables with these values where the `$` character has special meaning within the Linux container used to run Java apps. |
| 118 | +
|
| 119 | + * *public-access* → `None` which sets the server in public access mode with no firewall rules. Rules will be created in a later step. |
| 120 | + * *sku-name* → The name of the pricing tier and compute configuration, for example `GP_Gen5_2`. For more information, see [Azure Database for PostgreSQL pricing](https://azure.microsoft.com/pricing/details/postgresql/server/). |
| 121 | +
|
| 122 | +2. Configure the firewall rules on your server by using the [az postgres server firewall-rule create](/cli/azure/postgres/flexible-server/firewall-rule) command to give your local environment access to connect to the server. |
| 123 | +
|
| 124 | + ```azurecli |
| 125 | + az postgres server firewall-rule create \ |
| 126 | + --resource-group $RESOURCE_GROUP_NAME \ |
| 127 | + --server-name $DB_SERVER_NAME \ |
| 128 | + --name AllowMyIP \ |
| 129 | + --start-ip-address <your IP> \ |
| 130 | + --end-ip-address <your IP> |
| 131 | + ``` |
| 132 | +
|
| 133 | + Also, once your application runs on App Service, you'll need to give it access as well. run the following command to allow access to the database from services within Azure: |
| 134 | +
|
| 135 | + ```azurecli |
| 136 | + az postgres server firewall-rule create \ |
| 137 | + --resource-group $RESOURCE_GROUP_NAME \ |
| 138 | + --server-name $DB_SERVER_NAME \ |
| 139 | + --name AllowAllWindowsAzureIps \ |
| 140 | + --start-ip-address 0.0.0.0 \ |
| 141 | + --end-ip-address 0.0.0.0 |
| 142 | + ``` |
| 143 | +3. Create a database named `fruits` within the Postgres service with this command: |
| 144 | +
|
| 145 | + ```azurecli |
| 146 | + az postgres db create \ |
| 147 | + --resource-group $RESOURCE_GROUP \ |
| 148 | + --server-name $DB_SERVER_NAME \ |
| 149 | + --name fruits |
| 150 | + ``` |
| 151 | +
|
| 152 | +## Configure the Quarkus app properties |
| 153 | +
|
| 154 | +Quarkus configuration is located in the `src/main/resources/application.properties` file. Open this file in your editor, and observe several default properties. The properties prefixed with `%prod` are only used when the application is built and deployed, for example when deployed to Azure App Service. When the application runs locally, `%prod` properties are ignored. Similarly, `%dev` properties are used in Quarkus' Live Coding / Dev mode, and `%test` properties are used during continuous testing. |
| 155 | +
|
| 156 | +Delete the existing content in `application.properties` and replace with the following to configure our database for dev, test, and production modes: |
| 157 | +
|
| 158 | +```properties |
| 159 | +quarkus.package.type=uber-jar |
| 160 | +%dev.quarkus.datasource.db-kind=h2 |
| 161 | +%dev.quarkus.datasource.jdbc.url=jdbc:h2:mem:fruits |
| 162 | +
|
| 163 | +%test.quarkus.datasource.db-kind=h2 |
| 164 | +%test.quarkus.datasource.jdbc.url=jdbc:h2:mem:fruits |
| 165 | +
|
| 166 | +%prod.quarkus.datasource.db-kind=postgresql |
| 167 | +%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://${DBHOST}.postgres.database.azure.com:5432/${DBNAME}?user=${DBUSER}@${DBHOST}&password=${DBPASS} |
| 168 | +%prod.quarkus.hibernate-orm.sql-load-script=import.sql |
| 169 | +
|
| 170 | +quarkus.hibernate-orm.database.generation=drop-and-create |
| 171 | +``` |
| 172 | + |
| 173 | +> [!IMPORTANT] |
| 174 | +> Be sure to keep the dollar signs and braces intact when copying and pasting the above for the variables `${DBHOST}`, `${DBNAME}`, `${DBUSER}`, and `${DBPASS}`. We'll set the actual values later in our environment so that we don't expose them hard-coded in the properties file, and so that we can change them without having to re-deploy the app. |
| 175 | +
|
| 176 | +## Run the sample app locally |
| 177 | + |
| 178 | +Use Maven to run the sample. |
| 179 | + |
| 180 | +```bash |
| 181 | +mvn quarkus:dev |
| 182 | +``` |
| 183 | + |
| 184 | +This will build the app, run its unit tests, and then start the application in developer live coding. You should see: |
| 185 | + |
| 186 | +```output |
| 187 | +__ ____ __ _____ ___ __ ____ ______ |
| 188 | + --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ |
| 189 | + -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \ |
| 190 | +--\___\_\____/_/ |_/_/|_/_/|_|\____/___/ |
| 191 | +INFO [io.quarkus] (Quarkus Main Thread) hibernate-orm-panache-quickstart 1.0.0-SNAPSHOT on JVM (powered by Quarkus x.x.x.Final) started in x.xxxs. Listening on: http://localhost:8080 |
| 192 | +
|
| 193 | +INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated. |
| 194 | +INFO [io.quarkus] (Quarkus Main Thread) Installed features: [agroal, cdi, hibernate-orm, hibernate-orm-panache, jdbc-h2, jdbc-postgresql, narayana-jta, resteasy-reactive, resteasy-reactive-jackson, smallrye-context-propagation, vertx] |
| 195 | +``` |
| 196 | + |
| 197 | +You can access Quarkus app locally by typing the `w` character into the console, or using this link once the app is started: `http://localhost:8080/`. |
| 198 | + |
| 199 | + |
| 200 | + |
| 201 | +If you see exceptions in the output, double-check that the configuration values for `%dev` are correct. |
| 202 | + |
| 203 | +> [!TIP] |
| 204 | +> You can enable continuous testing by typing `r` into the terminal. This will continously run tests as you develop the application. You can also use Quarkus' *Live Coding* to see changes to your Java or `pom.xml` immediately. Simlply edit code and reload the browser. |
| 205 | +
|
| 206 | +When you're done testing locally, shut down the application with `CTRL-C` or type `q` in the terminal. |
| 207 | + |
| 208 | +## Configure App Service for Database |
| 209 | + |
| 210 | +Our Quarkus app is expecting various environment variables to configure the database. Add these to the App Service environment with the following command: |
| 211 | + |
| 212 | +```azurecli |
| 213 | +az webapp config appsettings set \ |
| 214 | + -g $RESOURCE_GROUP \ |
| 215 | + -n $WEBAPP_NAME \ |
| 216 | + --settings \ |
| 217 | + 'DBHOST=$DB_SERVER_NAME' \ |
| 218 | + 'DBNAME=fruits' \ |
| 219 | + 'DBUSER=$ADMIN_USERNAME' \ |
| 220 | + 'DBPASS=$ADMIN_PASSWORD' \ |
| 221 | + 'PORT=8080' \ |
| 222 | + 'WEBSITES_PORT=8080' |
| 223 | +``` |
| 224 | +> [!NOTE] |
| 225 | +> The use of single quotes (`'`) to surround the settings is required if your password has special characters. |
| 226 | +
|
| 227 | +Be sure to replace the values for `$RESOURCE_GROUP`, `$WEBAPP_NAME`, `$DB_SERVER_NAME`, `$ADMIN_USERNAME`, and `$ADMIN_PASSWORD` with the relevant values from previous steps. |
| 228 | + |
| 229 | +## Deploy to App Service on Linux |
| 230 | + |
| 231 | +Build the production JAR file using the following command: |
| 232 | + |
| 233 | +```azurecli |
| 234 | +mvn clean package |
| 235 | +``` |
| 236 | + |
| 237 | +The final result will be a JAR file in the `target/` subfolder. |
| 238 | + |
| 239 | +To deploy applications to Azure App Service, developers can use the [Maven Plugin for App Service](/learn/modules/publish-web-app-with-maven-plugin-for-azure-app-service/), [VSCode Extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azureappservice), or the Azure CLI to deploy apps. Use the following command to deploy our app to the App Service: |
| 240 | + |
| 241 | +```azurecli |
| 242 | +az webapp deploy \ |
| 243 | + --resource-group $RESOURCE_GROUP \ |
| 244 | + --name $WEBAPP_NAME \ |
| 245 | + --src-path target/*.jar --type jar |
| 246 | +``` |
| 247 | + |
| 248 | +You can then access the application using the following command: |
| 249 | + |
| 250 | +```azurecli |
| 251 | +az webapp browse \ |
| 252 | + --resource-group $RESOURCE_GROUP \ |
| 253 | + --name $WEBAPP_NAME |
| 254 | +``` |
| 255 | + |
| 256 | +> [!TIP] |
| 257 | +> You can also manually open the location in your browser at `http://<webapp-name>.azurewebsites.net`. It may take a minute or so to upload the app and restart the App Service. |
| 258 | +
|
| 259 | +You should see the app running with the remote URL in the address bar: |
| 260 | + |
| 261 | + |
| 262 | + |
| 263 | +If you see errors, use the following section to access the log file from the running app: |
| 264 | + |
| 265 | +## Stream diagnostic logs |
| 266 | + |
| 267 | +[!INCLUDE [Access diagnostic logs](../../includes/app-service-web-logs-access-no-h.md)] |
| 268 | + |
| 269 | +## Scale out the app |
| 270 | + |
| 271 | +Scale out the application by adding another worker: |
| 272 | + |
| 273 | +```azurecli |
| 274 | +az appservice plan update --number-of-workers 2 \ |
| 275 | + --name quarkus-tutorial-app-service-plan \ |
| 276 | + --resource-group $RESOURCE_GROUP |
| 277 | +``` |
| 278 | + |
| 279 | +## Clean up resources |
| 280 | + |
| 281 | +If you don't need these resources for another tutorial (see [Next steps](#next-steps)), you can delete them by running the following command in the Cloud Shell or on your local terminal: |
| 282 | +```azurecli |
| 283 | +az group delete --name $RESOURCE_GROUP --yes |
| 284 | +``` |
| 285 | + |
| 286 | +## Next steps |
| 287 | + |
| 288 | +[Azure for Java Developers](/java/azure/) |
| 289 | +[Quarkus](https://quarkus.io), |
| 290 | +[Getting Started with Quarkus](https://quarkus.io/get-started/), |
| 291 | +and |
| 292 | +[App Service Linux](overview.md). |
| 293 | + |
| 294 | +Learn more about running Java apps on App Service on Linux in the developer guide. |
| 295 | + |
| 296 | +> [!div class="nextstepaction"] |
| 297 | +> [Java in App Service Linux dev guide](configure-language-java.md?pivots=platform-linux) |
0 commit comments