Build Event Driven Applications on Vultr Kubernetes Engine with Knative Eventing

Updated on November 21, 2023
Build Event Driven Applications on Vultr Kubernetes Engine with Knative Eventing header image

Introduction

Knative Eventing is a standalone platform that is part of the Knative framework used to simplify the deployment and management of serverless applications on Kubernetes Clusters. It offers a set of tools for routing events that allow developers to create and deploy event-driven serverless applications on Kubernetes.

Knative Eventing offers the following components that work together to enable the development of event-driven systems:

  • Event Source: A Kubernetes custom resource that generates events in the system and forwards them to the broker
  • Broker: Acts as a central hub that receives and forwards events to the appropriate event-driven workloads
  • Channel: Store events in-memory for high-speed, and low-latency scenarios
  • Trigger: Filters events based on their content and metadata. A trigger listens to specific events and starts specific actions based on the specified conditions
  • Subscriptions: Define how events get delivered to the event-driven application

In this article, install Knative Eventing and implement the following event patterns on a Vultr Kubernetes Engine (VKE) cluster:

  • Source to Sink
  • Channel and Subscription
  • Broker and Trigger

Prerequisites

Before you begin:

Install Knative Serving

Knative Serving is a dependency resource required to run Knative Eventing. Install the necessary Knative Service components on your VKE cluster as described in the steps below.

  • Visit the Knative Serving releases page and verify the latest version number. This article uses v1.11.0, apply the latest version components to your cluster.
  1. Install the Knative Custom Resource Definitions (CRDs)

     $ kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.11.0/serving-crds.yaml
  2. Install the Knative core components

     $ kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.11.0/serving-core.yaml
  3. Install the Knative Kourier controller

     $ kubectl apply -f https://github.com/knative/net-kourier/releases/download/knative-v1.11.0/kourier.yaml
  4. Configure Knative Serving to use Kourier as the default controller

     $ kubectl patch configmap/config-network --namespace knative-serving --type merge --patch '{"data":{"ingress-class":"kourier.ingress.networking.knative.dev"}}'
  5. Verify that the Kourier controller is available in your cluster

     $ kubectl --namespace kourier-system get service kourier

    Output:

     NAME      TYPE           CLUSTER-IP    EXTERNAL-IP      PORT(S)                      AGE
     kourier   LoadBalancer   10.99.96.89   172.20.2.1   80:30491/TCP,443:30118/TCP   2m9s

    Verify that the Kourier load balancer resource has a new external IP address

  6. Verify that all Knative Serving components are ready and running

     $ kubectl get pods -n knative-serving

    Output:

     NAME                                      READY   STATUS    RESTARTS   AGE
     activator-5c95bd8f69-hk7vz                1/1     Running   0          117s
     autoscaler-7dc9d77576-mk5lj               1/1     Running   0          115s
     controller-77878dc999-7qjk7               1/1     Running   0          113s
     net-kourier-controller-7bbb56bddd-25bzc   1/1     Running   0          79s
     webhook-5586b8f6d7-n59j9                  1/1     Running   0          109s

Install Knative Eventing

  • Visit the Knative Eventing Release page and verify the latest version. v1.11.0 is applied in this article, use the latest version to correctly install all components to your cluster.
  1. Install the Knative Eventing CRDs

     $ kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.11.0/eventing-crds.yaml
  2. Install the latest Knative Eventing core components

     $ kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.11.0/eventing-core.yaml
  3. Verify that the installed Knative Eventing components are available and running in your cluster

     $ kubectl get pods -n knative-eventing

    Output:

     NAME                                   READY   STATUS    RESTARTS        AGE
     eventing-controller-6cc445d8c5-wgbdd   1/1     Running   2 (3m34s ago)   3m47s
     eventing-webhook-7bcc5cb885-hcjg2      1/1     Running   2 (3m31s ago)   3m44s
  4. Install the in-memory channel to pass events

     $ kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.11.0/in-memory-channel.yaml
  5. Install the broker to use available channels and run event routing

     $ kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.11.0/mt-channel-broker.yaml
  6. Verify if the channel and broker are correctly installed and running

     $ kubectl get pods -n knative-eventing

    Output:

     NAME                                   READY   STATUS    RESTARTS        AGE
     eventing-controller-6cc445d8c5-wgbdd   1/1     Running   2 (4m54s ago)   5m7s
     eventing-webhook-7bcc5cb885-hcjg2      1/1     Running   2 (4m51s ago)   5m4s
     imc-controller-58b6df69f7-v4jq2        1/1     Running   1 (47s ago)     54s
     imc-dispatcher-594458c69d-8nwff        1/1     Running   0               50s
     mt-broker-controller-cc69ff94-6kt6n    1/1     Running   0               7s
     mt-broker-filter-7c46c8cf7d-sdxfg      1/1     Running   0               12s
     mt-broker-ingress-68f67cf96b-tvnwh     1/1     Running   0               10s

Install the Knative CLI Tool

Knative CLI is a terminal-based tool that allows you to create resources such as Knative services and event sources without creating manifest files. This allows you to scale Knative services up and down based on your requirements within the Kubernetes cluster. Follow the steps below to install Knative CLI on your management server.

  1. Download the latest Knative CLI realease file for Linux systems

     $ wget https://github.com/knative/client/releases/download/knative-v1.11.0/kn-linux-amd64

    When using a different operating system, visit the Knative CLI release page to download the latest build for your OS flavor.

  2. Move the downloaded binary file to the /usr/local/bin/ directory to enable the kn system-wide command

     $ sudo mv kn-linux-amd64 /usr/local/bin/kn
  3. Grant execute permissions on the kn binary file

     $ sudo chmod +x /usr/local/bin/kn
  4. Verify the installed Knative CLI version

     $ kn version

    Output:

     Version:      v1.11.0
     Build Date:   2023-07-27 07:42:56
     Git Revision: b7508e67
     Supported APIs:
     * Serving
      - serving.knative.dev/v1 (knative-serving v1.11.0)
     * Eventing

Implement Source to Sink Patterns Using Knative Eventing

In Knative eventing, source to sink is a basic pattern that represents the flow of events. Sources are the primary event producers that send events to a sink. A sink is a target of events generated by the source. It's responsible for receiving and responding to incoming events from other resources.

Knative eventing offers many types of event sources. In this section, use the PingSource to produce events with a fixed payload on a specified Cron schedule.

  1. Using the Knative CLI, create a Knative Sink service application named knative-test

     $ kn service create knative-test --concurrency-target=1 --image=quay.io/redhattraining/kbe-knative-hello:0.0.1

    Output:

     Creating service 'knative-test' in namespace 'default':
    
       9.091s Configuration "knative-test" is waiting for a Revision to become ready.
       9.115s Ingress has not yet been reconciled.
       9.158s Waiting for load balancer to be ready
       9.352s Ready to serve.
    
     Service 'knative-test' created to latest revision 'knative-test-00001' is available at URL:
     http://knative-test.default.svc.cluster.local
  2. Create a PingSource to continuously send a JSON message Test Message! after every 1 minute to the Knative Service sink knative-test

     $ kn source ping create knative-test-ping-source --schedule "* * * * *" --data '{"message": "Test Message!"}' --sink ksvc:knative-test
  3. Verify that the PingSource is available

     $ kn source ping list

    Output:

     NAME                       SCHEDULE    SINK                AGE   CONDITIONS   READY   REASON
     knative-test-ping-source   * * * * *   ksvc:knative-test   17s   3 OK / 3     True    
  4. View the cluster pods and verify that knative-test is available

     $ kubectl get pods

    Output:

     NAME                                            READY   STATUS    RESTARTS   AGE
     knative-test-00001-deployment-848b49ccb-m9plw   2/2     Running   0          34s
     knative-test-00001-deployment-848b49ccb-s2thg   2/2     Running   0          34s
  5. View the logs of any running pod

     $ kubectl logs -f knative-test-00001-deployment-848b49ccb-s2thg -c user-container

    Your output should look like the one below:

     2023-09-15 04:18:00,112 INFO  [eventing-hello] (executor-thread-1) ce-id=f75a901d-303b-4525-b4fd-7627f20a99f5
     2023-09-15 04:18:00,113 INFO  [eventing-hello] (executor-thread-1) ce-source=/apis/v1/namespaces/default/pingsources/knative-test-ping-source
     2023-09-15 04:18:00,113 INFO  [eventing-hello] (executor-thread-1) ce-specversion=1.0
     2023-09-15 04:18:00,113 INFO  [eventing-hello] (executor-thread-1) ce-time=2023-09-15T04:18:00.101796919Z
     2023-09-15 04:18:00,113 INFO  [eventing-hello] (executor-thread-1) ce-type=dev.knative.sources.ping
     2023-09-15 04:18:00,113 INFO  [eventing-hello] (executor-thread-1) content-type=null
     2023-09-15 04:18:00,113 INFO  [eventing-hello] (executor-thread-1) content-length=28
     2023-09-15 04:18:00,113 INFO  [eventing-hello] (executor-thread-1) POST:{"message": "Test Message!"}

    As displayed in the above output, the JSON message sent by PingSource includes the message Test Message you created earlier

Implement Channel and Subscription Using Knative Eventing

Channel and Subscription patterns route events between channels using subscriptions. In Knative, the default In-memory Channel channel provides an interface between the event source and the subscriber. It stores the incoming event data and distributes it to the subscribers.

A Subscription connects a Channel to the event sink (Service) and specifies how events from a channel get delivered to one or more target services. In this section, set up a sample Channel and Subscription pattern using the Knative CLI tool.

  1. Create a new channel named knative-test-channel

     $ kn channel create knative-test-channel
  2. Verify that the channel is available

     $ kn channel list

    Output:

     NAME                   TYPE              URL                                                                AGE   READY   REASON
     knative-test-channel   InMemoryChannel   http://knative-test-channel-kn-channel.default.svc.cluster.local   6s    True    
  3. Using a text editor such as Nano, create a new PingSource sink service file

     $ nano knative-test-ping-source.yaml
  4. Add the following configurations to the file

     apiVersion: sources.knative.dev/v1beta2
     kind: PingSource
     metadata:
       name: knative-test-ping-source
     spec:
       schedule: "* * * * *"
       data: '{"message": "Test Message!"}'
       sink:
        ref:
         apiVersion: messaging.knative.dev/v1
         kind: Channel
         name: knative-test-channel

    Save and close the file

    The above configuration defines a new PingSource resource that can receive and process the events from the Channel

  5. Apply the resource to your cluster

     $ kubectl apply -f knative-test-ping-source.yaml
  6. Create a new subscription file to connect the service channel to an event sink

     $ nano knative-test-subs.yaml
  7. Add the following configurations to the file

     apiVersion: messaging.knative.dev/v1
     kind: Subscription
     metadata:
      name: knative-test-subs
     spec:
       channel:
         apiVersion: messaging.knative.dev/v1
         kind: Channel
         name: knative-test-channel
       subscriber:
        ref:
           apiVersion: serving.knative.dev/v1
          kind: Service
          name: knative-test

    Save and close the file

  8. Apply the subscription resource to your cluster

     $ kubectl apply -f knative-test-subs.yaml
  9. Using the Knative CLI, create another sink service knative-test-2 to view how the channel and the subscriptions work

     $ kn service create knative-test-2 --concurrency-target=1 --image=quay.io/redhattraining/kbe-knative-hello:0.0.1
  10. Verify that the sink service is available in your cluster

    $ kn service list

    Output:

    NAME             URL                                               LATEST                 AGE    CONDITIONS   READY   REASON
    knative-test     http://knative-test.default.svc.cluster.local     knative-test-00001     9m3s   3 OK / 3     True    
    knative-test-2   http://knative-test-2.default.svc.cluster.local   knative-test-2-00001   33s    3 OK / 3     True   

    As displayed in the above output, knative-test-2 is the new sink service available in your cluster

  11. Create another subscription knative-test-2-subs to subscribe to the knative-test-channel

    $ kn subscription create knative-test-2-subs --channel knative-test-channel --sink knative-test-2
  12. Verify that the subscription is available and ready to use

    $ kn subscription list

    Output:

    NAME                  CHANNEL                        SUBSCRIBER            REPLY   DEAD LETTER SINK   READY   REASON
    knative-test-2-subs   Channel:knative-test-channel   ksvc:knative-test-2                              True    
    knative-test-subs     Channel:knative-test-channel   ksvc:knative-test                                True    
  13. Verify that all Knative service pods in your cluster are running

    $ kubectl get pods

    Output:

    NAME                                               READY   STATUS        RESTARTS   AGE
    knative-test-00001-deployment-848b49ccb-bkdjb      2/2     Terminating   0          89s
    knative-test-00001-deployment-848b49ccb-tn2zb      2/2     Running       0          89s
    knative-test-2-00001-deployment-566d9dd859-lndqr   2/2     Running       0          29s
    knative-test-2-00001-deployment-566d9dd859-mqqwj   2/2     Running       0          29s
  14. View the logs of any pod to verify if the Channel-Subscription mechanism works

    $ kubectl logs -f knative-test-2-00001-deployment-566d9dd859-mqqwj -c user-container

    When the pod is running correctly, you should receive the Test Message! JSON output as displayed in the following output:

    2023-09-15 04:25:05,405 INFO  [eventing-hello] (executor-thread-1) ce-id=cc9c5e2c-9ec6-4e00-b03c-ddc134b6fe31
    2023-09-15 04:25:05,405 INFO  [eventing-hello] (executor-thread-1) ce-source=/apis/v1/namespaces/default/pingsources/knative-test-ping-source
    2023-09-15 04:25:05,405 INFO  [eventing-hello] (executor-thread-1) ce-specversion=1.0
    2023-09-15 04:25:05,405 INFO  [eventing-hello] (executor-thread-1) ce-time=2023-09-15T04:25:00.39065862Z
    2023-09-15 04:25:05,405 INFO  [eventing-hello] (executor-thread-1) ce-type=dev.knative.sources.ping
    2023-09-15 04:25:05,405 INFO  [eventing-hello] (executor-thread-1) content-type=null
    2023-09-15 04:25:05,405 INFO  [eventing-hello] (executor-thread-1) content-length=28
    2023-09-15 04:25:05,405 INFO  [eventing-hello] (executor-thread-1) POST:{"message": "Test Message!"}
  15. Before applying a Broker and Trigger to your cluster, remove the ping source, channel, and subscription resources to avoid conflicts

    $ kn subscription delete knative-test-subs && kn subscription delete knative-test-2-subs && kn channel delete knative-test-channel && kn source ping delete knative-test-ping-source

Implement Broker and Trigger Using Knative Eventing

Broker and Trigger are event mesh based patterns that collect a pool of events and distribute them to consumers. They offer a custom filtering mechanism to distribute events based on the trigger type.

  1. Create a new broker named knative-test-broker to collect events

     $ kn broker create knative-test-broker
  2. View the new broker resource

     $ kn broker list

    Output:

     NAME                  URL                                                                                    AGE   CONDITIONS   READY   REASON
     knative-test-broker   http://broker-ingress.knative-eventing.svc.cluster.local/default/knative-test-broker   18s   6 OK / 6     True  
  3. Create a Knative Trigger knative-test-trigger that references the broker, sink and defines the condition type testing1 for incoming events

     $ kn trigger create knative-test-trigger --broker=knative-test-broker --sink=ksvc:knative-test --filter=type=testing1
  4. Create another Trigger knative-test-2-trigger with a different condition named testing2

     $ kn trigger create knative-test-2-trigger --broker=knative-test-broker --sink=ksvc:knative-test-2 --filter=type=testing2
  5. Verify the created Triggers

     $ kn trigger list

    Output:

     NAME                     BROKER                SINK                  AGE   CONDITIONS   READY   REASON
     knative-test-2-trigger   knative-test-broker   ksvc:knative-test-2   11s   6 OK / 6     True    
     knative-test-trigger     knative-test-broker   ksvc:knative-test     74s   6 OK / 6     True  

    The knative-test service handles events with the type testing1, and knative-test-2 handles events with the type testing2

  6. View the broker Kubernetes service URL to verify your broker and triggers

     $ kubectl get broker knative-test-broker -o jsonpath='{.status.address.url}'

    Output:

     http://broker-ingress.knative-eventing.svc.cluster.local/default/knative-test-broker
  7. Run the following command to send greetings with the type testing1

     $ kubectl run greeting-requester --image quay.io/redhattraining/kbe-greeting-requester:latest --env="BROKER_URL=http://broker-ingress.knative-eventing.svc.cluster.local/default/knative-test-broker"  --env="GREETING=testing1"  --rm=True --attach=true --restart=Never

    The above command scales up the knative-test service you have defined with the condition type testing1

  8. View the list of running pods and verify that the knative-test service scales up

     $ kubectl get pods

    Output:

     NAME                                               READY   STATUS    RESTARTS   AGE
     knative-test-00001-deployment-848b49ccb-pb2rx      2/2     Running   0          50s
     knative-test-00001-deployment-848b49ccb-s28r9      2/2     Running   0          7m12s
     knative-test-2-00001-deployment-566d9dd859-5kzrb   2/2     Running   0          7m12s
  9. Send another greeting with the type testing2 to scale up the knative-test-2 service

     $ kubectl run greeting-requester --image quay.io/redhattraining/kbe-greeting-requester:latest --env="BROKER_URL=http://broker-ingress.knative-eventing.svc.cluster.local/default/knative-test-broker"  --env="GREETING=testing2"  --rm=True --attach=true --restart=Never

    The above command should now scale up the knative-test-2 service. You can verify it using the below command.

  10. View the list of running pods and verify that the knative-test-2 service scales up

    $ kubectl get pods

    Output:

    NAME                                               READY   STATUS    RESTARTS   AGE
    knative-test-2-00001-deployment-566d9dd859-2qxdx   2/2     Running   0          14s
    knative-test-2-00001-deployment-566d9dd859-gktkh   2/2     Running   0          14s
    knative-test-2-00001-deployment-566d9dd859-mr5vk   2/2     Running   0          11s
    knative-test-2-00001-deployment-566d9dd859-n6jq5   2/2     Running   0          11s
    knative-test-2-00001-deployment-566d9dd859-s97jj   2/2     Running   0          11s

    The above output confirms that the filtering mechanism of triggers is successful.

Conclusion

You have implemented different patterns using Knative Eventing on a Vultr Kubernetes Engine (VKE) cluster. Implementing Knative Eventing on the Kubernetes cluster allows you to build scalable, and event-driven microservices. For more information to unlock the full potential of your microservices, visit the official Knative Eventing documentation.