At Banzai Cloud we’re always looking for products or frameworks that add value to our business, which we can enable in our open source PaaS, Pipeline. Any list of such products would include serverless frameworks. Thus, today we’re adding Fn as a supported spotguide, making it easy for users to deploy Fn with Pipeline on their chosen cloud provider.
Before we dive into how to deploy and use Fn with Pipeline, here are a few reasons why we thought Fn should be supported by Pipeline:
- It runs on Kubernetes, and consequently leverages all the container orchestration provided by Kubernetes. More to the point, cloud providers have started to offer
managed Kubernetes
services, which means that applications running onKubernetes
are cloud provider agnostic. At the same time, we’ve retained the ability to run Kubernetes on-premise. - It’s open source.
- It makes the development/testing/deployment of serverless functions easy and straightforward, thus increases productivity.
- It’s Extensible (see writing extensions), allowing us to customize it as needed.
- It supports advanced function flows.
- And it can be monitored with Prometheus
Deploy Fn with Pipeline 🔗︎
We need a Kubernetes cluster to deploy Fn
onto. With Pipeline, it’s easy to spin up Kubernetes clusters on various cloud providers by launching the control plane launcher, then using the create cluster REST API calls.
Note: Pipeline is quickly moving towards a hosted PaaS model wherein all the steps below will be unnecessary, since provisioning the control plane, supported applications or frameworks, will be automated and streamlined. We use managed Kubernetes services (actually, we believe that the future is in managed k8s services deployed to the cloud), and are constantly looking to integrate new services alongside those we already support.
Look for the Deployment Create
API call in this Postman collection. To invoke Deployment Create
API we need to first provide two parameters:
-
cluster id - this identifies the desired Kubernetes cluster from the list of Kubernetes clusters Pipeline manages. (To see the list of Kubernetes clusters managed by Pipeline, invoke the
Cluster List
REST API call). -
REST call body:
{ "name": "banzaicloud-stable/fn" }
Those who prefer to deploy
Fn
manually can do so by using our Fn helm chart, which Pipeline uses behind the scenes.
The returned response contains:
-
release_name - this is the relase name by which the
Fn
components can be identified in Kubernetes -
notes - this is useful information regarding how to access the
Fn
service in Kubernetes
Here’s an example output from a deployment to Kubernetes:
{
"release_name": "early-dingo",
"notes": "The Fn service can be accessed within your cluster at:\n\n - http://early-dingo-fn-api.default:80\n\nSet the FN_API_URL environment variable to this address to use the Fn service from outside the cluster:\n\n!! NOTE: It may take a few minutes for the API load balancer to become available.\n\nYou can watch for EXTERNAL-IP to populate by running:\n\n kubectl get svc --namespace default -w early-dingo-fn-api\n\nThen set\n\n export FN_API_URL=http://$(kubectl get svc --namespace default early-dingo-fn-api -o jsonpath='{.status.loadBalancer.ingress[0].ip}'):80\n\n############################################################################\n### WARNING: Persistence is disabled!!! You will lose function and ###\n### flow state when the MySQL pod is terminated. ###\n### See the README.md for instructions on configuring persistence. ###\n############################################################################\n"
}
The following diagram is a high level depiction of the above deployment flow:
Execute the Cluster Public Endpoints
REST API call to Pipeline in order to get a list of services than can be reached from outside the Kubernetes cluster. From the returned list, the following public endpoints belong to the deployed Fn
:
Name | Host | Ports | Description |
---|---|---|---|
<fn-release-name> -fn-api |
The public IP or DNS Hostname of the endpoint | fn:80 | This is the ‘Fn’ API endpoint |
<fn-release-name> -fn-ui |
The public IP or DNS Hostname of the endpoint | fn-ui:80, flow-ui:3000 | This is the ‘UI’ endpoint. The Fn UI is available on port 80, while the Fn Flow UI on is 3000 |
Once Fn
is up and running, you can start using it via the Fn cli tool. All that you need is to point the Fn cli tool
to the API endpoint of the Fn
framework you just deployed.
$ export FN_API_URL=http://<the `Host` listed for <fn-release-name>-fn-api/
Now that we have an Fn
framework up and running, it’s time for some fun. Let’s see if we can deploy this Fn Flow Tutorial example to our serverless framework.
This example application requires an external component, a fake SDK dashboard, which the serverless functions of the application can talk to.
- The
fake SDK dashboard
exists outside the serverless framework, so we need to deploy it separately. Let’s deploy it to our Kubernetes cluster and expose it through a service, so as to make it reachable from the outside:
$ kubectl run bristol --image=tteggel/bristol --port=3001
$ kubectl create -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: bristol-svc
namespace: default
spec:
ports:
- name: bristol
port: 80
protocol: TCP
targetPort: 3001
selector:
run: bristol
sessionAffinity: None
type: LoadBalancer
EOF
Once the service is up, get its public IP (we’ll refer to this as public-ip-of-fake-dashboard
from here on in) from Kubernetes. This is the IP through which the fake SDK dashboard
is reachable.
-
In order to deploy our serverless functions, first, we need to run
docker login
. This is necessary, becauseFn
generates docker images from our serverless functions and uploads them to dockerhub. -
Deploy the application to the serverless framework
$ cd FlowSaga
$ fn deploy --all --registry <your dockerhub registry name>
This example application consists of multiple serverless functions which form a fn workflow.
- Verify the deployment
$ fn routes list travel
path image endpoint
/car/book <your-dockerhub-registry-name>/car-book:0.0.107 `<fn-release-name>`-fn-api host/r/travel/car/book
/car/cancel <your-dockerhub-registry-name>/car-cancel:0.0.91 `<fn-release-name>`-fn-api host/r/travel/car/cancel
/email <your-dockerhub-registry-name>/email:0.0.95 `<fn-release-name>`-fn-api host/r/travel/email
/flight/book <your-dockerhub-registry-name>/flight-book:0.0.67 `<fn-release-name>`-fn-api host/r/travel/flight/book
/flight/cancel <your-dockerhub-registry-name>/flight-cancel:0.0.117 `<fn-release-name>`-fn-api host/r/travel/flight/cancel
/hotel/book <your-dockerhub-registry-name>/hotel-book:0.0.89 `<fn-release-name>`-fn-api host/r/travel/hotel/book
/hotel/cancel <your-dockerhub-registry-name>/hotel-cancel:0.0.87 `<fn-release-name>`-fn-api host/r/travel/hotel/cancel
/trip <your-dockerhub-registry-name>/trip:0.0.230 `<fn-release-name>`-fn-api host/r/travel/trip
- Configure the deployed application
$ fn apps config set travel COMPLETER_BASE_URL "http://<fn-kubernetes-deployment-name>-fn-flow"
$ fn routes config set travel /flight/book FLIGHT_API_URL "http://<public-ip-of-fake-dashboard>/flight"
$ fn routes config set travel /flight/book FLIGHT_API_SECRET "shhhh"
$ fn routes config set travel /flight/cancel FLIGHT_API_URL "http://<public-ip-of-fake-dashboard>/flight"
$ fn routes config set travel /flight/cancel FLIGHT_API_SECRET "shhhh"
$ fn routes config set travel /hotel/book HOTEL_API_URL "http://<public-ip-of-fake-dashboard>/hotel"
$ fn routes config set travel /hotel/cancel HOTEL_API_URL "http://<public-ip-of-fake-dashboard>/hotel"
$ fn routes config set travel /car/book CAR_API_URL "http://<public-ip-of-fake-dashboard>/car"
$ fn routes config set travel /car/cancel CAR_API_URL "http://<public-ip-of-fake-dashboard>/car"
$ fn routes config set travel /email EMAIL_API_URL "http://<public-ip-of-fake-dashboard>/email"
- Trigger the application
Now that it’s been deployed and configured, we can pass the input payload to the application. Since this application is a flow of serverless functions, we’ll see multiple functions being executed.
$ cd trip
$ fn call travel /trip < sample-payload.json
- Visualize the application’s execution
- Fn UI is available at: http://
<fn-release-name>-fn-ui
/ - Fn Flow UI is available at: http://
<fn-release-name>-fn-ui
:3000/
- Fn UI is available at: http://
Monitoring 🔗︎
Pipeline provides out-of-the-box node and platform/Kubernetes metrics for monitoring purposes through Prometheus. Deploying these is as simple as invoking and passing the following to the Deployment Create
API:
{
"name": "banzaicloud-stable/pipeline-cluster-monitor"
}
Fn
provides application level metrics that can be consumed by Prometheus.
With federated monitoring, metrics collected by Prometheus instances (that are hosted on Kubernetes clusters managed by Pipeline) are exposed through a central Grafana, reachedable at http://<pipeline public ip>/grafana
.
Integration with Hollowtrees 🔗︎
Hollowtrees is an alert/react-based framework that’s part of the Pipeline PaaS
. It coordinates monitoring, applies rules, and dispatches action chains to plugins using standard CNCF interfaces. If you’d like to learn more about Hollowtrees
check out this post.
Until now, Hollowtrees has only supported microservices, listening on a gRPC interface, as action plugins. This is suboptimal in some use cases, since the action plugin
may unnecessarily burn CPU resources while the action plugin sits idle.
So we’ve decided to extend Hollowtrees
to support Fn functions as action plugins
. This helps cost efficiency because action plugins
are only triggered when there’s an event to handle, exiting once the event has been processed instead of continuously running. The diagram below shows how the Hollowtrees architecture changes when using Fn to react to alerts, as opposed to gRPC-based action plugins.
That brings us to the end of this post. In our next entry in the serverless series we’ll discuss writing action plugins
as serverless functions, as well as some changes we’re proposing and contributing in order to make Fn
more robust on Kubernetes.