Setting up serverless computing in Azure with Kubernetes and .NET

Serverless computing describes the concept of developing and running applications without having to worry about servers. On a high level and from a developer point of view that might be the case, but the underlying serverless platform does of course still rely on servers of some kind. In practice, serverless computing or function as a service (FaaS) is a layer of abstraction that hides away most of the operational aspects of running one or more applications. While Azure, Google and AWS all offer serverless products these days, you can also run a self-hosted serverless platform yourself.


When I started this article, i aimed to describe how OpenFaaS is a great way to set up a serverless computing environment that can run almost anywhere. Be it Kubernetes (pronounced “koo-ber-net-ees”), Docker Swarm or even a single machine, its supported. That means you can now deploy your functions with Azure, Google Cloud, AWS, or even a Raspberry Pi so be sure to look at it especially for running locally, but there are just to many variables so ill instead focus on OpenFaaS as a local setup and Azure as a cloud option.


OpenFaaS is also pretty language agnostic with support for Python, Java, Ruby, PHP, F# and of course C#. In this article, ill cover how to setup OpenFaaS and .NET in Azure. There are a few ways you can install OpenFaaS, including managed kubernetes clusters with cloud providers such as Azure, Google or AWS, but in this case we will focus on a deployment in Azure. OpenFaaS is fully compatible with Kubernetes and can leverage many of its features for improved scalability and configurability. A production ready Kubernetes cluster typically provides a solid foundation for vertical scaling. If the cluster also has horizontal scaling in the form of cluster auto scaling, OpenFaaS can virtually scale to infinity. Cluster auto scaling means worker nodes are created and destroyed automatically as workloads fluctuate.


Provided you don't run out of money and Azure doesn’t run out of virtual machines, that is.

OpenFaaS Architecture.


There are main two components that you should understand before getting started with OpenFaas, namely the Function Watchdog and API Gateway / UI Portal as shown below.



As the name indicates, the Function Watchdog is responsible for converting http messages to stdin then it passing them to functions and stdout or vice versa. Any docker image could be turned to serverless by adding Function Watchdog. The AWS API gateway provides an external route into your functions and collects Cloud Native metrics through Prometheus. It also scales functions according to demand by altering the service replica count in the Docker Swarm or Kubernetes API. It also provides the UI to invoke functions in your browser and create new ones as needed.


This section will walk you through how to get a Kubernetes cluster with Azure up and running. This involves two major steps:

  1. Creating a Kubernetes cluster.

  2. Installing the necessary software components inside the Kubernetes cluster.

1 Installation.

The process described in this article will create a managed Kubernetes cluster on Microsoft Azure. However I will give pointers as to what's needed to be changed to use another cloud provider. The steps involving the installation of the actual software components for OpenFaaS should work on any Kubernetes cluster.


This article will walk you through the process command by command. If you’re looking for a simpler and faster way you can find a mostly automated solution using Bash scripts in this GitHub repository from the legendary Marcus Legendre.

1.1 Prerequisites / Tool Chain

To follow along a Microsoft Azure account with a valid subscription is needed (a free trial is sufficient). Additionally a small selection of command line tools are needed:


Install the Azure CLI

Install Terraform

Install and set up kubectl

Install Helm

Azure CLI is needed to access your Microsoft Azure account from the command line. Once you have downloaded and installed the current release of Azure CLI, run the login command az login from either Windows Command Prompt or PowerShell. If the CLI can open your default browser, it will do so and load an Azure sign-in page. Otherwise, open a browser page at https://aka.ms/devicelogin and enter the authorization code displayed in your terminal. If no web browser is available or the web browser fails to open, use device code flow with az login --use-device-code.


Kubectl, is the Kubernetes (also known as K8s) command-line tool. It allows you to run commands against Kubernetes clusters. You can use kubectl to deploy applications, inspect and manage cluster resources, and view logs. Kubernetes is an open-source system for automating deployment, scaling, and management of containerized applications. If you want, you can use the following PowerShell script to downloaded the latest production version. The PowerShell script follows the same process as before, except it automatically extracts the zip file, saving the output to C:\Program Files\Kubectl\kubectl.exe and adds this path in your Machine Environment Variables Path.



<# This script is used to download kubectl on windows #> 
$user = [Security.Principal.WindowsIdentity]::GetCurrent();
if(!(New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator))
{
    Write-Warning "This PowerShell script requires that you run it as Administrator"
    Break
}
$Destination = 'C:\Program Files\Kubectl\kubectl.exe'
$KubectlDirectory = Split-Path -Path $Destination
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
if (!(Test-Path $KubectlDirectory))
{
    Write-Host -ForegroundColor White "==> Creating the Kubectl directy at C:\Program Files\Kubectl\"
    New-Item -Path "C:\Program Files\" -Name "Kubectl " -ItemType "directory" -Force
} 
$uri = "https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/#install-kubectl-binary-with-curl-on-windows"
Write-Host -ForegroundColor White "==> Getting download link from  $uri"   
$req = Invoke-WebRequest -UseBasicParsing -Uri $uri
try
{
    Write-Host -ForegroundColor White "==> Analyzing download link"   
    $downloadlink = ($req.Links | where href -Match "kubectl.exe").href
}
catch
{
    Write-Warning "==>Error Parsing Link"
    Break
}
Write-Host -ForegroundColor White "==> Starting download from $downloadlink using Bitstransfer"   
Start-BitsTransfer $downloadlink -DisplayName "Getting Kubectl from $downloadlink" -Destination $KubectlDirectory
Unblock-File $Destination
<# Set the Environment Variable Path #>
Write-Host -ForegroundColor White "==> Setting Kubectl Machine  Environment Variables Path"  
$machinePath = [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::Machine);
if ($machinePath | Select-String -SimpleMatch $KubectlDirectory)
{
    Write-Warning 'Folder already within Machine Environment Variables Path' 
} 
else
{
	Write-Host -ForegroundColor White "==> Adding $KubectlDirectory to Machine  Environment Variables Path"
	if($machinePath -match '\;$')
	{
		$updatedMachinePath = $machinePath + $KubectlDirectory
	}
	else
	{
		$updatedMachinePath = $machinePath + ';' + $KubectlDirectory
	}
	[Environment]::SetEnvironmentVariable("Path", $updatedMachinePath, [EnvironmentVariableTarget]::Machine)
      
}
Write-Host -ForegroundColor Green "==> Kubectl installed successfully at $KubectlDirectory"

This should produce the following output.


Helm is a package manager for Kubernetes. It simplifies the installation of software that’s comprised of multiple standalone components and assists with configuration management. E.g. an application might consist of multiple pods, which are collections of containers, some of which may require persistence storage and/or specific network configuration like exposing ports to a public network or load balancers. Helm packages are called charts and OpenFaaS provides an official Helm Chart which is used in this installation guide. Helm is also not provided by package managers and has to be downloaded from the official website. Again, if you want, you can use the following PowerShell script to downloaded the latest production version. The PowerShell script follows the same process as before, except it automatically extracts the zip file, saving the output to C:\Program Files\Helm\helm.exe and adds this path in your Machine Environment Variables Path.


<# This script is used to download Helm on windows #> 
$user = [Security.Principal.WindowsIdentity]::GetCurrent();
if(!(New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator))
{
    Write-Warning "This PowerShell script requires that you run it as Administrator"
    Break
}
$Destination = 'C:\Program Files\Helm\helm.exe'
$HelmDirectory = Split-Path -Path $Destination
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
if (!(Test-Path $HelmDirectory))
{
    Write-Host -ForegroundColor White "==> Creating the Helm directy at C:\Program Files\Helm\"  
    New-Item -Path "C:\Program Files\" -Name "Helm" -ItemType "directory" -Force
} 
$uri = "https://github.com/helm/helm/releases"
Write-Host -ForegroundColor White "==> Getting download link from  $uri"   
$req = Invoke-WebRequest -UseBasicParsing -Uri $uri
try
{
    Write-Host -ForegroundColor White "==> Analyzing download link"   
    $downloadlink = ($req.Links | where href -Match "-windows-amd64.zip" | select-object -First 1).href
}
catch
{
    Write-Warning "Error Parsing Link"
    Break
}
$ZipFile = $env:TEMP  + '\' + $(Split-Path -Path $downloadlink -Leaf) 
Write-Host -ForegroundColor White "==> Starting download from $downloadlink using Bitstransfer" 
Start-BitsTransfer $downloadlink -DisplayName "Getting Helm from $downloadlink" -Destination $ZipFile
Unblock-File $ZipFile
Write-Host -ForegroundColor White "==> Unzipping the zip from $downloadlink"
Expand-Archive -LiteralPath $ZipFile -DestinationPath $HelmDirectory -Force
Move-Item -Path "$HelmDirectory\windows-amd64\helm.exe" -Destination "$HelmDirectory\helm.exe"
Remove-Item "$HelmDirectory\windows-amd64\" -Recurse -ErrorAction Ignore
<# Set the Environment Variable Path #>
Write-Host -ForegroundColor White "==> Setting Helm Machine  Environment Variables Path"  
$machinePath = [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::Machine);
if ($machinePath | Select-String -SimpleMatch $HelmDirectory)
{
    Write-Warning "$HelmDirectory  already exists within Machine Environment Variables Path" 
} 
else
{
	Write-Host -ForegroundColor Magenta "==> Adding $HelmDirectory to Machine  Environment Variables Path"
	if($machinePath -match '\;$')
	{
		$updatedMachinePath = $machinePath + $HelmDirectory
	}
	else
	{
		$updatedMachinePath = $machinePath + ';' + $HelmDirectory
	}
	[Environment]::SetEnvironmentVariable("Path", $updatedMachinePath, [EnvironmentVariableTarget]::Machine)
      
}
Write-Host -ForegroundColor Green "==> Helm installed successfully at $HelmDirectory"

This should produce the following output.



1.2 Creating the Kubernetes cluster

First we need to log into Microsoft Azure using their command line tool by typing az login in a console. This will open the Azure website in a browser window and ask you to enter your login information and confirm that you want to grant access to the Azure CLI. NB, be sure to save all the generated json responses.

Step 1: Create a resource group (Optional). If you unaware of which location to use, you can get the full list with the command az account list-locations


az group create --name ServerlessRG --location uksouth


Step 2: Init Helm. Helm will help fulfill the need to quickly and reliably provision container applications through easy install, update, and removal. To use Helm to run your application in your AKS cluster, you need an Azure Container Registry to store your container images. You will need to provide your own unique registry name for the Azure Container Registry. The registry name must be unique within Azure, and contain 5-50 alphanumeric characters. Im using the Basic SKU because it's a cost-optimized entry point for development purposes that provides a balance of storage and throughput. You can do this running the following command but replace YourUniqueName with your unique container name.


az acr create --resource-group ServerlessRG --name YourUniqueName --sku Basic


Step 3: Create a Azure Kubernetes Service (AKS) cluster. Be sure to check out the pricing to understand costs. In this case I'm going to start with the A2 v2: 2 vCPUs, 4 GB RAM, 20 GB Temporary storage option.


az aks create --resource-group ServerlessRG --name OpenFaasCluster --location uksouth --node-vm-size Standard_A2_v2 --node-count 1 --enable-addons monitoring --attach-acr YourUniqueName --generate-ssh-keys


The command takes a few minutes so perhaps go get a coffee now.


Step 4: Connect to your newly created cluster by entering the following command. The command below uses the default location for the Kubernetes configuration file, which is ~/.kube/config. You can specify a different location for your Kubernetes configuration file using --file. I would also recommend you back up your keys to a safe location.


az aks get-credentials --resource-group ServerlessRG --name OpenFaasCluster


Step 5: Verify the connection to your cluster, using the kubectl get command to return a list of the cluster nodes.


kubectl get nodes


The following example output shows the single node created in the previous steps. Make sure that the status of the node is Ready.


Step 6: List all the cluster nodes and record the details.


kubectl get all -n kube-system


Step 7: Open Visual Studio and create a new ASP.NET Core Web App, Give it a name (In my case I just called it Kubernetes) and select the following options. You will need to have Docker Desktop installed to complete this step so if you don't have Docker Desktop installed, follow the steps here first.


Build your project and launch it in Docker to ensure its working as expected. If you encounter errors, I recommend you cover the steps on the Docker Getting Started Page as well as look at the free Microsoft Learn Course.


Step 7: Now build and push the web application to the ACR by using the az acr build command to build and push an image to the registry, using the preceding Dockerfile. The . at the end of the command sets the location of the Dockerfile, in this case to the current directory. This command must be run in the project folder. Replace the image name with whatever your projects name is.


az acr build --image Kubernetes:v1 --registry ServerlessHelmACR --file Dockerfile