top of page

Knative part 1

  • myriamfentanes
  • Dec 8, 2021
  • 5 min read

Serverless is a computing paradigm that has changed the operational model of applications, by eliminating the need to provision and manage the underlying infrastructure. Furthermore with the pressure covid19 put on business, IT has the mandate to switch to cost-effective models to eliminate the complexity of managing infrastructure. To solve this challenge, serverless platforms abstract much of this complexity with capabilities like:

  • Multi-language support

  • Account setup and configuration

  • Runtime security options

  • API routing control

  • Workflow and orchestration

  • Scaling and reliability

  • Metrics and monitoring

Knative for serverless

Knative is a technology that sits on top of Kubernetes as a collection of software processes, packaged into containers and a some additional customizations. All this to hide the complexities of Kubernetes configuration and change management. However for a developer all of this is transparent, the API just exposes YAML configuration files that declare the desired state of the application. Additionally the Knative CLI tool allows a more imperative configuration. From a use case perspective Knative core strength is the ability to handle unpredictability and variability: both for the load, scaling horizontally and back to zero, and on the type of applications it can connect.

Knative is divided into 2 subprojects: Serving and Eventing, both follow the same approach mentioned before. Serving is the more popular part of Knative. It contains all the logic to run your software, manage requests, route traffic, keep your software running, handle versioning, and scale to zero when necessary. This flexibility in scalability is one of the most appealing aspects of Knative. Below we can see the external components of Knative serving side.


ree

Knative user facing concepts


A service is defined by a Configuration, here is where you describe what the running service should look like.

Revisions are snapshots of a Configuration . Each time that you change a configuration, a new Revision is created, and actually is the revision that gets converted into Kubernetes low-level primitives. Revisions have the configuration that allows you to configure sophisticated routing setups, and deployment strategies like Blue/Green , Canary, or Incremental deployments, all of this based on Routes configuration.


To test Knative concepts, the first step is the installation, I used the Knative quickstart plugin, installed in minikube and found it very easy to use, so I didn't try any of the other install options. This quickstart is not for production use. Here are the instructions for the installation: https://knative.dev/docs/install/quickstart-install/ . I have also installed the Knative CLI (kn) to interact with the high-level API.

*Note that you will need to grant privileged access to minikube in order to open the ports required by Kourier, by default: 8o and 443.


My first Knative service

Lets create our first service:

> kn service create hello-world --image gcr.io/knative-samples/helloworld-go --env TARGET="Myriam"

Creating service 'hello-world' in namespace 'default':
0.049s The Route is still working to reflect the latest desired specification.
 0.138s ...
 0.177s Configuration "hello-world" is waiting for a Revision to become ready.
 3.612s ...
 3.802s Ingress has not yet been reconciled. 
 3.909s Waiting for load balancer to be ready
 4.021s Ready to serve.
 Service 'hello-world' created to latest revision 'hello-world- 
 00001' is available at URL:
 http://hello-world.default.127.0.0.1.sslip.io

The parameters are fairly simple:

  • name of the service

  • container image for the application. In this case I am using an image provided by Knative and written in go.

  • Environment variable consumed by the application, and injected by Knative.

To test your service you can curl on the URL

> curl http://hello-world.default.127.0.0.1.sslip.io
Hello Myriam!

Now lets do a second deployment for the service and see what happens


> kn service update hello-world --env TARGET="Maria"
0.035s The Configuration is still working to reflect the latest desired specification
2.267s Traffic is not yet migrated to the latest revision.
2.468s Ingress has not yet been reconciled.
2.600s Waiting for load balancer to be ready
2.673s Ready to serve.

Service 'hello-world' updated to latest revision 'hello-world-00002' is available at URL:
http://hello-world.default.127.0.0.1.sslip.io
  

To test your service you can curl on the URL

> curl http://hello-world.default.127.0.0.1.sslip.io
Hello Maria!

What happened is that I changed the TARGET environment variable, which is part of the service configuration. Whenever you create a service, you create also a Configuration and a Revision, in this case, the first time I created hello-world service, the configuration hello-world was created and the Revision hello-world-00001. When I updated the variable TARGET, I updated the Configuration which also created a new Revision called hello-world-00002, that by default is tagged as the latest revision. The revisions are suffixed with a number that indicates the generation of the Service. To list all the revisions available:


> kn revision list
NAME                SERVICE       TRAFFIC   TAGS   GENERATION   AGE   CONDITIONS   READY   REASON
hello-world-00002   hello-world   100%             2            30s   4 OK / 4     True
hello-world-00001   hello-world                    1            68s   4 OK / 4     True    

As you can see both Revisions are there, and the traffic is currently directed to the latest Revision. Almost any change I make to the configuration will trigger the creation of a new revision, except for Routes.

When I want to control the traffic that flows through my applications, Knative provides the abstraction for all networking through Routes, they handle public ingress and internal traffic to your services, the target services for the traffic and the percentage of traffic that goes to each specific target.

Let's see an example of splitting traffic between the 2 revisions:


> kn service update hello-world --traffic hello-world-00001=50 --traffic hello-world-00002=50
Updating Service 'hello-world' in namespace 'default':
0.029s The Route is still working to reflect the latest desired specification.
0.064s Ingress has not yet been reconciled.
0.083s Waiting for load balancer to be ready
0.273s Ready to serve.
Service 'hello-world' with latest revision 'hello-world-00002' (unchanged) is available at URL:
http://hello-world.default.127.0.0.1.sslip.io

If we test our service again we should see an evenly split response from both revisions:

> curl http://hello-world.default.127.0.0.1.sslip.io
Hello Myriam!
> http://hello-world.default.127.0.0.1.sslip.io
Hello Maria!

You can also specify the traffic using @latest as the target, instead of a specific Revision name.

So far we have used the high level Knative abstractions for the Serving component, and you don't need to know the internals to successfully deploy and configure your services.


Knative internals


Controllers

Knative has controllers that continuously reconcile the desired configuration with the reality called Reconcilers. The Reconcilers can be divided into 2 groups, the reconcilers for developer facing resources called configuration, service, revision and route. The second category are Reconcilers that work to carry lower-level-tasks, these are labeler, serverless and gc.


Webhook

A component in charge of processing API submissions, it injects routing and networking information to Kubernetes, validates configurations and sets default values and it resolves container image references.


Networking Controllers

Handles certificates and ingress, in previous versions it relied on Istio, but in the latest versions to avoid overhead, the networking has been abstracted so you can swap configurations and use other implementations for example: Kourier a Knative native implementation.


Autoscaler, Activator and Queue Proxy

AutoScaler is the easiest to explain, it observes the demand for a service calculates the instances needed to serve that demand and updates the service scale to meet the demand. When there is no load the number of instances will be configured to zero.

The Activator is the waiting zone where request go as a last resort when no instances are available, when the Activator receives new requests it pokes the Autoscaler to start new instances, and polls the service to redirect the requests as soon as an instance becomes available.

The Queue Proxy is a side car component that sits between your service and the traffic, every instance of a service has its own Queue Proxy and is here where Knative adds functionality like tracing, metrics, and buffering to requests flowing to the service.


And that is all for the first part of this series! In the second part, we will take a closer look to Routes and the Autoscaler.

Question: If you have deployed applications before Knative will feel familiar for you. Especially if you use the YAML configuration approach. What is the added value of Knative?












Recent Posts

See All

Comments


bottom of page