Shubham Seth
Mar 30, 2024

Knative: build Serverless and Event Driven Applications

Introduction:

Knative is an open-source framework launched to bridge the gap between the containerized and serverless applications among cloud providers. It was developed in 2018 and supported by a group of companies that worked together (Google, IBM, Pivotal, Red Hat, and SAP) to help Kubernetes run microservices and efficiently handle serverless applications.

Knative consists of two separate projects:

Knative Serving: For running stateless HTTP-based applications, such as microservices, Knative Serving can fully replace Kubernetes, and add benefits like:

Knative Eventing: Lets you program Kubernetes APIs declaratively to subscribe to event sources and filter/dispatch events to targets (like other Kubernetes or Knative applications in the same cluster).

This post mainly focuses on Knative Serving.

What can be run on Knative:

Contrary to Kubernetes, the Knative Serving stack is a lot less flexible in terms of apps you can run on it.

In a nutshell, Knative Serving is good for running “serverless containers”;

Only server applications that run on a port number.

Only stateless applications can be supported. Knative will scale up the instance count, or terminate instances for scale-down

Applications that can be built into an OCI container image (e.g. docker image).

    ⁠Deploying an application:

Knative supports 3 service mesh

For this demo we will be running Istio.

First we need a cluster on which we are going to install Knative and deploy an application for cluster we can use any cloud provider which provide a cluster with Kubernetes installed or we can try it on local cluster.

To create a local cluster we need KinD installed locally

⁠To install KinD follow this documentation.

Follow the below steps on cmd/git-bash/windows terminal

Step I: kind create cluster

Step II: kind get clusters (This will give us a cluster name as kind as output)

Step III: check if Kubernetes and Docker installed in your system (If not installed can follow official documentation of docker and after installation of docker open docker desktop and enable Kubernetes from settings)

Step IV:

kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.6.0/serving-crds.yaml

Step V:

kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.6.0/serving-core.yaml

Step VI:

kubectl apply -l knative.dev/crd-install=true -f https://github.com/knative/net-istio/releases/download/knative-v1.6.0/istio.yaml

Step VII:

kubectl apply -f https://github.com/knative/net-istio/releases/download/knative-v1.6.0/istio.yaml

StepVIII:

kubectl apply -f https://github.com/knative/net-istio/releases/download/knative-v1.6.0/net-istio.yaml

Step IX:

kubectl --namespace istio-system get service istio-ingressgateway

Step X: Verify the installation using

kubectl get pods -n knative-serving

Step XI: This step is only applicable if you have external IP on above output.

kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.6.0/serving-default-domain.yaml

Step XII:

kubectl apply -f https://github.com/knative/net-http01/releases/download/knative-v1.6.0/release.yaml

Step XIII:

kubectl patch configmap/config-network --namespace knative-serving --type merge --patch '{"data":{"certificate-class":"net-http01.certificate.networking.knative.dev"}}'

Step XIV:

kubectl patch configmap/config-network --namespace knative-serving --type merge --patch '{"data":{"auto-tls":"Enabled"}}'

After completion all the steps above we now have a Kubernetes cluster with Knative installed and configured. To deploy an application we can either make our own project or we can download the code examples of Knative from https://knative.dev/docs/samples/serving/ and deploy it.

After creating or downloading a project we need to create a docker image of our project and push it to a public or private repository.

If we push image to private repository we need to create a Kubernetes secret else we will get error image cant be download.

Secret can be made using:

kubectl create secret docker-registry <registry-credential-secrets> \

--docker-server=<private-registry-url> \

--docker-email=<private-registry-email> \

--docker-username=<private-registry-user> \

--docker-password=<private-registry-password> 

kubectl patch serviceaccount default -p "{\"imagePullSecrets\": [{\"name\": \" registry-credential-secrets \"}]}"

Now to push the image we need to login in our terminal with proper credentials depending upon the container service there are different command to push image. For example lets understand if we create repository on docker hub. We login we will use docker login and it will ask us our username and password and it will show login successful if the credentials are correct.

Now to push docker image we need to tag our docker image:

docker tag localImageName:tag server.containerRegistryName/imageName

here lcoalImageName and server.containerRegistryName/imageName will be changed according to user.

docker push server.containerRegistryName/imageName

now if the docker image is successfully pushed we can deploy the image using Knative.

To deploy using Knative we need to create a yaml file like this:

apiVersion: serving.knative.dev/v1 # Current version of Knative

kind: Service

metadata:

  name: knative-springboot-shubham # The name of the app

  namespace: default # The namespace the app will use

spec:

  template:

    spec:

      containers:

        - image: shubham/knative-test:springboot-knative-comparision

          imagePullPolicy: Always

here name in metadata can be changed with whatever the user want to name its service and image will be set with proper server name, image name and tag.

To deploy our first service we need to go to the same directory as our yaml file and execute command kubectl apply -f service.yaml here service.yaml is the name of the file.

After some time we will get the output as

Where ready = true.

If we are using a cluster which has a external IP assigned to it then we will have the url will have externalIp.sslip.io instead of example.com and we can hit the url and get the try our function but as currently we are using local cluster we don’t have a external IP so if we need to test our service what will do is port-forwarding and we will be able to hit our URL on 127.0.0.1 so to forward port we will use

⁠kubectl port-forward -n istio-system svc/istio-ingressgateway 8080:80 
⁠and now we can execute the service using
⁠curl -H "Host: knative-springboot-shubham.default.example.com" http://127.0.0.1:8080 
⁠and this will show us our output and we can save the output in a file if we want using > filename.txt/json.

Above we have a simple HelloWorld application running locally.

Every Knative deployment is a revision. Revision is a snapshot of a Knative service. If we change the image or any configuration which we need like min pods scale or pods memory or CPU and redeploy our service using same command as above a new revision will be created and all the traffic will be redirected to new revision this doesn’t change the URL of the service. We can also manage the traffic which will be sent to which revision if there are no many changes we have done we can divide the traffic into 2 revisions.

Deploying using serverless has its own issue like there will be a cold start time which will be taken before execution of the request.

We can save this by always having a pod ready. This can be done using.

spec:

  template:

    metadata:

        annotations:

          autoscaling.knative.dev/minScale: "1"

    spec:

      containers:

        - image: shubham/knative-test:springboot-knative-comparision

          imagePullPolicy: Always

Knative also provide a backpressure handling like by default 100 concurrent request can be handled by one pods at a time and if the request are higher the request will not error out but Knative will store it and wait till new pod is created and then transfer the request to newly created pod.

spec:

  template:

    metadata:

        annotations:

          autoscaling.knative.dev/minScale: "1"

    spec:

      containerConcurrency: 20

      containers:

        - image: shubham/knative-test:springboot-knative-comparision

          imagePullPolicy: Always

By using the containerConcurrency key we have set the configuration to only process 20 request at a time.

To give an overview of what happens when we apply a new yaml or redploy a yaml using create command

 A configuration is created

     A Route which

These are all done asynchronously.

More about the architecture can be learned from Knative docs.

For More Info can also refer:

For problems in Installation

Shubham Seth

Shubham Seth

A software engineer curious about everything in the world of Javascript 🚀

Leave a Reply

Related Posts

Categories