Blog Post

Apps on Azure Blog
10 MIN READ

App Service on Kubernetes with Azure Arc

Hanli_Ren's avatar
Hanli_Ren
Icon for Microsoft rankMicrosoft
Nov 03, 2021

We are happy to introduce this Preview feature that allows App Service running on Kubernetes or anywhere with Azure Arc.

 

Azure Arc allows you to deploy Azure application services such as Azure App Service, Functions, Logic Apps, Event Grid, and API Management anywhere, on-premises, edge locations, or any other cloud provider. This is great if you are building and running cloud-native applications on Azure PaaS services and want them to run outside of Azure without rearchitecting them.

 

In this blog, we will demonstrate an example of how to setup an App Service running on AKS from scratch.

 

Main reference documents used by this blog are:
- Set up Azure Arc for App Service, Functions, and Logic Apps 
- Quickstart: Create a web app on Azure Arc 

 

The complete steps can be separated into 4 parts:

  1. Part 1: Prepare the AKS and Azure Arc environment
  2. Part 2: Create Azure App Service in Kubernetes cluster
  3. Part 3: Deploy Application Code
  4. Part 4: Basic methods that can help you do the monitoring and troubleshooting

 

Part 1: Prepare the AKS and Azure Arc environment

In this part, I will only list all the bash commands that used to create AKS, Azure Arc, customer location, etc. These can be a quick reference when you need to create these resources from scratch.


More detailed explanations and command usage details can be found in https://docs.microsoft.com/en-us/azure/app-service/manage-create-arc-environment?tabs=bash 

 

The following Bash commands can be executed inside Azure Cloud Shell.

You can also install Azure CLI (version >= 2.26.0) in your local machine and run the Bash commands locally. 

Note: usually Linux OS by default has bash installed. For Windows OS, you may consider using WSL or Cygwin.

 

Install Azure CLI extensions

Because these CLI commands are not part of the core CLI set, we need to add them with the following commands.

 

az extension add --upgrade --yes --name connectedk8s
az extension add --upgrade --yes --name k8s-extension
az extension add --upgrade --yes --name customlocation
az provider register --namespace Microsoft.ExtendedLocation --wait
az provider register --namespace Microsoft.KubernetesConfiguration --wait
az provider register --namespace Microsoft.Kubernetes --wait
az provider register --namespace Microsoft.Web --wait
az extension remove --name appservice-kube
az extension add --yes --source "https://aka.ms/appsvc/appservice_kube-latest-py2.py3-none-any.whl"

 

 

Create a connected cluster

We will use this new created AKS cluster to deploy your App Service. If you already has an existing ASK cluster, then you can skip this step and continue to "Connect the cluster to Azure Arc" step.

 

aksClusterGroupName="<Define your AKS Resource Group name>" # Name of resource group for the AKS cluster
aksName="${aksClusterGroupName}-aks" # Name of the AKS cluster
resourceLocation="<Define your preferred location>"  # "eastus" or "westeurope" (in Preview stage,  only these two locations are supported now)
	
az group create -g $aksClusterGroupName -l $resourceLocation
az aks create --resource-group $aksClusterGroupName --name $aksName --enable-aad --generate-ssh-keys
infra_rg=$(az aks show --resource-group $aksClusterGroupName --name $aksName --output tsv --query nodeResourceGroup)
az network public-ip create --resource-group $infra_rg --name MyPublicIP --sku STANDARD
staticIp=$(az network public-ip show --resource-group $infra_rg --name MyPublicIP --output tsv --query ipAddress)
	
az aks get-credentials --resource-group $aksClusterGroupName --name $aksName --admin
kubectl get ns
	

 

 

Connect the AKS cluster to Azure Arc

Connect the cluster you created to Azure Arc.

 

groupName="<Define your Azure Arc Group name>" # Name of resource group for your Azure Arc resource
az group create -g $groupName -l $resourceLocation
	
clusterName="${groupName}-cluster" # Name of the connected cluster resource
az connectedk8s connect --resource-group $groupName --name $clusterName
az connectedk8s show --resource-group $groupName --name $clusterName

 

 

Create a Log Analytics workspace

While a Log Analytic workspace is not required to run App Service in Azure Arc, it's how developers can get application logs for their apps that are running in the Azure Arc-enabled Kubernetes cluster.

 

workspaceName="$groupName-workspace" # Name of the Log Analytics workspace

az monitor log-analytics workspace create \
	    --resource-group $groupName \
	    --workspace-name $workspaceName
	
logAnalyticsWorkspaceId=$(az monitor log-analytics workspace show \
	    --resource-group $groupName \
	    --workspace-name $workspaceName \
	    --query customerId \
	    --output tsv)
	
logAnalyticsWorkspaceIdEnc=$(printf %s $logAnalyticsWorkspaceId | base64 -w0) # Needed for the next step
	
logAnalyticsKey=$(az monitor log-analytics workspace get-shared-keys \
	    --resource-group $groupName \
	    --workspace-name $workspaceName \
	    --query primarySharedKey \
	    --output tsv)
	
logAnalyticsKeyEnc=$(printf %s $logAnalyticsKey | base64 -w0) # Needed for the next step

 

 

Install the App Service extension

Install the require App Service extension in the Azure Arc.

 

extensionName="appservice-ext" # Name of the App Service extension
namespace="appservice-ns" # Namespace in your cluster to install the extension and provision resources
kubeEnvironmentName="<Define your AppService Kubernetes Environment Name>" # Name of the App Service Kubernetes environment resource
	
az k8s-extension create \
   --resource-group $groupName \
   --name $extensionName \
   --cluster-type connectedClusters \
   --cluster-name $clusterName \
   --extension-type 'Microsoft.Web.Appservice' \
   --release-train stable \
   --auto-upgrade-minor-version true \
   --scope cluster \
   --release-namespace $namespace \
   --configuration-settings "Microsoft.CustomLocation.ServiceAccount=default" \
   --configuration-settings "appsNamespace=${namespace}" \
   --configuration-settings "clusterName=${kubeEnvironmentName}" \
   --configuration-settings "loadBalancerIp=${staticIp}" \
   --configuration-settings "keda.enabled=true" \
   --configuration-settings "buildService.storageClassName=default" \
   --configuration-settings "buildService.storageAccessMode=ReadWriteOnce" \
   --configuration-settings "customConfigMap=${namespace}/kube-environment-config" \
   --configuration-settings "envoy.annotations.service.beta.kubernetes.io/azure-load-balancer-resource-group=${aksClusterGroupName}" \
   --configuration-settings "logProcessor.appLogs.destination=log-analytics" \
   --configuration-protected-settings "logProcessor.appLogs.logAnalyticsConfig.customerId=${logAnalyticsWorkspaceIdEnc}" \
   --configuration-protected-settings "logProcessor.appLogs.logAnalyticsConfig.sharedKey=${logAnalyticsKeyEnc}"
	
extensionId=$(az k8s-extension show \
	    --cluster-type connectedClusters \
	    --cluster-name $clusterName \
	    --resource-group $groupName \
	    --name $extensionName \
	    --query id \
	    --output tsv)
	
az resource wait --ids $extensionId --custom "properties.installState!='Pending'" --api-version "2020-07-01-preview"
	
kubectl get pods -n $namespace

 

 

Create a custom location

Create your custom location in Azure, it will be used to assign the App Service Kubernetes environment.

 

customLocationName="<Define your custom location name>" # Name of the custom location
	
connectedClusterId=$(az connectedk8s show --resource-group $groupName --name $clusterName --query id --output tsv)
	
az customlocation create \
  --resource-group $groupName \
  --name $customLocationName \
  --host-resource-id $connectedClusterId \
  --namespace $namespace \
  --cluster-extension-ids $extensionId
	
az customlocation show --resource-group $groupName --name $customLocationName
	
customLocationId=$(az customlocation show \
  --resource-group $groupName \
  --name $customLocationName \
  --query id \
  --output tsv)

 

Record your customLocationId, which will be used when you create your App Service in the later step.

 

echo $customLocationId

 

You will get result like this:

/subscriptions/<subscript_id>/resourcegroups/<resource-group-name>/providers/microsoft.extendedlocation/customlocations/<customLocationName>

 

Create the App Service Kubernetes environment

The App Service Kubernetes environment resource is required before apps may be created. It enables configuration common to apps in the custom location, such as the default DNS suffix.

 

az appservice kube create \
  --resource-group $groupName \
  --name $kubeEnvironmentName \
  --custom-location $customLocationId \
  --static-ip $staticIp
	
az appservice kube show --resource-group $groupName --name $kubeEnvironmentName

 

 

Part 2: Create Azure App Service in Kubernetes cluster

We can use either Azure CLI or Azure Portal to create App Service in the Kubernetes cluster.

Option 1: Use Azure CLI command to create App Service in your custom location

Create App Service Plan:

 

az appservice plan create -g <Define your App Service Resource Group name> -n <Define your App Service Plan name> \
    --custom-location $customLocationId \
    --per-site-scaling --is-linux --sku K1

 

 

Create App Service using built-in Runtime stack:

To see all supported runtimes, run "az webapp list-runtimes --linux".

 

az webapp create \
   --plan <your App Service Plan name> \
   --resource-group <your App Service Resource Group name> \
   --name <Define your App Service name> \
   --custom-location $customLocationId \
   --runtime 'python|3.8'

 

 

Create App Service using your own Custom docker image:

 

az webapp create \
   --plan <your App Service Plan name> \
   --resource-group <your App Service Resource Group name> \
   --name <Define your App Service name> \
   --custom-location $customLocationId \
   --deployment-container-image-name <your ACR name>.azurecr.io/<image-name>:<tag>

 

 

Option 2:  Use Azure Portal to create App Service in your custom location

Create a resource > Marketplace > Web App 

We can choose to use App Service built-in Runtime stack or your own Docker Container.

 

Part 3: Deploy Application Code

If you are deploying your Custom Docker Image to App Service, there is no need to deploy application code separately. Since all the application code should already be packed inside your docker image.


If you are using App Service built-in Runtime stack, since the built-in docker image won't include your application code, you will need to deploy your code to the App Service. One of the easiest ways to deploy your code is using zip deployment.

 

Node.js deployment example

Your can pack your Node.js application on your local machine using the same Node.js version as you choose when creating the App Service.
As an example, we can start from the following sample code:

 

git clone https://github.com/Azure-Samples/nodejs-docs-hello-world 

 

In order to test dependency package installation, you can define your own "dependencies" section in package.json file.

For example:

 

{
    "name": "app-service-hello-world",
    "description": "Simple Hello World Node.js sample for Azure App Service",
    "version": "0.0.1",
    "private": true,
    "license": "MIT",
    "author": "Microsoft",
    "scripts": {
        "start": "node index.js"
    },
    "dependencies": {
        "http-errors": "~1.6.3",
        "applicationinsights": "1.8.7"
    }
}

 

Then use the following commands to pack the application into package.zip file. Make sure you run the "npm install" command, then confirm packages being installed in node_modules folder.

 

cd nodejs-docs-hello-world
npm install
zip -r package.zip .

 

Deploy the zip file to the App Service.

 

az webapp deployment source config-zip --resource-group  <your App Service Resource Group name> --name <your App Service Name> --src package.zip

 

 

Python deployment example

Your can pack your python application on your local machine using the same Python version as you choose when creating the App Service.
As an example, we can start from the following sample code:

 

git clone https://github.com/Azure-Samples/python-docs-hello-world

 

In order to test dependency package installation, you can add packages in your requirements.txt file
Then use the following commands to pack the application into package.zip file.
Make sure you create a python virtual environment with name "antenv", then run the "pip install" command and confirm packages being installed in /antenv/lib/pythonx.x/site-packages/.

 

cd python-docs-hello-world/
python3 -m venv antenv
source antenv/bin/activate
pip install -r requirements.txt
zip -r package.zip .

 

 

Deploy the zip file to the App Service.

 

az webapp deployment source config-zip --resource-group <your App Service Resource Group name> --name <your App Service Name> --src package.zip

 

 

After the code being successfully deployed, you should be able to open the website using the URL showed up in the App Service Overview Portal.

 

 

Part 4: Basic methods that can help you do the monitoring and troubleshooting

Use kubectl command to monitor and troubleshoot your AKS cluster

You can run kubectl command in Azure Cloud Shell, or you can run it on your local machine with Azure CLI installed. 

Firstly, your will need to get kubeconfig file and test your connection to the cluster. By default, the kubeconfig file is saved to ~/.kube/config.

 

az aks get-credentials --resource-group <your AKS Resource Group name> --name <your aks cluster name> --admin

 

 

Check pods status in your AKS.

The namespace value should be the one you defined in Part 1: Install the App Service extension step.

 

kubectl get pods --namespace appservice-ns 

 

 

Check App Service pod log.

The App Service pod name is listed by "kubectl get pods ..." command.

 

kubectl --namespace appservice-ns logs <App Service pod name>

 

 

Get AKS node status

 

kubectl get nodes

 

 

Get node details

 

kubectl describe node aks-nodepool1-xxxx-xxxx

 

 

Manually scale the node count

The "resource group name" should be "aksClusterGroupName" value you defined in Part 1: Create a connected cluster step.

The "AKS cluster name" should be "aksName" value you defined in Part 1: Create a connected cluster step.

 

az aks scale --resource-group <your AKS cluser resource group> --name <your AKS cluster name> --node-count 3

 

 

Restart the AKS cluster

 

az aks stop --name <your AKS cluster name> --resource-group  <your AKS cluster resource group>
az aks start --name <your AKS cluster name> --resource-group  <your AKS cluster resource group>

 

 

Check Logs in Log Analytics Workspace

App Service docker console logs are also recorded in the Log Analytics Workspace we created in Part 1: Create a Log Analytics workspace step.

You can use the following Kusto query to get logs generated by a specific App Service.

 

AppServiceConsoleLogs_CL 
| where AppName_s == "<App Service Name>"
| project TimeGenerated,AppName_s, ContainerImage_s,Log_s

 

 

 

Use WebSSH to access App Service application docker container

If you are using App Service Built-in runtime. The docker image already has WEBSSH enabled. So you can login to your application docker container.
Get the App Service's scm site URL, user name and password in App Service Portal --> Overview --> Get publish profile

Go to https://<app-service-name>.scm.xxxxxx.xxxx.k4apps.io/instances/any/webssh/host
Put in username and password you got in publish profile file.

Then you should be able to log in to the Application Docker Container via WEBSSH.

 

Access the Kubernetes web dashboard in Azure Kubernetes Service (AKS)

Reference doc:

https://docs.microsoft.com/en-us/azure/aks/kubernetes-dashboard#for-rbac-enabled-clusters

https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/

 

You need the Azure CLI version 2.6.0 or later installed and configured on your local machine.

 

Get the admin kubeconfig with the following command:

The RG_NAME should be "aksClusterGroupName" value you defined in Part 1: Create a connected cluster step.

The CLUSTER_NAME should be "aksName" value you defined in Part 1: Create a connected cluster step.

configure file by defualt will be saved in ~/.kube/config

 

az aks get-credentials -a --resource-group <RG_NAME> --name <CLUSTER_NAME>

 

 

The Kubernetes Dashboard UI is not deployed by default. To deploy it, run the following command:

 

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml

 

 

You can enable access to the Dashboard using the kubectl command-line tool, by running the following command:

 

kubectl proxy

 

 

Then you can access Kubernetes dashboard in your local machine.

http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/login 

 

We can check App Service details in the dashboard.

For example:

Check Docker container logs.

Get inside the Docker container

Updated Oct 22, 2021
Version 1.0
  • How cool is that? Out of this world is the answer 🙂 So much good can come out of it, thank you for making this a reality!!!

     

    Happy Azure Stacking!!!