<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anirudh Garg</title>
    <description>The latest articles on DEV Community by Anirudh Garg (@anirudhgarg_99).</description>
    <link>https://dev.to/anirudhgarg_99</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F309597%2Fc62122f1-ff03-4004-9075-c7c6129ee1a4.png</url>
      <title>DEV Community: Anirudh Garg</title>
      <link>https://dev.to/anirudhgarg_99</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anirudhgarg_99"/>
    <language>en</language>
    <item>
      <title>Why use Azure Functions for ML inference ?</title>
      <dc:creator>Anirudh Garg</dc:creator>
      <pubDate>Thu, 28 May 2020 16:57:18 +0000</pubDate>
      <link>https://dev.to/azure/why-use-azure-functions-for-ml-inference-ela</link>
      <guid>https://dev.to/azure/why-use-azure-functions-for-ml-inference-ela</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article highlights the current limitations in offerings by FaaS providers for ML inference applications and how capabilities in Azure Functions overcome these making it an ideal platform for such applications. It also links to an end to end sample illustrating these features.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ML Inference in FaaS Services
&lt;/h2&gt;

&lt;p&gt;The core promise of Serverless/FaaS (Functions as a Service) computing is to make it easier for developers to build, deploy and scale up their applications. Among the different kinds of applications - ML applications have seen an explosion in their usage and are now rapidly being deployed and bringing unprecedented novel capabilities in various domains.&lt;/p&gt;

&lt;p&gt;A typical ML workflow consists of using sample data to train a model and then use that model in an application to make predictions based on input. These stages are typically called &lt;em&gt;training&lt;/em&gt; and &lt;em&gt;inference&lt;/em&gt; respectively. On the surface, ML &lt;em&gt;inference&lt;/em&gt; should be a straightforward FaaS use case as essentially there is a single "predict" function that is called to "infer" the result for a particular input. However, due to various limits that typical FaaS platforms impose it hasn't been as optimum a platform that it can be. These are some of the limitations:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;ML &lt;em&gt;libraries&lt;/em&gt; can be big&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;ML(especially Deep learning) libraries can be big in size. For example the &lt;a href="https://pytorch.org/" rel="noopener noreferrer"&gt;PyTorch&lt;/a&gt; (even the non-CUDA version) library is around ~300MB. &lt;br&gt;
However, most FaaS providers only allow a maximum of ~250MB-~500MB of deployed package size &lt;em&gt;including&lt;/em&gt; any modules needed in the application. Customers have to resort to getting around to these limitations by compressing shared libraries, removing test folders etc.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. &lt;strong&gt;Python ML &lt;em&gt;libraries&lt;/em&gt; use native dependencies&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Many Python ML libraries call into other C/C++ libraries, those need to be recompiled based on the OS causing a mismatch between the development and production deployments. For instance, developers using Windows have to resort to using Docker before deploying their FaaS application.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. &lt;strong&gt;ML &lt;em&gt;models&lt;/em&gt; can be big&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Some of the latest ML models can be very big in size - for example the &lt;a href="https://arxiv.org/abs/1404.5997" rel="noopener noreferrer"&gt;AlexNet&lt;/a&gt; pre-trained &lt;a href="https://pytorch.org/docs/stable/torchvision/models.html#id1" rel="noopener noreferrer"&gt;PyTorch model&lt;/a&gt; is 230MB. Some models like &lt;a href="https://openai.com/blog/gpt-2-1-5b-release/" rel="noopener noreferrer"&gt;GPT-2&lt;/a&gt; can be several GB in size. FaaS offerings have a limited deployment size package as mentioned above - further, they don't offer a way to separate out the model from the code by mounting a file system for instance.&lt;/p&gt;

&lt;p&gt;Further, some large models need to be completely loaded into memory before they can be used and amount of memory offered in current Serverless offerings might not be enough.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. &lt;strong&gt;Concurrency models for I/O bound invocations are sub-optimal&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Many ML inference API's are typically I/O bound, however, in current FaaS execution frameworks a single instance cannot handle concurrent requests. The can lead to a lot of wasted idle resources on individual instances. &lt;/p&gt;
&lt;h3&gt;
  
  
  5. &lt;strong&gt;Cold start&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;FaaS workloads scale down to zero instances when not being used, therefore starting a new instance always incurs lag - which is called cold start. For many applications this lag is not acceptable.&lt;/p&gt;
&lt;h3&gt;
  
  
  6. &lt;strong&gt;GPU support is not available&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Many inference applications have a very stringent latency requirements (think for instance applications related to providing auto-suggestions as you type). To meet these latency requirements often (especially for bigger models) GPU processing can lead to several times of improvement. However FaaS providers currently do not support GPU's.&lt;/p&gt;
&lt;h3&gt;
  
  
  7. &lt;strong&gt;No native support for long running ML workloads and/or orchestration patterns&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Some ML workloads might be inherently long running and/or have complex orchestration needs. Current FaaS providers do not offer native frameworks for these scenarios and customers need to resort to external services and built the complex coordination logic themselves.&lt;/p&gt;
&lt;h2&gt;
  
  
  Azure Functions Python
&lt;/h2&gt;

&lt;p&gt;In Azure Functions Python capabilities and features have been added to overcome some of the above limitations and make it a first class option for ML inference with all the traditional FaaS benefits of scaling on demand, fast iteration and pay-for-use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FAzure-Samples%2Fazure-functions-pytorch-image-identify%2Fmaster%2Fmedia%2Fteaser.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FAzure-Samples%2Fazure-functions-pytorch-image-identify%2Fmaster%2Fmedia%2Fteaser.png" alt="azure-functions-ml"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  1. &lt;strong&gt;Higher deployment package sizes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Azure Functions support higher deployment packages as much as several GB in size. This means that even larger deep learning frameworks like TensorFlow and PyTorch can be supported out of the box without resorting to having to reduce the size without affecting functionality. &lt;/p&gt;
&lt;h3&gt;
  
  
  2. &lt;strong&gt;Support for Remote Build&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As mentioned above, many Python libraries have native dependencies. This means if you are developing your application on Windows and then deploy it in production which typically is on Linux - it might not work as they have to be recompiled to work on another operating system. &lt;/p&gt;

&lt;p&gt;To help with this problem in Azure Functions we built the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-python#remote-build" rel="noopener noreferrer"&gt;Remote Build&lt;/a&gt; functionality, where we automatically compile and pull in the right libraries on the server side. Hence, they don't have to be included in your deployment package locally and only need to be referenced in your requirements.txt file. This is default experience when using VSCode or the func core tools to deploy your Python Azure Functions application. This is a snippet from the deployment logs showing the libraries being installed on the server side.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;12:02:54 AM pytorch-image-consumption: Starting deployment...
.
12:03:01 AM pytorch-image-consumption: Running pip install...
...
12:03:14 AM pytorch-image-consumption: [07:03:14+0000] Collecting torch==1.4.0+cpu
12:03:14 AM pytorch-image-consumption: [07:03:14+0000]   Downloading https://download.pytorch.org/whl/cpu/torch-1.4.0%2Bcpu-cp37-cp37m-linux_x86_64.whl (127.2MB)
12:03:45 AM pytorch-image-consumption: [07:03:45+0000] Collecting torchvision==0.5.0
12:03:45 AM pytorch-image-consumption: [07:03:45+0000]   Downloading https://files.pythonhosted.org/packages/1c/32/cb0e4c43cd717da50258887b088471568990b5a749784c465a8a1962e021/torchvision-0.5.0-cp37-cp37m-manylinux1_x86_64.whl (4.0MB)
....
12:04:08 AM pytorch-image-consumption: [07:04:08+0000] Successfully installed azure-functions-1.2.1 certifi-2020.4.5.1 chardet-3.0.4 idna-2.9 numpy-1.15.4 pillow-7.1.2 requests-2.23.0 six-1.14.0 torch-1.4.0+cpu torchvision-0.5.0 urllib3-1.25.9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. &lt;strong&gt;Support for mounting an external file system through Azure Files&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To allow for arbitrarily large ML models and to separate the workflow of building the application and training your ML model the capability to automatically mount a &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/scripts/functions-cli-mount-files-storage-linux" rel="noopener noreferrer"&gt;configured Azure file share&lt;/a&gt; has been recently introduced.&lt;/p&gt;

&lt;p&gt;This is as simple as using an Azure CLI command where the &lt;em&gt;$shareName&lt;/em&gt; Azure File share will automatically be mounted whenever the &lt;em&gt;$functionAppName&lt;/em&gt; Function app starts up. The path available to the Function app will be with the name of &lt;em&gt;$mountPath&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az webapp config storage-account add &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--resource-group&lt;/span&gt; myResourceGroup &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$functionAppName&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--custom-id&lt;/span&gt; &lt;span class="nv"&gt;$shareId&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--storage-type&lt;/span&gt; AzureFiles &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--share-name&lt;/span&gt; &lt;span class="nv"&gt;$shareName&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--account-name&lt;/span&gt; &lt;span class="nv"&gt;$AZURE_STORAGE_ACCOUNT&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--mount-path&lt;/span&gt; &lt;span class="nv"&gt;$mountPath&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--access-key&lt;/span&gt; &lt;span class="nv"&gt;$AZURE_STORAGE_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an Azure Files storage view with two different models.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FAzure-Samples%2Fazure-functions-pytorch-image-identify%2Fmaster%2Fmedia%2Fstorage-account-file-share.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FAzure-Samples%2Fazure-functions-pytorch-image-identify%2Fmaster%2Fmedia%2Fstorage-account-file-share.png" alt="azure-files"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This functionality is available both in the Consumption and Premium plans. It is also worth noting that &lt;a href="https://docs.microsoft.com/en-us/azure/storage/files/storage-how-to-create-premium-fileshare" rel="noopener noreferrer"&gt;Azure Files have a Premium tier&lt;/a&gt; which can be used as well - it offers a higher level of performance i.e. high throughput and low latency for IO-intensive workloads(many ML applications)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The above two features Remote Build and support for Azure Files allow the deployment package to be much smaller. For example, in the PyTorch sample referenced below the total package size would have been close to 520MB in size when using the resnet100 model (~350MB for PyTorch and ~170MB for the model) while without it it is barely 50KB in size.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Azure Functions concurrency model is optimal for I/O bound invocations&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In Azure Functions - the same instance is re-used for concurrent calls. This can lead to optimum use of resources especially for &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-python#scaling-and-concurrency" rel="noopener noreferrer"&gt;concurrent I/O bound invocations&lt;/a&gt; where the underlying api has async variants.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Azure Functions Premium SKU's offer higher memory limits and no cold start&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-premium-plan" rel="noopener noreferrer"&gt;The Azure Functions Premium SKU&lt;/a&gt; offers &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-premium-plan#available-instance-skus" rel="noopener noreferrer"&gt;higher memory limits - up to 14GB&lt;/a&gt; for cases where you would want to load the entire model in memory. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SKU&lt;/th&gt;
&lt;th&gt;Cores&lt;/th&gt;
&lt;th&gt;Memory&lt;/th&gt;
&lt;th&gt;Storage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;EP1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3.5GB&lt;/td&gt;
&lt;td&gt;250GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EP2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;7GB&lt;/td&gt;
&lt;td&gt;250GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EP3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;14GB&lt;/td&gt;
&lt;td&gt;250GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It also avoids &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-premium-plan#pre-warmed-instances" rel="noopener noreferrer"&gt;cold start&lt;/a&gt; for those applications where there cannot be any latency at all. &lt;/p&gt;

&lt;p&gt;Further, the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-function-linux-custom-image?tabs=bash%2Cportal&amp;amp;pivots=programming-language-python" rel="noopener noreferrer"&gt;custom container support&lt;/a&gt; enables integration with the &lt;a href="https://docs.microsoft.com/en-us/azure/machine-learning/how-to-deploy-functions" rel="noopener noreferrer"&gt;Azure Machine Learning service&lt;/a&gt; such that you can package a model from the Azure ML service into an Azure Function Premium app and allows the use of a &lt;a href="https://github.com/Hazhzeng/functions-conda" rel="noopener noreferrer"&gt;Conda&lt;/a&gt; environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. &lt;strong&gt;Deploy Azure Functions to a Kubernetes cluster with GPU support&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Finally, as in Azure Functions the &lt;a href="https://github.com/Azure/azure-functions-host" rel="noopener noreferrer"&gt;programming model&lt;/a&gt; is separate from the deployment target, an Azure Function app can be deployed to a Kubernetes cluster (it can be scaled up and down using &lt;a href="http://keda.sh" rel="noopener noreferrer"&gt;KEDA&lt;/a&gt;). Many managed Kubernetes offering (including &lt;a href="https://docs.microsoft.com/en-us/azure/aks/gpu-cluster" rel="noopener noreferrer"&gt;AKS&lt;/a&gt;) have GPU support.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. &lt;strong&gt;Orchestrating inference invocations - Durable Functions Python&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;With the impending release of &lt;a href="https://github.com/Azure/azure-functions-durable-python" rel="noopener noreferrer"&gt;Durable Functions Python&lt;/a&gt; long running ML workloads can now be supported. Durable Functions allows many different orchestration use cases including processing multiple inputs in a batch, parallelizing classification tasks etc. These are enabled by the &lt;a href="https://github.com/Azure/azure-functions-durable-python/tree/dev/samples/function_chaining" rel="noopener noreferrer"&gt;Chaining&lt;/a&gt;, &lt;a href="https://github.com/Azure/azure-functions-durable-python/tree/dev/samples/fan_out_fan_in" rel="noopener noreferrer"&gt;Fan-Out Fan-In&lt;/a&gt; and other Durable Function patterns. &lt;a href="https://github.com/Azure/azure-functions-durable-python/tree/dev/samples/fan_out_fan_in_tensorflow" rel="noopener noreferrer"&gt;This sample&lt;/a&gt; illustrates the use of the Fan-Out Fan-In pattern doing parallel image classification using &lt;a href="https://www.tensorflow.org/" rel="noopener noreferrer"&gt;TensorFlow&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample
&lt;/h2&gt;

&lt;p&gt;To put this all together and show a real example - please find a &lt;a href="https://github.com/Azure-Samples/azure-functions-pytorch-image-identify" rel="noopener noreferrer"&gt;step by step walk through examples of an Azure Function app&lt;/a&gt; that is able to use several of these &lt;a href="https://pytorch.org/docs/stable/torchvision/models.html#classification" rel="noopener noreferrer"&gt;pre-trained PyTorch models&lt;/a&gt; from an Azure File share to create an inference application which classifies images.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FAzure-Samples%2Fazure-functions-pytorch-image-identify%2Fmaster%2Fmedia%2Fpytorch-models.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FAzure-Samples%2Fazure-functions-pytorch-image-identify%2Fmaster%2Fmedia%2Fpytorch-models.png" alt="pytorch-models"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It illustrates the use of  &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-python#remote-build" rel="noopener noreferrer"&gt;Remote Build&lt;/a&gt;, gives guidance on how you can deploy the same app to the Premium plan for no-cold start and higher memory limits and gives guidance on how the same app can be deployed to a AKS cluster with GPU. More end to end examples will be added soon for text generation and other ML tasks.&lt;/p&gt;

&lt;p&gt;Hopefully this blog post encourages you to consider Azure Functions for your ML inference applications. Please ask any questions in the comments, or open any issues in the &lt;a href="https://github.com/Azure/azure-functions-python-worker" rel="noopener noreferrer"&gt;Azure Functions Python Worker repo&lt;/a&gt; or in the &lt;a href="https://github.com/Azure-Samples/azure-functions-pytorch-image-identify" rel="noopener noreferrer"&gt;sample repo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>azure</category>
      <category>serverless</category>
      <category>python</category>
    </item>
    <item>
      <title>Announcing Azure Functions Kafka extension Public Preview</title>
      <dc:creator>Anirudh Garg</dc:creator>
      <pubDate>Tue, 28 Apr 2020 04:38:18 +0000</pubDate>
      <link>https://dev.to/anirudhgarg_99/announcing-azure-functions-kafka-extension-public-preview-45hl</link>
      <guid>https://dev.to/anirudhgarg_99/announcing-azure-functions-kafka-extension-public-preview-45hl</guid>
      <description>&lt;p&gt;We're excited to announce today the public preview of the &lt;a href="https://github.com/Azure/azure-functions-kafka-extension"&gt;Kafka Extension&lt;/a&gt; for Azure Functions. With this new extension you can now have functions trigger in response to messages in Kafka Topics, or write to a Kafka Topic through the output binding. The extension is supported when hosting functions in the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-scale#premium-plan"&gt;Premium plan&lt;/a&gt; enabling it to elastically scale and trigger on Kafka messages. You can also use Kafka with Azure Functions containers in Kubernetes alongside &lt;a href="https://keda.sh/scalers/apache-kafka/"&gt;KEDA&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  How to get started with the Kafka Trigger
&lt;/h3&gt;

&lt;p&gt;To get started with using the Kafka trigger, you need to include the extension in your function project.&lt;/p&gt;

&lt;h4&gt;
  
  
  .NET Functions
&lt;/h4&gt;

&lt;p&gt;For .NET functions, you can pull in the Kafka &lt;a href="https://www.nuget.org/packages/Microsoft.Azure.WebJobs.Extensions.Kafka/2.0.0-beta"&gt;NuGet extension&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet add package Microsoft.Azure.WebJobs.Extensions.Kafka --version 2.0.0-beta
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  JavaScript, TypeScript, Python, Java, and PowerShell Functions
&lt;/h4&gt;

&lt;p&gt;For other functions, you need to install the extension into your project using the Azure Functions core tools&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func extensions install Microsoft.Azure.WebJobs.Extensions.Kafka --version 2.0.0-beta
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can then create a function that can activate and run whenever a message is dropped in a  Kafka topic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example C# Trigger using Confluent Cloud Managed Kafka
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;kafka_example&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FunctionName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kafkaApp"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConfluentCloudStringTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
             &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;KafkaTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;"BootstrapServer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"users"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;ConsumerGroup&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;ConsumerGroup&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Protocol&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BrokerProtocol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SaslSsl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;AuthenticationMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BrokerAuthenticationMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Plain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;APIKey&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;APISecret&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;SslCaLocation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"confluent_cloud_cacert.pem"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="n"&gt;KafkaEventData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;kafkaEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;       
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kafkaEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Example host.json
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"kafka"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"maxBatchSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can find more settings documented &lt;a href="https://github.com/Azure/azure-functions-kafka-extension#configuration-settings"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example functions.json
&lt;/h3&gt;

&lt;p&gt;Note: This is auto-generated for C#&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"bindings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kafkaTrigger"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"consumerGroup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"azfunc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"saslSsl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"authenticationMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"plain"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;KafkaAPIKey&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;KakfaSecret&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sslCaLocation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;RootCertificateFile&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"topic"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;KafkaTopicName&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"brokerList"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;Server&amp;gt;.eastus.azure.confluent.cloud:9092"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kafkaEvent"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Please find a complete end to end walkthrough and sample app using the Confluent Cloud in this GitHub repo &lt;a href="https://github.com/Azure/azure-functions-kafka-extension-sample-confluent"&gt;Kafka extension sample with Confluent Cloud.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This extension is being developed in the open, please contribute, try out and post any issues on the &lt;a href="https://github.com/Azure/azure-functions-kafka-extension"&gt;Azure Functions Kafka extension GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Along with the &lt;a href="https://dev.to/azure/announcing-the-rabbitmq-extension-for-azure-functions-2mbo"&gt;Rabbit MQ Trigger&lt;/a&gt; that we announced last year that is now also supported in the Premium Plan, we continue to innovate to bring in more Cloud Native and Open Source event sources. We are looking forward to see what applications you build with this ! &lt;/p&gt;

</description>
      <category>azure</category>
      <category>serverless</category>
      <category>kafka</category>
    </item>
    <item>
      <title>Scale a HTTP Triggered app up and down in Kubernetes using KEDA and Prometheus</title>
      <dc:creator>Anirudh Garg</dc:creator>
      <pubDate>Mon, 13 Jan 2020 03:22:19 +0000</pubDate>
      <link>https://dev.to/anirudhgarg_99/scale-up-and-down-a-http-triggered-function-app-in-kubernetes-using-keda-4m42</link>
      <guid>https://dev.to/anirudhgarg_99/scale-up-and-down-a-http-triggered-function-app-in-kubernetes-using-keda-4m42</guid>
      <description>&lt;p&gt;This blog post goes into how you can scale up and down your Http Triggered application in Kubernetes based on requests using KEDA and Prometheus.&lt;/p&gt;

&lt;p&gt;The application here is an Azure Function app but it can be any app that exposes a Http interface. Where appropriate below I point out where you can use your app instead of an Azure Function app.&lt;/p&gt;

&lt;p&gt;Among the major cloud providers, the FaaS implementation in Azure, Azure Functions, is unique that its runtime is &lt;a href="https://github.com/Azure/azure-functions-host" rel="noopener noreferrer"&gt;open-source&lt;/a&gt;. The runtime and your code can therefore be deployed to a &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-function-linux-custom-image?tabs=nodejs" rel="noopener noreferrer"&gt;custom container&lt;/a&gt; or deployed on your own infrastructure including Kubernetes. &lt;/p&gt;

&lt;p&gt;To enable scaling of a function app (or any other workload) in Kubernetes we at Azure (along with RedHat) built &lt;a href="http://keda.sh" rel="noopener noreferrer"&gt;KEDA&lt;/a&gt;, Kubernetes Event Driven Autoscaling. With the combination of aforementioned runtime and KEDA you can run and scale your Azure Functions in your own &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-kubernetes-keda" rel="noopener noreferrer"&gt;Kubernetes cluster&lt;/a&gt;. Currently in KEDA we support more than twenty different message event sources  including Kafka, RabbitMQ, NATS, &lt;a href="https://github.com/kedacore/sample-hello-world-azure-functions" rel="noopener noreferrer"&gt;Azure Queue&lt;/a&gt;, AWS SQS Queue, GCP Pub Sub etc. However, there is no support for Http request based scaling. This post outlines one approach on how you can scale a Http Trigerred function app in Kubernetes using the &lt;a href="https://keda.sh/scalers/prometheus/" rel="noopener noreferrer"&gt;Prometheus KEDA scaled object&lt;/a&gt; and an Ingress Controller. &lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;The basic idea is that we will deploy an &lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/" rel="noopener noreferrer"&gt;Ingress Controller&lt;/a&gt; in this case the &lt;a href="https://kubernetes.github.io/ingress-nginx/" rel="noopener noreferrer"&gt;NGINX Ingress Controller&lt;/a&gt; and have all HTTP traffic to your function app go through it. We use Prometheus to track the incoming request metrics on the Ingress Controller. Finally, we use KEDA's Prometheus based scaler to scale up/down the function app deployment. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faqvoayuj7g1ns14tdvwz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faqvoayuj7g1ns14tdvwz.jpg" alt="HttpScale" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Walkthrough
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;A Kubernetes cluster which has the ability to install a Service with a Load Balancer (usually any cloud provider). The steps below were tested using an &lt;a href="https://docs.microsoft.com/en-us/azure/aks/" rel="noopener noreferrer"&gt;AKS&lt;/a&gt; cluster.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/" rel="noopener noreferrer"&gt;kubectl&lt;/a&gt; pointing to your Kubernetes cluster &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://helm.sh/docs/intro/install/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; to install the artifacts. All of the artifacts below use Helm3&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local" rel="noopener noreferrer"&gt;Azure Functions core tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.docker.com/install/" rel="noopener noreferrer"&gt;docker&lt;/a&gt; installed locally and a &lt;a href="https://hub.docker.com/" rel="noopener noreferrer"&gt;Docker Hub&lt;/a&gt; account.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a namespace for your ingress resources&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create namespace ingress-nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the NGINX-Ingress ingress controller &lt;/p&gt;

&lt;p&gt;Use Helm to deploy an NGINX ingress controller and enable metrics and set the right annotations for Prometheus. The ingress controller is installed as service with LoadBalancer type. In addition, a backend Service and a metrics Service are also deployed.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm install ingress-controller stable/nginx-ingress \     
    --namespace ingress-nginx \
    --set controller.replicaCount=2 \
    --set controller.metrics.enabled=true \
    --set controller.podAnnotations."prometheus\.io/scrape"="true" \
    --set controller.podAnnotations."prometheus\.io/port"="10254"

kubectl -n ingress-nginx get svc
NAME                                                  TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)                      AGE
ingress-controller-nginx-ingress-controller           LoadBalancer   10.0.14.166    40.70.230.xxx   80:31036/TCP,443:32179/TCP   31s
ingress-controller-nginx-ingress-controller-metrics   ClusterIP      10.0.240.199   &amp;lt;none&amp;gt;          9913/TCP                     31s
ingress-controller-nginx-ingress-default-backend      ClusterIP      10.0.63.133    &amp;lt;none&amp;gt;          80/TCP                       31s
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The ingress controller is exposed via the EXTERNAL-IP 40.70.230.xxx above. Also have a look at the following &lt;a href="https://github.com/kubernetes/ingress-nginx/blob/master/docs/deploy/index.md" rel="noopener noreferrer"&gt;page&lt;/a&gt; for instructions on how to install it for various configurations.&lt;br&gt;&lt;br&gt;
Optionally - Create a DNS entry pointing to your ingress controller. For AKS, you can get a cloudapp.azure.com address using the procedure &lt;a href="https://docs.microsoft.com/en-us/azure/aks/ingress-tls#configure-a-dns-name" rel="noopener noreferrer"&gt;here&lt;/a&gt;. In the steps below the fqdn configured is "function-helloworld.eastus2.cloudapp.azure.com"   &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://kubernetes.github.io/ingress-nginx/user-guide/monitoring/" rel="noopener noreferrer"&gt;Deploy Prometheus&lt;/a&gt; to monitor the NGINX ingress Controller&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply --kustomize github.com/kubernetes/ingress-nginx/deploy/prometheus/    

kubectl -n ingress-nginx get svc
NAME                                                  TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)                      AGE
...
prometheus-server                                     NodePort       10.0.38.50     &amp;lt;none&amp;gt;          9090:30860/TCP               34s

kubectl -n ingress-nginx get pods
NAME                                                              READY   STATUS    RESTARTS   AGE
..
prometheus-server-86cd54f9d5-9xxh7                                1/1     Running   0          95s
&lt;/code&gt;&lt;/pre&gt;


&lt;blockquote&gt;
&lt;p&gt;Note: If you happen to use any other namespace other than "ingress-nginx" then you need to go and change the namespace in the yaml files from &lt;a href="https://github.com/kubernetes/ingress-nginx/tree/master/deploy/prometheus" rel="noopener noreferrer"&gt;here&lt;/a&gt; and then deploy. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy &lt;a href="https://keda.sh/deploy/" rel="noopener noreferrer"&gt;KEDA&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm install keda kedacore/keda --namespace ingress-nginx     

kubectl get pods -n ingress-nginx
NAME                                                              READY   STATUS    RESTARTS   AGE
...
keda-operator-697b98dcdd-8zdrk                                    2/2     Running   0          5d17h
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy a function app to the Kubernetes cluster&lt;br&gt;
Create a Python Http Trigerred function app, generate the required docker file and finally deploy the function app to the cluster.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func init --worker-runtime python
func new --template "HttpTrigger" --name helloworld
func init --docker-only
func kubernetes deploy --name function-helloworld --namespace ingress-nginx --service-type ClusterIP --registry anirudhgarg
&lt;/code&gt;&lt;/pre&gt;


&lt;blockquote&gt;
&lt;p&gt;Note that the authentication mode has to be changed to anonymous for now while we are working to support function keys. Navigate to the function app folder and open the function.json file. Find the following line: "authLevel": "function" and change the authLevel to "anonymous" &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;--name&lt;/em&gt; is the name of your Deployment. &lt;em&gt;--registry&lt;/em&gt; points to your DockerHub registry and you have to be logged in to docker and connected to your account locally. See more &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-kubernetes-keda#deploying-a-function-app-to-kubernetes" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Instead of using a function app you can deploy your own app that listens to Http requests. Just make sure you create a k8s Cluster IP Service pointing to your deployment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy an Ingress Resource pointing to the deployed function app Service.&lt;br&gt;&lt;br&gt;
This is how the YAML looks like:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;apiVersion: extensions/v1beta1&lt;/span&gt;
&lt;span class="s"&gt;kind: Ingress&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="s"&gt;  name: function-helloworld&lt;/span&gt;
&lt;span class="s"&gt;  namespace: ingress-nginx&lt;/span&gt;
&lt;span class="na"&gt;  annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="s"&gt;    kubernetes.io/ingress.class: nginx&lt;/span&gt;
&lt;span class="s"&gt;    nginx.ingress.kubernetes.io/rewrite-target: /$2    &lt;/span&gt;
&lt;span class="s"&gt;spec:  &lt;/span&gt;
&lt;span class="s"&gt;  rules:  &lt;/span&gt;
&lt;span class="s"&gt;    - host: &amp;lt;replace-with-host-name-pointing-to-ingress-controller&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;      http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="s"&gt;        paths:                &lt;/span&gt;
&lt;span class="na"&gt;        - backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="s"&gt;            serviceName: function-helloworld-http&lt;/span&gt;
&lt;span class="s"&gt;            servicePort: 80&lt;/span&gt;
&lt;span class="s"&gt;          path: /helloworld(/|$)(.*)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;You can find an example &lt;a href="https://github.com/anirudhgarg/azurefunction-k8s-http/blob/master/functionapp-ingress.yml" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;serviceName&lt;/em&gt; attribute is the name of the Service for the function app. &lt;em&gt;host&lt;/em&gt; should point to the fqdn configured pointing to the Ingress Controller. You can also choose a random name here but a host &lt;em&gt;has&lt;/em&gt; to be configured otherwise Prometheus monitoring of the Ingress Resource will not work. A &lt;em&gt;path&lt;/em&gt; has also been configured with prefix "helloworld".&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create an Ingress Resource with NGINX Ingress Controller annotations pointing to the Prometheus Service&lt;br&gt;&lt;br&gt;
This is how the YAML looks like:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;apiVersion: extensions/v1beta1&lt;/span&gt;
&lt;span class="s"&gt;kind: Ingress&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="s"&gt;  name: prometheus-service&lt;/span&gt;
&lt;span class="s"&gt;  namespace: ingress-nginx&lt;/span&gt;
&lt;span class="na"&gt;  annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="s"&gt;    kubernetes.io/ingress.class: nginx    &lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="s"&gt;  rules:  &lt;/span&gt;
&lt;span class="na"&gt;    - http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;        paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;        - backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="s"&gt;            serviceName: prometheus-server&lt;/span&gt;
&lt;span class="s"&gt;            servicePort: 9090&lt;/span&gt;
&lt;span class="s"&gt;          path: /&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &lt;em&gt;serviceName&lt;/em&gt; attribute is the name of the Service for the Promtheus Server.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f "https://raw.githubusercontent.com/anirudhgarg/azurefunction-k8s-http/master/prom-ingress.yml"    
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy the KEDA Prometheus Scaled object which inturn monitors the NGINX Ingress Controller&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f "https://raw.githubusercontent.com/anirudhgarg/azurefunction-k8s-http/master/keda-prom.yml"    
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This is how the YAML looks like:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;keda.k8s.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ScaledObject&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus-scaledobject&lt;/span&gt;
&lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingress-nginx&lt;/span&gt;
&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;deploymentName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;function-helloworld-http&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;deploymentName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;function-helloworld-http&lt;/span&gt;
&lt;span class="na"&gt;pollingInterval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;
&lt;span class="na"&gt;cooldownPeriod&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;30&lt;/span&gt;
&lt;span class="na"&gt;minReplicaCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;maxReplicaCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;span class="na"&gt;triggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus&lt;/span&gt;
  &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;serverAddress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://prometheus-server.ingress-nginx.svc.cluster.local:9090&lt;/span&gt;
    &lt;span class="na"&gt;metricName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;access_frequency&lt;/span&gt;
    &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1'&lt;/span&gt;
    &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sum(rate(nginx_ingress_controller_requests[1m]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;em&gt;deploymentName&lt;/em&gt; is the name of the function app Deployment, the &lt;em&gt;pollingInterval&lt;/em&gt; is how frequently in seconds does KEDA poll Prometheus, we have a minimum of 1 pod (&lt;em&gt;minReplicaCount&lt;/em&gt;) and the maximum scale out is 10 pods (&lt;em&gt;maxReplicaCount&lt;/em&gt;). &lt;em&gt;query&lt;/em&gt; is pointing to the prometheus query which tracks the metrics to incoming requests to the ingress controller in the last minute. Since the &lt;em&gt;threshold&lt;/em&gt; is '1' the function app will scale as long as the number of requests/minute &amp;gt; 60.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test ! &lt;br&gt;
The function app is now listening on:&lt;br&gt;
&lt;a href="http://function-helloworld.eastus2.cloudapp.azure.com/helloworld/api/helloworld?name=anirudh" rel="noopener noreferrer"&gt;http://function-helloworld.eastus2.cloudapp.azure.com/helloworld/api/helloworld?name=anirudh&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that if you did not create a domain name pointing to your Ingress Controller then you might need to use curl --resolve or its equivalent to invoke the function app&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```
 curl -v function-helloworld.eastus2.cloudapp.azure.com/helloworld/api/helloworld?name=anirudh
* Trying 40.70.230.199...
* TCP_NODELAY set
* Connected to function-helloworld.eastus2.cloudapp.azure.com (40.70.230.199) port 80 (#0)
&amp;gt; GET /helloworld/api/helloworld?name=anirudh HTTP/1.1
&amp;gt; Host: function-helloworld.eastus2.cloudapp.azure.com
&amp;gt; User-Agent: curl/7.55.1
&amp;gt; Accept: */*
&amp;gt;
&amp;lt; HTTP/1.1 200 OK
&amp;lt; Server: openresty/1.15.8.2
&amp;lt; Date: Mon, 13 Jan 2020 01:47:30 GMT
&amp;lt; Content-Type: text/plain; charset=utf-8
&amp;lt; Content-Length: 14
&amp;lt; Connection: keep-alive
&amp;lt;
Hello anirudh!* Connection #0 to host function-helloworld.eastus2.cloudapp.azure.com left intact
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can use your favorite Http requests tool and send requests at a high enough rate to triger the scale out. (I used a tool called &lt;a href="https://k6.io/" rel="noopener noreferrer"&gt;k6&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```
kubectl -n ingress-nginx get pods
NAME                                                              READY   STATUS              RESTARTS   AGE
function-helloworld-http-6ccd9c9bbf-6f6d7                         0/1     ContainerCreating   0          0s
function-helloworld-http-6ccd9c9bbf-98bzq                         1/1     Running             0          15s
function-helloworld-http-6ccd9c9bbf-dcdwc                         0/1     ContainerCreating   0          0s
function-helloworld-http-6ccd9c9bbf-fr7hq                         0/1     ContainerCreating   0          0s
function-helloworld-http-6ccd9c9bbf-k9lhn                         1/1     Running             0          6d20h
function-helloworld-http-6ccd9c9bbf-mfp4c                         1/1     Running             0          15s
function-helloworld-http-6ccd9c9bbf-v7g47                         0/1     ContainerCreating   0          0s
function-helloworld-http-6ccd9c9bbf-x9l2t                         1/1     Running             0          15s
ingress-controller-nginx-ingress-controller-6c9f7486d4-27vjq      1/1     Running             0          7d1h
ingress-controller-nginx-ingress-controller-6c9f7486d4-b8ddr      1/1     Running             0          7d1h
ingress-controller-nginx-ingress-default-backend-df57464f-lvqmj   1/1     Running             0          7d1h
keda-operator-697b98dcdd-8zdrk                                    2/2     Running             0          6d18h
prometheus-server-86cd54f9d5-9xxh7                                1/1     Running             0          7d1h
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a while if there are no further requests the function pods will scale back down to 1. Note that we are only scaling down to 1 here. &lt;/p&gt;

&lt;p&gt;Hope you found this useful. Please try it out and let me know in the comments or send me a &lt;a href="https://twitter.com/anirudhgarg" rel="noopener noreferrer"&gt;tweet&lt;/a&gt; if this approach worked for you or not. We are looking to streamline this process further as we go forward. &lt;/p&gt;

&lt;p&gt;Acknowledgments for inspiration -  &lt;a href="https://itnext.io/tutorial-auto-scale-your-kubernetes-apps-with-prometheus-and-keda-c6ea460e4642" rel="noopener noreferrer"&gt;Autoscaling Kubernetes apps with Prometheus and KEDA&lt;/a&gt; post by Abhishek Gupta, and to &lt;a href="https://docs.openfaas.com/architecture/autoscaling/#scaling-by-requests-per-second" rel="noopener noreferrer"&gt;OpenFaaS&lt;/a&gt; which also uses Prometheus metrics for request based scaling. &lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>azure</category>
      <category>serverless</category>
      <category>functions</category>
    </item>
  </channel>
</rss>
