Running Azure PaaS anywhere using Azure application services with Azure Arc

Azure application services with Azure Arc brings the cloud to their customers, instead of the customers to the cloud.

Running Azure PaaS anywhere using Azure application services with Azure Arc

Over the past decade, our industry started to transition from running solutions in on-premise datacenters to the cloud, to make things more scalable and more flexible.

Unfortunately, not every company can make this transition for reasons including data regulation, latency, security, and more.

Microsoft has been investing a lot in this area through various product lines. Today, Microsoft announced Azure application services with Azure Arc. This is the next step in their journey towards multi-cloud & hybrid workloads, allowing you to run Azure PaaS anywhere as if it would be on Microsoft Azure.

Let's take a walk down memory lane to see how this came about.

Microsoft’s hybrid and on-premises strategy

Microsoft’s aim has always been to allow customers to use Azure’s technology where they need it. This can be for fully on-premises or hybrid workloads.

Their first attempt at this was with Windows Azure Pack for Windows Server. It allowed you to install Azure on your hardware so that you could use Service Bus, Web Apps, VMs, and more on-premises.

We have had customers in the past that were doing this successfully, but it had limitations, was clunky to install & manage, and eventually it was no longer maintained by Microsoft.

Later on, Microsoft announced what would become the Azure Stack family, allowing you to use a range of hardware compliances that bring Azure to your datacenter and the edge.

Azure Stack

Azure Stack is a great solution if you are looking to run your Azure cloud and is actively maintained.

With Azure Arc, Microsoft takes this concept even further by allowing you to manage resources from within Azure while they can be running practically anywhere.

Azure Arc currently supports managing & operating typical servers, SQL servers, and Kubernetes clusters that run on any cloud provider, hybrid scenario, or on-premises infrastructure that is fully managed through Microsoft Azure as your single-pane-of-glass.

Azure Arc

Learn more about the changes to Azure Stack and the introduction of Azure Arc in our Ignite 2019 blog post.

Lastly, Microsoft has been working on making their products more open, giving you the capability to run them anywhere. It started with Azure Functions which is fully open-sourced and platform-agnostic, and later they have started the KEDA project in collaboration with Red Hat which is now a CNCF Sandbox project.

At Ignite 2019, Azure API Management announced their self-hosted gateway which allows you to run it where you want, and in 2020 Azure Logic Apps joined that effort with their new engine which is built on Azure Functions.

This means that you can easily run all these technologies outside of Azure already, on any cloud, on-premises, or the edge, and use the same paradigms to meet your business needs:

Self-hosting Azure PaaS anywhere 

All these products are relying on containerization as a packaging model, allowing them to provide a platform-agnostic way of execution.

Kubernetes, the industry-standard for container orchestration, is an essential technology in this story that allows you to manage not only your applications, but others such as Azure Functions, Logic Apps & API Management.

However, it is not a walk in the park because the learning curve for Kubernetes is steep and you just want to deploy your application. Also, there is no easy way to manage & operate these applications similar to what Microsoft Azure provides today.

Which brings us to Azure application services with Azure Arc (announcement) to bring Azure PaaS to customers. Codit was part of the private preview and we would like to share our experience with it and how we see this evolve.

What is Azure application services with Azure Arc?

Azure application services with Azure Arc makes it easier to successfully bring the Azure platform-as-a-service to where you need it.

It allows you to easily deploy Azure PaaS services such as Web Apps, Function Apps, Logic Apps, API Management & Event Grid to Kubernetes while still managing them from within Azure:

Azure application services with Azure Arc

It comes with additional integrations, such as Dapr & KEDA, to help you design, develop and autoscale your workloads automatically so you have to worry less about them.

By using an extension on your Azure Arc-enabled Kubernetes clusters, you can easily install the App Service control plane on Kubernetes and start deploying applications to it.

How does it work?

Azure application services with Azure Arc is available as an extension on Azure Arc-enabled Kubernetes clusters that allow you to easily install the App Service control plane on Kubernetes and start deploying your applications to it.

By creating a custom location on our Azure Arc-enabled Kubernetes cluster (docs), it allows customers to define a location in their cluster to which apps can deploy from Azure.

How does it work?

On that custom location, a new App Service Kubernetes Environment can be created allowing you to see what App Plans and Apps are hosted in the Kubernetes cluster. You can think of it as an App Service Environment, but for Kubernetes.

Once that environment is available, it allows you to host App Plan on it to deploy Web Apps, Function Apps, etc on them.

It is Azure, but running anywhere on Kubernetes!

You can develop, deploy, manage, and govern your applications regardless of where they are running – on Microsoft Azure or Azure Arc.

Where your resources are hosted becomes an implementation detail, because you no longer have to become a Kubernetes expert to understand how to deploy your applications; Azure handles this for you.

This not only reduces the learning curve and time-to-market, but it also allows you to more easily experiment with the new hosting option without too much investment.

However, you are still in charge of managing, operating, and scaling the Kubernetes cluster. That means that you’ll still need to learn Kubernetes itself, but you have less responsibility for managing the applications running on top of it and can fully rely on Azure Resource Manager (ARM).

Getting our hands dirty

In this example, we will bootstrap our cluster and install an Azure Web App on Kubernetes by using Azure CLI and ARM.

The commands in this blog post use variables without going much into detail on what they represent since it would make the blog post too lengthy but we’d like to give you the idea of the steps that need to be taken.

Bootstrapping our cluster

Before we can get started, we need to connect our Kubernetes cluster to Azure Arc:

$ az connectedk8s connect --name $clusterName –resource-group $groupName

When doing this, it will show an Azure resource in the portal that represents your Kubernetes cluster:

Those who are familiar with Azure Kubernetes Service will recognize the experience as it is very similar.

Next, we need to install the Azure application services with Azure Arc extension on our Arc-enabled Kubernetes cluster:

$ az k8s-extension create -g $groupName --name $extensionName --cluster-type connectedClusters -c $clusterName --extension-type 'Microsoft.Web.Appservice' --release-train stable --auto-upgrade-minor-version true --scope cluster --release-namespace $appServiceNamespace --configuration-settings "Microsoft.CustomLocation.ServiceAccount=default" --configuration-settings "appsNamespace=${appServiceNamespace}" --configuration-settings "clusterName=${kubeEnvironmentName}" --configuration-settings "loadBalancerIp=${staticIp}" --configuration-settings "buildService.storageClassName=default" --configuration-settings "buildService.storageAccessMode=ReadWriteOnce" --configuration-settings "customConfigMap=${appServiceNamespace}/kube-environment-config" --configuration-settings "${aksClusterGroupName}" --configuration-settings "logProcessor.appLogs.destination=log-analytics" --configuration-protected-settings "logProcessor.appLogs.logAnalyticsConfig.customerId=${logAnalyticsWorkspaceIdEnc}" --configuration-protected-settings "logProcessor.appLogs.logAnalyticsConfig.sharedKey=${logAnalyticsKeyEnc}"

By doing this, it will install the control plane to manage all the resources inside the cluster. Once that has completed, you will see a new extension on your Arc-enabled cluster:

If we have a look at our cluster, we can see that it deploys various components.

Here you can see the deployments that it uses:

Store the ID of our Azure application services with Azure Arc extension for later use:

$extensionId = az k8s-extension show –cluster-type connectedClusters -c $clusterName -g $groupName –name $extensionName –query id -o tsv

Now that the bootstrapping is done, we can start hosting our applications on Kubernetes but manage them through Azure ARM.

Deploying Web App to Kubernetes through Azure Arc

Creating a custom location

We will create a custom location for Azure Arc into a given Kubernetes namespace and give it a name:

$ az customlocation create -g $groupName -n $customLocationName --host-resource-id $connectedClusterId --namespace $appServiceNamespace -c $extensionId

Once completed, you will see it appear in the Azure portal.

Store the ID of the custom location for later use:

$customLocationId = az customlocation show -g $groupName -n $customLocationName --query id -o tsv

Creating an App Service Kubernetes Environment

It is easy to create an App Service Kubernetes Environment by giving it a name, specifying the custom location and the static IP of your cluster:

$ az appservice kube create -g $groupName -n $kubeEnvironmentName --custom-location $customLocationId --static-ip "$staticIp"

Now that that’s done, we can start deploying our applications!

Deploying a Web App to our App Service Kubernetes Environment

We will start by creating an App Plan on our Kubernetes environment:

$ az appservice plan create --name $appPlanName --resource-group $groupName --custom-location $customLocationId --is-linux --per-site-scaling

Next, we will deploy our Bacon API that provides a variety of flavors that you can try. This API is available as a container on GitHub Container Registry and can be hosted on any container platform:

$ az webapp create --resource-group $groupName --name codit-project-lima-web-app-bacon-api --custom-location $customLocationId --deployment-container-image-name --plan $appPlanName

And that is it! Your Web App is now deployed on Kubernetes but managed through Azure!

In the Azure portal, you see your typical Web App resources:

Note that Kubernetes is added as part of the kind for the resources.

When looking at the Kubernetes Environment, you will be able to see all app plans & apps running on top of it:

Giving you detailed information:

Lastly, if you have a look at the custom location that we have created, you can see the deployed resources in that location:

I hope that this example has shown you how easy it is to deploy App Services to Kubernetes!

Do you prefer ARM? No problem! It is almost identical to a typical Web App for Container:

    "$schema": "",
    "contentVersion": "",
    "parameters": {
        "AppService.Kubernetes.Environment.Id" : {
            "type": "string",
            "defaultValue": "/subscriptions/c1537527-c126-428d-8f72-1ac9f2c63c1f/resourceGroups/codit-preview-project-lima-us-east/providers/Microsoft.Web/kubeEnvironments/codit-project-lima-kube"
        "AppService.Plan.Name": {
            "type": "string",
            "defaultValue": "bacon-apps-arm"
        "Arc.Location.Id": {
            "type": "string",
            "defaultValue": "/subscriptions/c1537527-c126-428d-8f72-1ac9f2c63c1f/resourcegroups/codit-preview-project-lima-us-east/providers/microsoft.extendedlocation/customlocations/codit-project-lima-custom-location"
        "AppService.WebApp.Name": {
            "type": "string",
            "defaultValue": "codit-project-lima-web-app-bacon-api-arm"
        "Image.Name": {
            "type": "string",
            "defaultValue": "nginx"
        "Region": {
            "type": "string",
            "defaultValue": "Central US EUAP"
    "variables": {
        "AppService.Plan.Id": "[resourceId('Microsoft.Web/serverfarms', parameters('AppService.Plan.Name'))]"
    "resources": [
            "type": "Microsoft.Web/serverfarms",
            "name": "[parameters('AppService.Plan.Name')]",
            "location": "[parameters('Region')]",
            "apiVersion": "2018-02-01",
            "kind": "linux,kubernetes",
            "sku": {
                "name": "K1",
                "tier": "Kubernetes"
            "extendedLocation": {
                "type": "customlocation",
                "name": "[parameters('Arc.Location.Id')]"
            "properties": {
                "name": "[parameters('AppService.Plan.Name')]",
                "location": "[parameters('Region')]",
                "workerSizeId": "0",
                "numberOfWorkers": "1",
                "kubeEnvironmentProfile": {
                    "id": "[parameters('AppService.Kubernetes.Environment.Id')]"
                "reserved": true
            "dependsOn": [
            "type": "Microsoft.Web/sites",
            "name": "[parameters('AppService.WebApp.Name')]",
            "location": "[parameters('Region')]",
            "apiVersion": "2016-09-01",
            "kind": "linux,kubernetes,app,container",
            "extendedLocation": {
                "type": "customlocation",
                "name": "[parameters('Arc.Location.Id')]"
            "properties": {
                "name": "[parameters('AppService.WebApp.Name')]",
                "serverFarmId": "[variables('AppService.Plan.Id')]",
                "siteConfig": {
                    "appSettings": [
                    "linuxFxVersion": "[concat('DOCKER|', parameters('Image.Name'))]"
            "dependsOn": [

When looking closely, you will notice the following differences compared to a typical Web App template:

  • Both resources now have “Kubernetes” as part of the Kind
  • The App Plan now has a kubeEnvironmentProfilethat refers to the App Service Kubernetes Environment

But once again, that is how easy it is to deploy to Kubernetes by using Azure application services with Azure Arc.

When should you use Azure application services with Azure Arc?

So when should you use Azure application services with Azure Arc? Glad you’ve asked!

I’m a believer that you should always get started with Azure Serverless and PaaS to focus on your application and not the infrastructure. For a lot of scenarios, this is the perfect starting point and by using containerization, your application is already portable for the day you need to move it.

We have seen a lot of customers who are very happy with Azure Serverless & PaaS and keep running on top of it because it meets all their needs. Integrations with other services, such as Azure Monitor Autoscale, Application Insights, and more, are a big added value that simplifies their applications.

Azure Kubernetes Service, however, is a cluster platform-as-a-service (CPaaS) and not a PaaS. While it gives you a fully managed Kubernetes cluster there are still a lot of things that you have to take care of that you often don’t need such as Kubernetes version management, cluster capacity planning & scaling, cluster monitoring, cost management, security, and we haven’t talked about running any applications on it yet.

However, Kubernetes does have its place and time to shine! So I would advise using Azure application services with Azure Arc to host your workloads when:

  • You have multi-cloud/run anywhere needs, but want to have a unified management/operational story
  • Your company has standardized on Kubernetes
  • You want to reduce the lock-in of your platform (no lock-in is a myth)
  • You have existing workloads running on a Kubernetes cluster and need to make your workloads available to them, without jeopardizing security
  • You need more control than you get on Azure PaaS

Just know that this comes with some trade-offs since:

  • You will have to manage the onboarding of your Kubernetes clusters to Azure Arc, custom location, and new App Service extension
  • You are in charge of not only the workloads that you deploy on the cluster but also the App Service control plane or you will no longer be able to deploy
  • You need to ensure that you take care of the typical Kubernetes cluster responsibilities such as ensuring capacity, patching nodes, Kubernetes version management, etc
  • Your company has enough Kubernetes experience to be able to troubleshoot in case of (production) issues, even if you are running a PaaS on top of it

But this allows you to have the best of both worlds – You rely on open-source technology by using Kubernetes, but still, have to worry less about management for the application itself.


Kubernetes is a very powerful technology that allows you to build cloud-native solutions that are vendor-agnostic, allowing you to run in the cloud, on-prem, or on the edge.

However, running Kubernetes is not a walk in the park and comes with a lot of responsibilities. Luckily, there is a big community behind the technology that helps to make it easier to use it.

Azure Kubernetes Service is another key tool in your toolchain to simplify the infrastructure for your clusters, but for new developers & operators it still can be a bit overwhelming, and it has a steep learning curve.

We are on the verge of a new era where the Kubernetes adoption will skyrocket even more. Azure application services with Azure Arc is an essential asset for building cloud-native solutions that are operable and provide a consistent experience, regardless of where they run.

Azure application services with Azure Arc brings the cloud to their customers, instead of the customers to the cloud.

Thanks for reading,


Photo by Michael & Diane Weidner on Unsplash