A few years ago we all built monolithic applications which where hard to deploy and maintain. Mostly they were pushed to some application server for hosting like IIS or JBoss. Currently everyone is doing micro-services and that often in combination with Docker for easy build and deployment, but the next big thing is right around the corner. Functions-as-a-Service (FaaS) is hot right now in the software development scene and that’s why we have a look at it today.
The idea behind functions is to do exactly one thing and that well. FaaS takes away the complexity of building, deploying and hosting such functions. Commercial vendors are already providing FaaS in their server-less offers. The most popular being Azure Functions and AWS Lambda.
But what if you want to run FaaS on premise on your own computer in your companies data center? This is where OpenFaaS comes into the play. OpenFaaS is an open-source function-as-a-service platform which runs on Docker. This means it easy to setup with Docker Swarm or Kubernetes.
In this blog post I’ll show how to setup OpenFaaS locally on your Windows machine with Docker for Windows and Kubernetes. The good thing about Docker for Windows is that it comes with Kubernetes preinstalled. You just need to enable it and your Kubernetes clusters runs.
Furthermore you need a Docker Hub account to push your Docker images to. Unfortunately Kubernetes does not use the local Docker repository on your computer to search for images.
Install OpenFaaS on Kubernetes
Installing OpenFaaS on a local Kubernetes cluster is pretty straight forward. Clone the repo and deploy to Kubernetes.
git clone https://github.com/openfaas/faas-netes kubectl apply -f https://raw.githubusercontent.com/openfaas/faas-netes/master/namespaces.yml cd faas-netes kubectl apply -f ./yaml
That’s it. Your OpenFaaS in running and ready to be used!
We can access the web UI of OpenFaaS with a browser. Since Kubernetes forwards the OpenFaaS on some random port, we need to get the port on which the service is listening.
kubectl get services --selector="app=gateway" --namespace openfaas
This should show some output like this:
Output: NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE gateway NodePort 10.111.109.152 8080:31112/TCP 22m
This tells us that OpenFaaS runs on localhost:31112. The UI is reachable under http://localhost:3112/ui.
Create a function in C#
Now, lets create a new function in C# with .Net Core. To do so, we need to download the OpenFaas CLI.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Invoke-WebRequest -Uri https://github.com/openfaas/faas-cli/releases/download/0.6.10/faas-cli.exe -OutFile faas-cli.exe
The function we want to build should return if a given string is a valid domain name. For example, given “google.com”, it should return “google.com is a valid domain name.” and for “google,com” (note the comma) it should return “google,com is not a valid domain name”.
First we create a new project from a template. The project name is valid-domain.
.\faas-cli.exe new --lang csharp valid-domain
After the operation completed, a folder valid-domain which contains a code template and a file valid-domain.yml are in our current directory.
Open the file .\valid-domain\FunctionHandler.cs. The class FunctionHandler contains a method Handle. This method is invoked, every time the function is requested. Change the content to the following.
using System; using System.Text; namespace Function { public class FunctionHandler { public void Handle(string input) { input = SanitizeInput(input); if(IsValidDomainName(input)) Console.WriteLine($"{input} is a valid domain name."); else Console.WriteLine($"{input} is not a valid domain name."); } private bool IsValidDomainName(string name) { return Uri.CheckHostName(name) != UriHostNameType.Unknown; } private string SanitizeInput(string input) { return input.Trim().Replace("\n", string.Empty).Replace("\r", string.Empty); } } }
The function SanitizeInput is necessary, because OpenFaaS adds non-printable characters to the input string. If these characters are evaluated in the IsValidDomainName function, it will always return false. That’s all the code we need.
Now edit the .\valid-domain.yml file to look like this:
provider: name: faas gateway: http://127.0.0.1:31112 functions: valid-domain: lang: csharp handler: ./valid-domain image: docker_hub_name/valid-domain
Replace the port of the gateway with the port where OpenFaaS is listening on your machine. Replace the image prefix with your Docker Hub account name.
The next step is to build the function. This creates a local Docker image called valid-domain.
.\faas-cli.exe build -f .\valid-domain.yml
As mentioned above, Kubernetes doesn’t use the local Docker repository, so we are forced to upload our function to a public one.
$env:DOCKER_ID_USER="docker_hub_username" docker login docker tag valid-domain $env:DOCKER_USER_ID/valid-domain docker push $env:DOCKER_USER_ID/valid-domain
When the image is pushed, we are ready to deploy the function to the local OpenFaaS instance.
.\faas-cli.exe deploy -f .\valid-domain.yml
If the operation was successful, we have to wait a bit until the function is ready to use. You can check the state in the web UI. If the function is ready, we can try it out in the UI.
It works! The function can be called over REST such that an easy invoke over PowerShell is possible.
(Invoke-WebRequest -Method Post -Uri http://localhost:31112/function/valid-domain -Body google.com).ToString() google.com is a valid domain name. (Invoke-WebRequest -Method Post -Uri http://localhost:31112/function/valid-domain -Body google,com).ToString() google com is not a valid domain name.
As we can see above, our function works as expected. You can wrap any command line tool that takes input from stdin and outputs to stdout as a function without touching the code!
Hi very interested in what you are doing here. When following along I get the following message when trying to retrieve the services with kubctl “No resources found”. Is there maybe a step missing in trying to get the openfaas service up and running in kube?
LikeLike
Here’s another C# handler, built with ASPNET Core 5. Gives you an HttpContext for better control, returns an IActionResult, allows method attributes, route templates and more.
https://github.com/redpandaltd/openfaas-csharp-http-template
LikeLike