Knative eventing
Tags: kubernetes, serverless, knative, eventdriven
Published: 2023-02-26 14:05:19

Knative Eventing is a collection of APIs that enable you to use an event-driven architecture with your applications. You can create components that route events from event producers to event consumers, known as sinks, that receive events.

#### Use-cases
General areas of application are:
- Publishing an event without creating a consumer. You can send events to a broker as an HTTP POST, and use binding to decouple the destination configuration from your application that produces events.
- Consuming an event without creating a publisher. You can use a trigger to consume events from a broker based on event attributes.
- IoT, network monitoring, application monitoring, website testing and validation, and mobile app front-end processes that act as event generators.

Use Knative eventing when:
- When you want to publish an event without creating a consumer. You can send events to a broker as an HTTP POST, and use binding to decouple the destination configuration from your application that produces events.
- When you want to consume an event without creating a publisher. You can use a trigger to consume events from a broker based on event attributes. The application receives events as an HTTP POST.
- When you want to create components that route events from event producers to event consumers, known as sinks, that receive events. Sinks can also be configured to respond to HTTP requests by sending a response event.

#### Components
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/17l6rtls4hbke9uukffa.png)
Image credit: [https://medium.com/knative/announcing-knative-v0-5-release-cfe646ca8e30](https://medium.com/knative/announcing-knative-v0-5-release-cfe646ca8e30)

##### Sources
Knative eventing sources are objects that generate events and send them to a sink. They are created by instantiating a custom resource (CR) from a source object⁴. There are different types of sources, such as PingSource, ApiServerSource, KafkaSource, etc., depending on the event producer.

A PingSource is a simple source that creates events with a fixed payload on a cron schedule. For example, you can create a PingSource that sends an event every minute to a Knative service using this YAML file:

```yaml
apiVersion: sources.knative.dev/v1
kind: PingSource
metadata:
  name: test-ping-source
spec:
  schedule: "*/1 * * * *"
  contentType: "application/json"
  data: '{"message": "Hello world!"}'
  sink:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: event-display
```

##### Sinks
Knative eventing sinks are objects that receive events from sources or other components. They can be Addressable or Callable resources that have an address defined in their status.address.url field. Addressable sinks can receive and acknowledge an event delivered over HTTP, while Callable sinks can also respond to HTTP requests by sending a response event. Knative Services, Channels, and Brokers are all examples of sinks.

A Knative Service is a sink that runs a containerized application that can process incoming events. For example, you can create a Knative Service that displays events using this YAML file:

```yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: event-display
spec:
  template:
    spec:
      containers:
        - image: gcr.io/knative-releases/knative.dev/eventing-contrib/cmd/event_display
```

##### Brokers
Knative eventing brokers are objects that define an event mesh for collecting a pool of events. Brokers provide a discoverable endpoint for event ingress, and use triggers for event delivery. Event producers can send events to a broker by POSTing the event¹. Brokers are Kubernetes custom resources that can be created by using the kn CLI or by applying YAML files using kubectl.

A broker can be created by adding an annotation to a namespace, for example:
` kubectl label namespace default knative-eventing-injection=enabled`

This creates a default broker named `default` in the `default` namespace.

##### Channels
Channels are custom resources that define a single event-forwarding and persistence layer. You can connect channels to various backends for sourcing events, such as In-Memory, Kafka, or GCP PubSub³. You can also fan-out received events, through subscriptions, to multiple destinations, or sinks. Examples of sinks include brokers and Knative services.

To create a channel, you need to specify its type, name, namespace, and optionally some configuration parameters. For example, you can create an InMemoryChannel with this YAML file⁴:

```yaml
apiVersion: messaging.knative.dev/v1
kind: InMemoryChannel
metadata:
  name: my-channel
  namespace: default
```


Knative uses two types of channels: a generic channel object and channel implementations that each have their own custom resource definitions (CRDs), such as InMemoryChannel and KafkaChannel. Custom channel implementations each have their own event delivery mechanisms, such as in-memory or broker-based². Examples of brokers include KafkaBroker and GCP Pub/Sub Broker.

The KafkaChannel supports an ordered consumer delivery guarantee, which is a per-partition blocking consumer that waits for a successful response from the CloudEvent subscriber before it delivers the next message of the partition.

To create other channel types, you need to specify the channel implementation CRD in the YAML file for the channel object. For example, you can create a KafkaChannel with this YAML file:

```yaml
apiVersion: messaging.knative.dev/v1beta1
kind: KafkaChannel
metadata:
  name: my-kafka-channel
  namespace: default
spec:
  numPartitions: 3
  replicationFactor: 1
```

You can also use the generic channel object if you do not care about the properties a particular channel implementation provides, such as ordering and persistence. In that case, you need to configure a default channel type for your cluster or namespace.

###### Default channel
To configure a default channel type, you need to edit the default-ch-webhook ConfigMap in the knative-eventing namespace. You can do this by modifying the KnativeEventing CR or using kubectl. For example, you can set KafkaChannel as the default channel type for a namespace with this YAML file:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: default-ch-webhook
  namespace: knative-eventing
data:
  # Configuration for defaulting channels that do not specify CRD implementations.
  default-ch-config: |
    clusterDefault:
      apiVersion: messaging.knative.dev/v1beta1
      kind: InMemoryChannel
      spec:
        delivery:
          backoffDelay: PT0.5S
          backoffPolicy: exponential
          retry: 5
    namespaceDefaults:
      knativetutorial:
        apiVersion: messaging.knative.dev/v1beta1
        kind: KafkaChannel
        spec:
          numPartitions: 3
          replicationFactor: 1

```


##### Subscriptions
Knative subscriptions are objects that enable event delivery from a channel to an event sink, also known as a subscriber. A subscription specifies the channel and the sink to deliver events to, as well as some sink-specific options, such as how to handle failures.

You can create and manage subscriptions by using the Knative CLI (kn) or by modifying YAML files directly. For example, you can create a subscription with this command:

```bash
kn subscription create <subscription-name> --channel <channel-name> --sink <sink-name>
```

Or with this YAML file:

```yaml
apiVersion: messaging.knative.dev/v1
kind: Subscription
metadata:
  name: my-subscription
  namespace: default
spec:
  channel:
    apiVersion: messaging.knative.dev/v1
    kind: InMemoryChannel
    name: my-channel
  subscriber:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: my-service

```


---
##### Working example
Installation
```shell
# defintions
> kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.9.5/eventing-crds.yaml
# objects
> kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.9.5/eventing-core.yaml
# in-memory channel
> kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.9.5/in-memory-channel.yaml
# mt based broker
> kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.9.5/mt-channel-broker.yaml
```
post installation, we should see the following resources
```sh
❯ kapp inspect -a ce-demo -t
Target cluster 'https://127.0.0.1:55690' (nodes: macbook-control-plane, 2+)

Resources in app 'ce-demo'

Namespace     Name                             Kind           Owner    Rs  Ri  Age
knative-demo  ce-python                        Service        kapp     ok  -   17s
knative-demo   L ce-python                     Endpoints      cluster  ok  -   17s
knative-demo   L ce-python-zc5vx               EndpointSlice  cluster  ok  -   17s
knative-demo  ce-python                        Deployment     kapp     ok  -   17s
knative-demo   L ce-python-6bdd8d9995          ReplicaSet     cluster  ok  -   17s
knative-demo   L.. ce-python-6bdd8d9995-nmmgt  Pod            cluster  ok  -   17s
knative-demo  ce-python                        Trigger        kapp     ok  -   17s
(cluster)     knative-demo                     Namespace      kapp     ok  -   17s
knative-demo  default                          Broker         kapp     ok  -   17s

Rs: Reconcile state
Ri: Reconcile information

9 resources

Succeeded

❯ kubectl -n knative-demo get trigger ce-python
NAME        BROKER    SUBSCRIBER_URI                                    AGE   READY   REASON
ce-python   default   http://ce-python.knative-demo.svc.cluster.local   16m   True
```
let us test with a `curl` pod
```sh
❯ kubectl run curlpod --image=curlimages/curl --restart=Never -it -- sh
If you don't see a command prompt, try pressing enter.
/ $ curl -v "broker-ingress.knative-eventing.svc.cluster.local/knative-demo/default" \
> -X POST \
> -H "Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f79" \
> -H "Ce-specversion: 0.3" \
> -H "Ce-Type: dev.knative.events.demo01" \
> -H "Ce-Source: ashoka007/knative-events/demo01" \
> -H "Content-Type: application/json" \
> -d '{"message":"Hello World from the curl pod."}'
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 10.96.211.99:80...
* Connected to broker-ingress.knative-eventing.svc.cluster.local (10.96.211.99) port 80 (#0)
> POST /knative-demo/default HTTP/1.1
> Host: broker-ingress.knative-eventing.svc.cluster.local
> User-Agent: curl/7.88.1-DEV
> Accept: */*
> Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f79
> Ce-specversion: 0.3
> Ce-Type: dev.knative.events.demo01
> Ce-Source: ashoka007/knative-events/demo01
> Content-Type: application/json
> Content-Length: 44
>
< HTTP/1.1 202 Accepted
< Allow: POST, OPTIONS
< Date: Wed, 22 Feb 2023 14:41:25 GMT
< Content-Length: 0
<
exit
```

---
##### References
- https://master--knative.netlify.app/v0.19-docs/eventing
- https://medium.com/knative/announcing-knative-v0-5-release-cfe646ca8e30
- Examples: https://github.com/matzew/knative-broker-box