Click here to Skip to main content
15,789,776 members
Articles / Containers / Kubernetes

Deploying to Azure Arc via Azure Application Services Part 3: Deploying a Multi-cloud Azure App Service Web App

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
7 Apr 2022CPOL6 min read 3.5K   4  
In this article we learn how to deploy an Azure App Service web app written in Java to an Arc-hosted Kubernetes cluster hosted in another cloud service.

This article is a sponsored article. Articles such as these are intended to provide you with information on products and services that we consider useful and of value to developers

This article proceeds through the steps to deploy an Azure App Service web app written in Java to an Arc-hosted Kubernetes cluster hosted in another cloud service.

The article demonstrates how to:

  • Provision an app service Kubernetes environment
  • Deploy a Java web app to an Arc-enabled cluster on Google Cloud

It concludes by demonstrating that our Azure app is running on Google Cloud while being managed from Azure.

These instructions target PowerShell on Windows but can be recreated in Bash with little additional effort. They are also broken down to aid in understanding the process. However, they can be compiled into a singular, more concise script in production.


This demo uses:

  • Azure CLI
  • Java 11
  • Maven
  • An Azure subscription (free trials are available)

If you are not already familiar with Java and web apps in Azure, we recommend that you read through the Azure App Service documentation.

The first article of this series reminded us how to connect our Azure Arc to Kubernetes on Google Cloud. Before starting here, let’s run a few checks to ensure everything is as we left it. Remember to account for any naming changes you might have made.

First, confirm the presence of the resource group named arc-rg in your Azure subscription.

(Note that while in preview, resource groups for Azure Arc must be in either West Europe or East US.)

Then confirm registration of the Kubernetes providers:

az provider show -n Microsoft.Kubernetes --query registrationState -tsv

az provider show --namespace Microsoft.KubernetesConfiguration --query registrationState -o tsv

Next, confirm that the connected Azure Arc resource, k8s-gke, exists in the resource group.

Additionally, confirm that you have a kubeconfig entry to authenticate with the GKE cluster.

Check that the azure-arc is Active:

kubectl get namespace

Next, verify that the Azure Arc Kubernetes agents are deployed:

kubectl get pods -n azure-arc

They should all show as running.

Then validate the connection with the following command.:

az connectedk8s show --resource-group arc-rg --name k8s-gke

This should show the provisioningState property as Succeeded.

Finally, check that the connected Kubernetes cluster is a resource group in the Azure portal.

Image 1

Step 1: Provision an App Service Kubernetes Environment

You are free to use any names for SQL Server to suit your preference. (You will also need to set your Azure subscription ID.) However, for the sake of simplicity, this article uses the following names:

  • k8s-gke – Azure Arc resource
  • arc-rg – Azure resource group for Azure Arc
  • arc-app-service – Kubernetes App Service extension
  • arc-ns – App namespace
  • arc-app-custom-location – custom location

Log in to Azure

For deployment pipelines, it can be helpful to connect Kubernetes clusters to Azure Arc using service principles with limited-privilege role assignments. You can find instructions for this here.

For this demo, we log in to our Azure account:

az login
az account set -s "<SUBSCRIPTION_ID>"

Add or Update the Prerequisites for Custom Location

az provider register --namespace Microsoft.ExtendedLocation --wait
az extension add --upgrade -n customlocation

Enable the Feature on the Cluster

az connectedk8s enable-features -n k8s-gke -g arc-rg --features custom-locations

This also enables the cluster-connect feature for us.

Install the App Service Extension in Your Azure Arc-connected Cluster

az k8s-extension create -g "arc-rg" --name "arc-app-service" 
    --cluster-type connectedClusters -c "k8s-gke" `
    --extension-type 'Microsoft.Web.Appservice' --release-train stable --auto-upgrade-minor-version true `
    --scope cluster --release-namespace "arc-ns" `
    --configuration-settings "Microsoft.CustomLocation.ServiceAccount=default" `
    --configuration-settings "appsNamespace=arc-ns" `
    --configuration-settings "clusterName=arc-app-service" `
    --configuration-settings "keda.enabled=true" `
    --configuration-settings "buildService.storageClassName=standard" `
    --configuration-settings "buildService.storageAccessMode=ReadWriteOnce" `
    --configuration-settings "customConfigMap=arc-ns/kube-environment-config"

If we want Log Analytics enabled in production, we must add it now following the additional configuration shown here. We will not be able to do this later.

There are two parameters for persistent storage that need proper consideration. You can learn more about Kubernetes persistent volumes, including a breakdown of all available access modes on the storage resources provided by all major cloud service providers, in the official Kubernetes documentation. In this demo, we’re hosting our cluster in Google Cloud Engine (GCE), which provides GCEPersistentDisk. This supports the following PersistentVolume (PV) types for Kubernetes:

  • ReadWriteOnce
  • ReadOnlyMany

The AppService extension supports:

  • ReadWriteOnce
  • ReadWriteMany

Suppose we don’t explicitly set the AppService extension to ReadWriteOnce. In that case, it defaults to ReadWriteMany. There will be a mismatch between the PersistentVolumeClaim (PVC), the request for storage from the AppService extension, and the available PVs in GCE.

We also must configure the correct class name for the persistent storage on GCP.

Image 2

The command can take a few minutes. If you encounter any errors during this process, check the troubleshooting documentation.

When the command completes, navigate to the Kubernetes Azure Arc resource in Azure Portal and click Extensions in the sidebar. You should see the arc-app-service extension listed as Installed.

Image 3

Create the Custom Location

We must set up a custom location to enable the deployment of Azure Functions to an Arc-enabled Kubernetes cluster. We looked at these in the first article.

Get the id property of the App Service extension:

$extensionId=(az k8s-extension show --name arc-app-service --cluster-type connectedClusters -c k8s-gke -g arc-rg --query id -o tsv)

Get the id property of the Azure Arc-connected cluster:

$connectedClusterId=(az connectedk8s show -n k8s-gke -g arc-rg --query id -o tsv)

Use these values to create the custom location:

az customlocation create `
    --resource-group arc-rg `
    --name arc-app-custom-location `
    --host-resource-id $connectedClusterId `
    --namespace arc-ns `
    --cluster-extension-ids $extensionId

When this completes, validate it with the following command:

az customlocation show --resource-group arc-rg --name arc-app-custom-location --query privisioingState -o tsv

The output should read Succeeded. If not, wait a minute and run the command again.

Create the App Service Kubernetes Environment

Get the custom location id property:

$customLocationId=$(az customlocation show `
    --resource-group arc-rg `
    --name arc-app-custom-location `
    --query id `
    --output tsv)

Use this id to create the App Service Kubernetes environment:

az appservice kube create `
    --resource-group arc-rg `
    --name k8s-gke `
    --custom-location $customLocationId

Check the provisioning state is set to Succeeded:

az appservice kube show --resource-group arc-rg --name k8s-gke

Step 2: Create the Web App in Azure

Use the Azure Portal to create a new Web App with the following settings:

  • Resource group: arc-rg
  • Name: azure-arc-demo-java-app
  • Publish: Code
  • Runtime stack: Java 11
  • Java webserver stack: Tomcat 9.0

The only difference to how we usually make apps in Azure is the region. You must select the custom location instead of a regular region name.

Image 4

Step 3: Deploy an Azure Java Web App

We will adapt the Maven Hello World Java web app to display the host’s IP address and prove that it is running in Google Cloud.

Create the Java App

For this step, you can clone the completed code from this demo’s GitHub repository or complete the steps yourself:

mvn archetype:generate "-DgroupId=example.demo" "-DartifactId=helloworld" "-DarchetypeArtifactId=maven-archetype-webapp" "-Dversion=1.0-SNAPSHOT"

Then change the page to output the host’s IP own address:

    <% try (java.util.Scanner s=new java.util.Scanner(new"").openStream())) {
        out.println(s.useDelimiter(" \\A").next()); } catch (Exception ex) { ex.printStackTrace(); } %>

Deploying to Azure

Note: Usually, the next step for a Java Azure Web App would be to configure the Maven plugin for deployment. However, at the time of writing, Maven cannot see Java apps in custom locations as it can with those in standard regions. As a result, we won’t deploy with Maven. We will instead use the Azure CLI.

The next step is to package our web app in a Web Application Resource (WAR) file:

cd helloworld
mvn clean package

Now we can deploy it to our newly created Java web app in Azure:

az webapp deploy --name azure-arc-demo-java-app --resource-group arc-rg --src-path .\target\helloworld.war


We have provisioned an App Service Kubernetes Environment in Azure, hosted in Google Cloud, and successfully deployed a Java Azure Web App.

Image 5

When we visit the URL for our deployed app, it calls to retrieve its host’s IP address, which it then renders in the page output:

Image 6

When we perform a whois query on that IP address, we see the following:

Image 7

This is definitive proof that our Java Azure Web App is running in Google Cloud!

After the initial steps required to connect our Google Cloud Kubernetes cluster and configure it to host Azure App Services, creating and deploying new apps is the same as working with those native to Azure, regardless of whether we are deploying them from a pipeline or a local machine.

To learn how to manage, govern, and secure your Kubernetes clusters across on-premises, edge, and cloud environments with Azure Arc Preview, check out Azure webinar series Manage Kubernetes Anywhere with Azure Arc Preview.

This article is part of the series 'Deploying to Azure Arc via Azure Application Services View All


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Written By
Software Developer (Senior)
United Kingdom United Kingdom
Ben is the Principal Developer at a and .NET Foundation foundation member. He previously worked for over 9 years as a school teacher, teaching programming and Computer Science. He enjoys making complex topics accessible and practical for busy developers.

Comments and Discussions

-- There are no messages in this forum --