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:
- Part 1: Prepare the AKS and Azure Arc environment
- Part 2: Create Azure App Service in Kubernetes cluster
- Part 3: Deploy Application Code
- 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.
We can check App Service details in the dashboard.
For example:
Check Docker container logs.
Get inside the Docker container