Serverless

Overview

Lambdas or lambda functions are small functions that run in Kyma in a cost-efficient and scalable way using JavaScript in Node.js. As the following diagram shows, these functions enable the linking of a wide range of functionalities using Kyma.

Kyma connected to other products through Lambda functions

This is an example lambda function:

def myfunction (event, context):
  print event
  return event['data']

The use of lambdas in Kyma addresses several scenarios:

  • Create and manage lambda functions
  • Trigger functions based on business Events
  • Expose functions through HTTP
  • Consume services
  • Provide customers with customized features
  • Version lambda functions
  • Chain multiple functions

Lambda functions best serve integration purposes due to their ease of use. Lambda is a quick and ideal solution when the goal is to combine functionalities which are tightly coupled. And, in the context of Kyma, they provide integration with the Event system and Customer Engagement and Commerce tools. Lambda functions are not well-suited to building an application from scratch.

The Serverless implementation of Kyma is based on Kubeless.

Custom Resources

Kubeless uses custom resource definitions (CRD) to:

  • define the information required for the configuration of custom resources
  • create functions
  • create objects

The function CRD ships by default with Kubeless.

See the content of the kubeless-crd.yaml file:

apiVersion: apiextensions.k8s.io/v1beta1
description: Kubernetes Native Serverless Framework
kind: CustomResourceDefinition
metadata:
  name: {{ .Values.function.customResourceDefinition.metadata.name | quote }}
  labels:
{{ include "labels.standard" . | indent 4 }}
spec:
  group: {{ .Values.function.customResourceDefinition.spec.group | quote }}
  names:
    kind: {{ .Values.function.customResourceDefinition.names.kind | quote }}
    plural: {{ .Values.function.customResourceDefinition.names.plural | quote }}
    singular: {{ .Values.function.customResourceDefinition.names.singular | quote }}
  scope: Namespaced
  version: v1beta1

Use the .yaml file to create the custom resource using the following command:

kubectl create -f <filename>

Kubeless creates a new namespaced endpoint that you can use to create and manage custom objects. Learn how to use CRDs to create objects in the Kubeless documentation on the Kubeless website.

Managing Lambdas

Kubernetes provides Kyma with labels that allow you to arrange lambda functions and group them. Labeling also makes it possible to filter lambdas functions. This functionality is particularly useful when a developer needs to manage a large set of lambda functions.

Behind the scenes, labeling takes place in the form of key value pairs. Here is an example of code that enhances a function:

"labels": {
  "key1" : "value1",
  "key2" : "value2"
}

For more details on labels and selectors, visit the Kubernetes website.

The Node.js Programming Model

Kyma supports Node.js 6 and 8. The function interface is the same for both versions. It is still best practice to start with Node.js 8, as it supports Promises out of the box. The result is less complicated code.

Please set the runtime version (Node.js 6 or 8) while creating a function.

In the next sections, we will describe how the system creates Node.js functions.

The Handler

The system uses module.exports to export Node.js handlers. A handler represents the function code executed during invocation. You have to define the handler using the command line. The Console UI only supports main as a handler name.

module.exports = { main: function (event, context) {
    return
} }

Kyma supports two execution types: Request / Response (HTTP) and Events. In both types, a return identifies a successful execution of the function. For event types, the event is reinjected as long as the execution is not successful. Functions of the Request Response type can return data to the requesting entity. The following three options are available:

Return Content Type HTTP Status Response
return none 200 (OK) -
return "Hello World!" none 200 (OK) Hello World!
return {foo: "BAR"} application/json 200 (OK) {"foo":"BAR"}

A failing function simply throws an error to tell the event service to reinject the event at a later point. An HTTP-based function returns an HTTP 500 status.

The Event Object and Context Object

The function retrieves two parameters: Event and Context.

event:
  data:                                         # Event data
    foo: "bar"                                  # The data is parsed as JSON when required
  extensions:                                   # Optional parameters
    request: ...                                # Reference to the request received
    response: ...                               # Reference to the response to send
                                                # (specific properties will depend on the function language)
context:
    function-name: "pubsub-nodejs"
    timeout: "180"
    runtime: "nodejs6"
    memory-limit: "128M"

The Event contains the event payload as well as some request specific metadata. The request and response attributes are primarily responsible for providing control over http behavior.

Advanced Response Handling

To enable more advanced implementations, the system forwards Node.js Request and Response objects to the function. Access the objects using event.extensions.<request|response>.

In the example, a custom HTTP response is set.

module.exports = { main: function (event, context) {
    console.log(event.extensions.request.originalUrl)
    event.extensions.response.status(404).send("Arg....")
} }

The example code logs the original request url. The response is an HTTP 404. The body is Arg.....

Logging

Logging is based on standard Node.js functionality. console.log("Hello") sends "Hello" to the logs. As there is no graphical log tool available, use the command kubectl to display the logs.

$ kubectl logs -n <environment> -l function=<function> -c <function>

Architecture

The term "serverless" refers to an architecture that is Internet-based. Application development that uses serverless technology relies solely on a combination of cloud-based, third-party services, client-side logic, and service-hosted remote procedure calls, also known as "Functions as a Service" or FaaS. Developers use lambdas to create this combination. As a result, this combination replaces the common use of a server. In the context of Kyma, lambda functions connect third-party services and Kyma. Developing with this serverless approach reduces the implementation and operation effort of an application to the absolute minimum.

The Serverless architecture

The following diagram illustrates a generic serverless implementation.

General serverless architecture

The application flow takes place on the client side. Third parties handle the infrastructural logic. Custom logic can process updates and encapsulate databases. Authentication is an example of custom logic. Third parties can also handle business logic. A hosted database contains read-only data that the client reads. None of this functionality runs on a single, central server. Instead, the client relies on FaaS as its resource.

The following diagram shows an example of tasks that lambdas can perform in Kyma after a user invokes them.

Lambdas in Kyma

First, the user invokes the exposed lambda endpoint. Then, the lambda function can carry out a number of tasks, such as:

  • Retrieving cart information from Enterprise Commerce
  • Retrieving stock details
  • Updating a database

Open source components

Kyma is comprised of several open source technologies to provide extensive functionality.

Kubeless

Kubeless is the serverless framework integrated into Kyma that allows you to deploy lambda functions. These functions run in Pods inside the Kubeless controller on a node, which can be a virtual or hardware machine.

Kubeless also has a command line interface. Use Node.js to create lambda functions.

Istio

Istio is a third-party component that makes it possible to expose and consume services in Kyma. See the Istio documentation to learn more. Istio helps create a network of deployed services, called a service mesh.

In Kyma, functions run in Pods. Istio provides a proxy for specified pods that talk to a pilot. The pilot confirms whether access to the pod is permissible as per the request. In the diagram, Pod B requests access to Pod A. Pod A has an Istio proxy that contains a set of instructions on which services can access Pod A. The Istio proxy also notifies Pod A as to whether Pod B is a part of the service mesh. The Istio Proxy gets all of its information from the Pilot.

Istio architecture

NATS

The Event Bus in Kyma monitors business events and trigger functions based on those events. At the heart of the Event Bus is NATS, an open source, stand-alone messaging system. To learn more about NATS, visit the NATS website.

The following diagram demonstrates the Event Bus architecture.

Event Bus architecture

The Event Bus exposes an HTTP endpoint that the system can consume. An external event, such as a subscription, triggers the Event Bus. A lambda function works with a push notification, and the subscription handling of the Event Bus processes the notification.

CLI reference

This section provides you with useful command line examples used in Kyma.

Prerequisites

To develop, deploy, or run functions directly download these tools additionally:

Set the cluster domain variable

The commands throughout this guide use URLs that require you to provide the domain of the cluster which you are using. To complete this configuration, set the variable yourClusterDomain to the domain of your cluster.

For example if your cluster's domain is 'demo.cluster.kyma.cx' then run the following command:

   export yourClusterDomain='demo.cluster.kyma.cx'

Details

Use the command line to create, call, deploy, expose, and bind a function.

Deploy a function using a yaml file and kubectl

You can use the Kubeless CLI to deploy functions in Kyma.

$ kubectl apply -f https://minio.$yourClusterDomain/content/components/serverless/assets/deployment.yaml

Check if the function is available:

$ kubeless function list hello

Deploy a function using a JS file and the Kubeless CLI

You can deploy a function using the Kubernetes and Kubeless CLI. See the following example:

$ kubeless function deploy hello --runtime nodejs8 --handler hello.main --from-file https://minio.$yourClusterDomain/content/components/serverless/assets/hello.js --trigger-http

Call a function using the CLI

Use the CLI to call a function:

$ kubeless function call hello

Expose a function without authentication

Use the CLI to create an API for your function:

$ kubectl apply -f https://minio.$yourClusterDomain/content/components/serverless/assets/api-without-auth.yaml

Expose a function with authentication enabled

If your function is deployed to a cluster run:

 curl -k https://minio.$yourClusterDomain/content/components/serverless/assets/api-with-auth.yaml | sed "s/.kyma.local/.$yourClusterDomain/" | kubectl apply -f -

If Kyma is running locally, add hello.kyma.local mapped to minikube ip to /etc/hosts

$ echo "$(minikube ip) hello.kyma.local" | sudo tee -a /etc/hosts

Create the API for your function:

kubectl apply -f https://minio.$yourClusterDomain/content/components/serverless/assets/api-with-auth.yaml

Bind a function to events

You can bind the function to Kyma and to third-party services. For details, refer to the Service Catalog documentation.