Brand Claim Brand Claim
by Robert Neumann

How to use Knative to deploy a Serverless Application on CCE and Kubernetes

Photo by Pixabay from Pexels

Container or Serverless? A question that will soon be superfluous with Knative. The open source project Knative was developed by Google together with Pivotal, IBM, Red Hat and SAP and offers middleware components for serverless container applications based on Kubernetes and Istio. This allows developers to focus more on writing code. Based on the Open Telekom Cloud CCE service we install Knative and show how to use it.

Knative Introduction

Knative is an open source framework that provides a collection of components that extend Kubernetes. Currently, Knative offers three components: Serving, Build, and Eventing.

The best descriptions of the components are given by Pivotal on their website.

"Serving is a scale-to-zero, request-driven compute runtime which leverages Istio to route traffic amongst revisions. The goal of Serving is to provide Kubernetes extensions for deploying and running serverless workloads."¹

"Build provides a pluggable model for building containers from source code. It’s based on Google’s container builder service. Buildpacks are one style of builds that could be plugged into this model."¹

"Eventing provides building blocks for consuming and producing events that adhere to the CloudEvents specification. It includes abstractions for feeds from event sources, and decoupled delivery through messaging channels backed by pluggable pub/sub broker services."¹

Knative is developed for different target groups the following diagram gives an overview:

Diagram by Knative

Developers

"Knative components offer developers Kubernetes-native APIs for deploying serverless-style functions, applications, and containers to an auto-scaling runtime."²

Operators

"Knative components are intended to be integrated into more polished products that cloud service providers or in-house teams in large enterprises can then operate. Any enterprise or cloud provider can adopt Knative components into their own systems and pass the benefits along to their customers."²

Contributors

"With a clear project scope, lightweight governance model, and clean lines of separation between pluggable components, the Knative project establishes an efficient contributor workflow."²

Istio

The use of cloud platforms is diverse and offers companies far-reaching opportunities. But it can lead to a situation in which the operation of the cloud burdens the developers as well as the operation. This leads to complex microservice architectures to ensure portability, with the operation having to administer extensive hybrid and multi-cloud implementation. In this situation Istio helps to control, secure, connect and monitor services. For more information about Istio, I recommend the Istio-documentation

Install Istio

After a short introduction we can start to install Knative on our CCE - Kubernetes Cluster.

First, we need to install Istio. This will be done by the following commands. It will take some seconds to get all services in the running state.

kubectl apply --filename https://github.com/knative/serving/releases/download/v0.4.1/istio-crds.yaml &&
kubectl apply --filename https://github.com/knative/serving/releases/download/v0.4.1/istio.yaml

Next, we need to label the default namespace with istio-injection=enabled. This activates Istio on the “default” Kubernetes namespace and injects automatically an Istio proxy sidecar container to all pods deployed to the this namespace.

kubectl label namespace default istio-injection=enabled

To check whether all Istio components are in Running status, execute the following command.

kubectl get pods --namespace istio-system

It will take a few minutes until all components are started.

Install Knative

At this stage our Istio service mesh is running and we are ready to install Knative. The following command must be executed without any error.

kubectl apply --filename https://github.com/knative/serving/releases/download/v0.4.0/serving.yaml &&
kubectl apply --filename https://github.com/knative/build/releases/download/v0.4.0/build.yaml &&
kubectl apply --filename https://github.com/knative/eventing/releases/download/v0.4.0/release.yaml &&
kubectl apply --filename https://github.com/knative/eventing-sources/releases/download/v0.4.0/release.yaml &&
kubectl apply --filename https://github.com/knative/serving/releases/download/v0.4.0/monitoring.yaml &&
kubectl apply --filename https://raw.githubusercontent.com/knative/serving/v0.4.0/third_party/config/build/clusterrole.yaml

We can monitor the component installation with the following commands. All these must indicate the status running before continuing.

kubectl get pods --namespace knative-serving
kubectl get pods --namespace knative-build
kubectl get pods --namespace knative-eventing
kubectl get pods --namespace knative-sources
kubectl get pods --namespace knative-monitoring

If everything looks good we are ready to deploy our first app with Knative.

Deploy an App with Knative

After the installation of Istio and Knative we can start to deploy a serverless application. In this case we will deploy a go hello-world example by use of the serving component.

For our example we will use the “default” namespace in the Kubernetes cluster. We need to create yaml-file for our application with the following content.

apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
  name: helloworld-go
  namespace: default
spec:
  runLatest:
    configuration:
      revisionTemplate:
        spec:
          container:
            image: gcr.io/knative-samples/helloworld-go # The URL to the image of the app
            env:
              - name: TARGET # The environment variable printed out by the sample app
                value: "Go Sample v1"

With the created namespace and the yaml-file we are ready to deploy our app by the use of kubectl apply.

kubectl apply --filename service.yaml

Our service is ready to interact we need to find the public IP-address of the gateway. We use the kubectl get service command in our case we don’t have an external load balancer we will use NodePorts. We need to get the following three variables.

export INGRESSGATEWAY=istio-ingressgateway
export IP_ADDRESS=$(kubectl get node  --output 'jsonpath={.items[0].status.addresses[0].address}'):$(kubectl get svc $INGRESSGATEWAY --namespace istio-system   --output 'jsonpath={.spec.ports[?(@.port==80)].nodePort}')
export HOST_URL=$(kubectl get ksvc helloworld-go  --output jsonpath='{.status.domain}')

With all the collected information we are ready to interact with our service by the us of the curl. Output should like the line below.

curl -H "Host: helloworld-go.default.example.com" http://${IP_ADDRESS}
Hello Go Sample v1!

Our service is available and we can interact with it. The next step is to change the version of our application. We have to edit the yaml-file like the following.

apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
  name: helloworld-go
  namespace: default
spec:
  runLatest:
    configuration:
      revisionTemplate:
        spec:
          container:
            image: gcr.io/knative-samples/helloworld-go # The URL to the image of the app
            env:
              - name: TARGET # The environment variable printed out by the sample app
                value: "Go Sample v2"

After the applying the service again. The configuration of it will change. We will see another revision of our service.

NAME                                                  READY     STATUS    RESTARTS   AGE
pod/helloworld-go-mjzcj-deployment-657b8bd6bf-pm4kr   3/3       Running   0          1m
pod/helloworld-go-wzmlk-deployment-b48847589-fmnkz    3/3       Running   0          9s
pod/icagent-dp2vv                                     1/1       Running   0          22h
pod/icagent-kfbmn                                     1/1       Running   0          22h

NAME                                        DOMAIN                              LATESTCREATED         LATESTREADY           READY     REASON
service.serving.knative.dev/helloworld-go   helloworld-go.default.example.com   helloworld-go-wzmlk   helloworld-go-wzmlk   True

NAME                                              LATESTCREATED         LATESTREADY           READY     REASON
configuration.serving.knative.dev/helloworld-go   helloworld-go-wzmlk   helloworld-go-wzmlk   True

NAME                                               SERVICE NAME                  AGE       READY     REASON
revision.serving.knative.dev/helloworld-go-mjzcj   helloworld-go-mjzcj-service   45m       True
revision.serving.knative.dev/helloworld-go-wzmlk   helloworld-go-wzmlk-service   10s       True

NAME                                      DOMAIN                              READY     REASON
route.serving.knative.dev/helloworld-go   helloworld-go.default.example.com   True

The curl command will also show the new revision v.2 as response.

curl -H "Host: helloworld-go.default.example.com" http://${IP_ADDRESS}
Hello Go Sample v2!

To demonstrate the scale-to-zero feature we do not send requests to our service. We will see that the pods will disappear. In the first stage the old revision of our service is terminating.

kubectl get pods
NAME                                              READY     STATUS        RESTARTS   AGE
helloworld-go-mjzcj-deployment-657b8bd6bf-pm4kr   2/3       Terminating   0          2m
helloworld-go-wzmlk-deployment-b48847589-fmnkz    3/3       Running       0          1m

After a while the other revision will terminating.

kubectl get pods
NAME                                             READY     STATUS        RESTARTS   AGE
helloworld-go-wzmlk-deployment-b48847589-fmnkz   2/3       Terminating   0          2m

When we send requests again it will take a few seconds until we get a response because the pods have to be started again.

curl -H "Host: helloworld-go.default.example.com" http://${IP_ADDRESS}
Hello Go Sample v2!

kubectl get pods
NAME                                             READY     STATUS    RESTARTS   AGE
helloworld-go-wzmlk-deployment-b48847589-6jvxn   3/3       Running   0          10s

Serving Resources

The Serving component provides four resources Service, Route, Configuration and Revision. These are defines as a set of objects as Kubernetes Custom Resource Definitions (CRDs) and used to define and control the behaviour you serverless workflow on the cluster.

  • Service: The service.serving.knative.dev resource automatically manages the whole lifecycle of your workload. It controls the creation of other objects to ensure that your app has a route, a configuration, and a new revision for each update of the service. Service can be defined to always route traffic to the latest revision or to a pinned revision.⁵

  • Route: The route.serving.knative.dev resource maps a network endpoint to a one or more revisions. You can manage the traffic in several ways, including fractional traffic and named routes.⁵

  • Configuration: The configuration.serving.knative.dev resource maintains the desired state for your deployment. It provides a clean separation between code and configuration and follows the Twelve-Factor App methodology. Modifying a configuration creates a new revision.⁵

  • Revision: The revision.serving.knative.dev resource is a point-in-time snapshot of the code and configuration for each modification made to the workload. Revisions are immutable objects and can be retained for as long as useful.⁵

The following diagram shows how these interact with each other.

Diagram by Knative

This tutorial can be adapted for any other application to deploy it with Knative on a Kubernetes cluster. The Knative documentation offers also different samples for many other programming languages. Further topics will be Knative Eventing- and Build-component and will be covered in future articles.

[1]: Pivotal. Knative: https://pivotal.io/de/knative

[2]: Knative. Knative: https://www.knative.dev/docs/

[3]: Istio. What is Istio: https://istio.io/docs/concepts/what-is-istio/

[4]: Google. Using Knative to deploy serverless applications to Kubernetes: https://codelabs.developers.google.com/codelabs/knative-intro/index.html#0

[5]: Knative. Knative Serving: https://www.knative.dev/docs/serving/