DEV Community

Cover image for Knative Serverless in 2024
Jens Gerke
Jens Gerke

Posted on

Knative Serverless in 2024

At Direktiv, we're big fans of Knative. It's not just for serverless – it's a fantastic deployment tool for Kubernetes too.

The project is emphasizing the serverless nature but it's just in general a great deployment tool as well. In my opinion, it simplifies that process because the deployment of e.g. a HTTP services comes down to one file which describes the whole service you want to provide to your applications or users.

I could provide a big overview of how Knative works, but in this little tutorial I want to show you the basic installation and configuration and how to deploy your first Knative service.

Knative Installation

Starting with Knative can be a bit daunting, especially when it comes to choosing the right installation method. There are two primary ways to install Knative: YAML-based installation and the Knative operator.

The YAML-based installation is straightforward, but it's somewhat limited in flexibility. If you need to modify configurations during installation, this method won't be good enough. That's where the Knative operator comes in handy. The operator not only installs the serving component but also the eventing component if required and it is offering more flexibility and customization options.

To get started with the Knative operator, you can use the following command. Do note that it can only be installed in the default namespace:

kubectl apply -f https://github.com/knative/operator/releases/download/knative-v1.13.3/operator.yaml
Enter fullscreen mode Exit fullscreen mode

Once you've executed the command to install the Knative operator, you should have the operator up and running with two pods in the default namespace.

To verify that the operator is running, you can use the command kubectl get pods

knative-operator-6d768fb7-xnjgs      
operator-webhook-7d6b54d78b-q66fh              
Enter fullscreen mode Exit fullscreen mode

Knative is requiring a network layer and you have three different options: Istio, Kourier, and Contour.

Istio: Istio is a powerful service mesh that provides advanced networking, security, and observability features.

Kourier: Kourier is purpose-built for Knative, providing a lightweight and efficient network layer specifically designed for serverless workloads.

Contour: Contour is a Kubernetes ingress controller that can also be used as the network layer for Knative. It provides basic routing and load balancing capabilities.

When deciding which option to choose, consider your specific environment, requirements, and preferences. At Direktiv, we typically opt for Contour due to its simplicity. However, your choice may vary depending on your use case and infrastructure setup.

In this tutorial we will use Contour as well:

kubectl apply --filename https://github.com/knative/net-contour/releases/download/knative-v1.13.0/contour.yaml
Enter fullscreen mode Exit fullscreen mode

Contour installs an internal and external service in two namespaces. If external access to your Knative services isn't needed, you can optimize your setup by deleting the contour-external namespace. This eliminates the allocation of an unnecessary external IP within the cluster. Simply run the following command:

kubectl delete ns contour-external
Enter fullscreen mode Exit fullscreen mode

Knative Configuration

Installing Knative using a single YAML file with the operator is convenient, but configuring it can be challenging and I find the documentation a bit thin. Therefore I will explain it a little bit (although there is a lot more).

The basic YAML would look like the following snippet.

apiVersion: operator.knative.dev/v1beta1
kind: KnativeServing
metadata:
  name: knative-serving
Enter fullscreen mode Exit fullscreen mode

Usually you want to configure the network layer, features and other settings in Knative. You can modify this file to change the settings during installation.

apiVersion: operator.knative.dev/v1beta1
kind: KnativeServing
metadata:
  name: direktiv-knative
spec:
  ingress:
    contour:
      enabled: true
  deployments:
  - name: activator
    annotations:
      linkerd.io/inject: enabled
  config:
    features:
      multi-container: "enabled"  
      kubernetes.podspec-volumes-emptydir: "enabled"
      kubernetes.podspec-init-containers: "enabled"
    autoscaler:
      initial-scale: "0"
      allow-zero-initial-scale: "true"
      min-scale: "0"
    deployment:
      registries-skipping-tag-resolving: "kind.local,ko.local,dev.local,localhost:5000,localhost:31212"
    network:
      ingress-class: "contour.ingress.networking.knative.dev"
Enter fullscreen mode Exit fullscreen mode

This YAML is a very simple installation file for Knative. Individual components can be addressed under deployments. These components can be activator, autoscaler, controller, webhook or autoscaler-hpa. In this YAML we are setting an annotation for the activator pod.

Under config is the configuration for Knative's different ConfigMaps in kubernetes.

  • config-autoscaler
  • config-defaults
  • config-deployment
  • config-domain
  • config-features
  • config-gc
  • config-leader-election
  • config-logging
  • config-network
  • config-observability
  • config-tracing

You can lookup all the different settings in the configmaps after installation and tweak your Knative installation like modifying timeouts and maximum connections.

The most important setting in this case is ingress-class: "contour.ingress.networking.knative.dev" under network. This has to be configured because we are using Contour as network layer in this tutorial.

We recently had one installation where a proxy server was required. Because it took me a little bit to figure out how to set environment variables for the pods I'd like to share the snippet how to do that:

...
  deployments:
  - name: controller
    env:
    - container: controllerserving-certs-ctrl-ca
      envVars:
      - name: HTTP_PROXY
        value: "http://myproxy:3128"
      - name: HTTPS_PROXY
        value: "http://myproxy:3128"
      - name: NO_PROXY
        value: ".svc,.default,.local,.cluster.local,localhost"
...
Enter fullscreen mode Exit fullscreen mode

After appying the YAML with kubectl apply -f knative.yaml the list of pods in the default namespace will look like this and we are ready to install the first service.

knative-operator-6d768fb7-jthff                          1/1     Running   
operator-webhook-7d6b54d78b-75v46                        1/1     Running  
autoscaler-79d9fb98c-5mtnd                               1/1     Running  
controller-cdf856494-lv9qk                               1/1     Running  
webhook-dddf6fcff-jvdjc                                  1/1     Running    
autoscaler-hpa-7969f4f665-kdhv7                          1/1     Running     
activator-74cc7497c9-vqch9                               1/1     Running    
Enter fullscreen mode Exit fullscreen mode

Creating a Service

After setting up Knative it is time to run the first service. Applying the following file will create a Knative service.

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
spec:
  template:
    spec:
      containers:
      - image: direktiv/simple-hello
        env:
        - name: TARGET
          value: "Go Sample v1"
Enter fullscreen mode Exit fullscreen mode

To check if the service is up and running execute kubectl get ksvc and the service will show up in the list of available Knative services and it's status.

NAMESPACE   NAME            URL                                              LATESTCREATED         LATESTREADY           READY   REASON
default     helloworld-go   http://helloworld-go.default.svc.cluster.local   helloworld-go-00001   helloworld-go-00001   True 
Enter fullscreen mode Exit fullscreen mode

By default Knative would start a pod instance as well but because we have configured allow-zero-initial-scale and initial-scale the service will only be prepared for consumption and not started. A simple curl will "activate" the pod though.

kubectl run -it --rm --restart=Never --image curlimages/curl curl-test -- curl http://helloworld-go.default
Enter fullscreen mode Exit fullscreen mode

Maybe you have noticed the delay when calling the service. This happens when the service does a "cold start" with zero pods available.

At the beginning we said, Knative is a great deployment tool even without the serverless component. We can configure the service to have at least X pods available all the time to avoid those cold starts. With that approach Knative can be used as a simplified Kubernetes deployment tool.

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
  namespace: default
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/min-scale: "1"
    spec:
      containers:
      - image: direktiv/simple-hello
        env:
        - name: TARGET
          value: "Go Sample v1"
Enter fullscreen mode Exit fullscreen mode

The annotation autoscaling.knative.dev/min-scale would set the minimum number of pods to 1 meaning there is always one pod running at any given time.

I'm hoping this quick introduction to Knative will help you to get started. There is so much more to explore with Knative with e.g. traffic management and versioning. But I will write about this in a different post.

If you have any questions, just leave a comment!

Top comments (0)