Building functions with Knative and Tekton

Shashank Sharma - Apr 18 '22 - - Dev Community

Knative was recently accepted as a CNCF incubation project and there are so many exciting things about it(!), one of them being the evolution and adoption of its components. Through this blog, we will be looking at one such component - func plugin; creating a function in go runtime in our local machine and then pushing it to a github repository and finally initiating its deployment. Once the function is deployed, we will be provided with a URL through which we can access it.

The expectation out of this is for a developer to get as comfortable as possible with writing functions, and essentially reach a point where they no longer have to worry about low level k8s resources (and ops in general). This would also mean that to run our code in a k8s cluster, we'd essentially need to run just one command.

Prerequisites

A v1.21 k8s cluster or later versions. It is possible to run this blog on older versions, but for that, knative and tekton versions will have to be installed accordingly - check their releases for more details.
Warning: This blog requires administrator privileges on the k8s cluster, and the function builds happen on privileged containers.

Installing Knative and Tekton

Check that both Knative Serving and Tekton Pipelines components are running by checking the status of pods in knative-serving and tekton-pipelines namespaces.

Writing the function

Following command will create a local repository kcd-chennai containing the function signature in handle.go and the function configuration parameters in func.yaml.

$ func create -l go kcd-chennai
Created go Function in /home/shashank/kcd-chennai
$ ls
func.yaml  go.mod  handle.go  handle_test.go  README.md
Enter fullscreen mode Exit fullscreen mode

Now we can edit the handle.go file to add our custom code like this:

package function

import (
        "context"
        "fmt"
        "net/http"
)

// Handle an HTTP Request.
func Handle(ctx context.Context, res http.ResponseWriter, req *http.Request) {
        fmt.Println("received a request")       
        fmt.Fprintln(res, "Hello from KCD Chennai! Read more about us here: https://community.cncf.io/events/details/cncf-kcd-chennai-presents-kubernetes-community-days-chennai-2022/") // Send KCD community link back to the client
}
Enter fullscreen mode Exit fullscreen mode

Info: Notice that we didnt have to write most of the go code that we'd usually write, we simply just added our business logic.
This is an http template, but there is also a cloudevent template which is more relevant in the world of FaaS and serverless, but out of scope for this blog.

Building the function

Now we will see, how we can build this code and deploy it on kubernetes and successfully invoke it using a URL.

Building locally

We can run the following command:

$ func deploy
Enter fullscreen mode Exit fullscreen mode

Our function is now available on the URL http://kcd-chennai.default.example.com.
To access this URL from outside the k8s cluster, ideally we'd need the kourier service in kourier-system namespace to have a discoverable ExternalIP, but for this blog we can try to hit the function URL from within the cluster using the following two commands:

export ingressIP=$(kubectl get svc kourier --namespace kourier-system -ojsonpath='{.spec.clusterIP}')
curl $ingressIP -H "Host: kcd-chennai.default.example.com"
Enter fullscreen mode Exit fullscreen mode

Info: It's possible to configure the hostname of this function to a custom value, or to even explicitly make the function private to our cluster and then access it using http://kcd-chennai.default.svc.cluster.local (we can also use this URL to access the function instead of the above 2 commands).

Building from github repo on-cluster

To do this, we'd need to push our local code to a github repo and create some tekton resources as describe below, tekton being a cloud native CICD system, will use those resources to run a pipeline for things like - cloning our code, building it and then deploying the function.
Warning: We'd need persistent volume claims to be working in our cluster, since the code will be cloned in there.

For tekton to do its job, we need to run following commands:

Next we have to change the configuration in func.yaml to look like this:

build: git
git:
  url: https://github.com/Shashankft9/kcd-chennai.git
  revision: master
Enter fullscreen mode Exit fullscreen mode

Now, run the following command:

$ func deploy
Enter fullscreen mode Exit fullscreen mode

Follow the video below to see the progress of build and how we can access the function.
function build using tekton

Inherent function features from Knative

Since the functions are running with knative serving layer, it leverages some of the features listed below (non exhaustive):

  • autoscaling on the basis of rps/concurrency.
  • automatic ingress configuration, we use tls as well.
  • scale to and from zero by default.
  • can work with many languages like go, python, rust, node, springboot etc.
  • readiness and liveness probes configured automatically for functions.
  • no need to create service, deployment and other resource files with labels, ports etc.
  • easier and faster deployments.
  • prometheus metrics like http_requests_total with respective response codes are exposed.
  • traffic splitting, progressive rollouts available.
  • ability to handle unstable windows, sudden traffic bursts with scaling configuration.
  • easy integration with an event driven architecture because of the usage of cloudevents.
  • more secure deployments because function builds use Buildpacks under the hood.
  • by using Tekton for builds, we can easily configure the pipeline to add features like cloning code from a private github repo and more.

Things you can explore as a follow-up to get more comfortable with what we did in this blog:

If you got stuck at any of the steps in the blog or want to report any issues, feel free to ping me (Shashank Sharma) in the knative slack - thanks!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .