Introduction to Knative Eventing
Knative Eventing is a part of Knative that provides features for implementing event-driven architecture in a serverless way. Knative eventing has tools for routing events from event sources to sinks, enabling developers to create event-driven serverless applications.
You can use Knative eventing for the following:
- Publishing an Event Without Creating a Consumer
-
You can send events to a broker as an HTTP POST from your application, which produces events. You can use subscriptions to decouple the producer applications from event consumers.
- Consuming an Event Without Creating a Publisher
-
You can use a trigger to consume events from a broker, and filter them based on event attributes. The application receives events as an HTTP POST.
Eventing Patterns
There are three main patterns that you can implement using Knative Eventing:
-
Source to Sink
-
Channel and Subscription
-
Broker and Trigger
Source to Sink
Source to sink is the most basic eventing pattern. It has two kinds of Knative resource interfaces, Source
and Sink
.
- Source
-
A
Source
is responsible for sending the events to aSink
. Sources are the primary event producers. Sources are abstract Knative resources, so you must use an implementation of it to send events from it.There are many types of Knative Sources. Here are a few that the Knative team maintains:
-
PingSource: Produces events with a fixed payload on a specified Cron schedule.
-
APIServerSource: Brings Kubernetes API server events into Knative. The APIServerSource fires a new event each time a Kubernetes resource is created, updated or deleted.
-
Apache Kafka: Brings Apache Kafka messages into Knative. The
KafkaSource
reads events from an Apache Kafka cluster, and passes these events to a sink to be consumed. -
GitHub: Registers for events of the specified types on the specified GitHub organization or repository, and brings those events into Knative. The
GitHubSource
fires a new event for selected GitHub event types.For more information on other Knative Source types, you can visit the Knative Event Sources official documentation.
-
- Sink
-
A
Sink
is an adressable or a callable resource that can receive incoming events from other resources. Knative Services, Channels, and Brokers are all examples of sinks. You must use a Knative Service as a sink to implement thesource to sink
pattern. Channels and Brokers are the topics of other eventing patterns.
Creating Knative Sink Services
You can create a Knative service application as a sink by using the kn
CLI or kubectl
CLI. The following command creates a Service
with the name knative-hello
.
kn service create knative-hello \
--concurrency-target=1 \
--image=quay.io/redhattraining/kbe-knative-hello:0.0.1
The output must be as follows:
...output omitted...
27.810s Ingress has not yet been reconciled.
27.949s Waiting for load balancer to be ready
28.053s Ready to serve.
Service 'knative-hello' created to latest revision 'knative-hello-00001' is available at URL:
https://knative-hello-YOUR_NAMESPACE.apps-crc.testing
Note |
Note that the |
Creating Eventing Sources
To create an Event Source, you can use the kn
CLI, or kubectl
CLI. The following command creates a PingSource
that sends a JSON message every minute to the Knative Service sink knative-hello
you’ve created.
kn source ping create knative-hello-ping-source \
--schedule "* * * * *" \
--data '{"message": "Hello from KBE!"}' \
--sink ksvc:knative-hello
Ping source 'knative-hello-ping-source' created in namespace 'YOUR_NAMESPACE'.
The preceding command creates a PingSource
resource as follows:
apiVersion: sources.knative.dev/v1beta2
kind: PingSource
metadata:
name: knative-hello-ping-source
spec:
data: '{"message": "Hello from KBE!"}'
schedule: '* * * * *'
sink:
ref:
apiVersion: serving.knative.dev/v1
kind: Service
name: knative-hello
You can verify that you have the ping source created:
kn source ping list
The output must be as follows:
NAME SCHEDULE SINK AGE CONDITIONS READY REASON
knative-hello-ping-source * * * * * ksvc:knative-hello 2m5s 3 OK / 3 True
List the running pods of the knative-hello
service and examine the logs:
kubectl get pods
NAME READY STATUS RESTARTS AGE
knative-hello-00001-deployment-cf6bb989b-jldk6 2/2 Running 0 6s
knative-hello-00001-deployment-cf6bb989b-vfj6m 2/2 Running 0 10s
kubectl logs \
-f knative-hello-00001-deployment-xxxx-xxxx \
-c user-container
The log output of the service must be as follows:
...output omitted...
2022-04-25 22:26:00,105 INFO [eventing-hello] (executor-thread-1) ce-specversion=1.0
2022-04-25 22:26:00,105 INFO [eventing-hello] (executor-thread-1) ce-time=2022-04-25T22:26:00.090162485Z
2022-04-25 22:26:00,106 INFO [eventing-hello] (executor-thread-1) ce-type=dev.knative.sources.ping
2022-04-25 22:26:00,106 INFO [eventing-hello] (executor-thread-1) content-type=null
2022-04-25 22:26:00,106 INFO [eventing-hello] (executor-thread-1) content-length=30
2022-04-25 22:26:00,106 INFO [eventing-hello] (executor-thread-1) POST:{"message": "Hello from KBE!"}
...output omitted...
Important |
Because the ping source you’ve created sends event data in a 1 minute interval, you might have to wait before the ping occurs in the logs. |
Channel and Subscription
Channels and Subscriptions provide an event pipe
pattern that routes events between channels by using subscriptions.
- Channel
-
A
Channel
is an interface between the event source and the subscriber. A channel is a special kind of a sink, because they can store the incoming event data and distribute them to the subscribers.There are a 3 types of channels in Knative:
-
In-memory Channel
-
Apache Kafka Channel
-
Google Cloud Platform Pub-sub Channel
The
In-memory Channel
is the default channel in Knative. This channel does not provide any durability, message recovery or persistence. If you need a more reliable channel, you must use a channel such as theApache Kafka Channel
.
-
- Subscription
-
A Subscription is responsible for connecting a channel with a service. In other words, services can subscribe to a channel via
subscriptions
. Once a service subscribes to a channel, it starts receiving the events.
Creating a Channel
To create a channel, you can run the following command:
kn channel create knative-hello-channel
You can verify the created channel by running the following command:
kn channel list
The output must be as follows:
NAME TYPE ...
knative-hello-channel InMemoryChannel
The YAML representation of this channel must be as follows:
apiVersion: messaging.knative.dev/v1
kind: Channel
metadata:
name: knative-hello-channel
Note |
Because no extra configurations were applied, Knative creates channels as an |
To make the channel available for a Knative source usage, you must configure its sink as this channel. You can create a file called knative-hello-ping-source.yaml
and paste the following content into it.
apiVersion: sources.knative.dev/v1beta2
kind: PingSource
metadata:
name: knative-hello-ping-source
spec:
schedule: "* * * * *"
data: '{"message": "Hello from KBE!"}'
sink:
ref:
apiVersion: messaging.knative.dev/v1
kind: Channel
name: knative-hello-channel
Notice that this is the YAML representation of the knative-hello-ping-source
you have already created, but with a slight difference. The sink points to the channel knative-hello-channel
in this configuration. This means that the ping source will use this channel to send the events. Any sink that subscribes to this channel must receive those events.
If you want to update the source, save the YAML file and apply it by using the following command:
kubectl apply -f knative-hello-ping-source.yaml
This command should update the Knative source knative-hello-ping-source
to use the channel knative-hello-channel
as sink.
Note |
You can also use the |
Creating Subscriptions
We have our service knative-hello
, but unless it subscribes to the channel, it cannot recieve the event messages. You can create a subscription for the knative-hello
service by applying the following YAML configuration.
apiVersion: messaging.knative.dev/v1
kind: Subscription
metadata:
name: knative-hello-subs
spec:
channel:
apiVersion: messaging.knative.dev/v1
kind: Channel
name: knative-hello-channel
subscriber:
ref:
apiVersion: serving.knative.dev/v1
kind: Service
name: knative-hello
You can save this YAML in a file called knative-hello-subs.yaml
, and apply it by running the following command:
kubectl apply -f knative-hello-subs.yaml
Another way to create a subscription is to use the kn
CLI. Before creating another subscription by using kn
, you can create another sink service for a better demonstration of the channel and the subscriptions. Let’s name this service as knative-hello-2
. This is the same service as knative-hello
because it uses the same container image.
kn service create knative-hello-2 \
--concurrency-target=1 \
--image=quay.io/redhattraining/kbe-knative-hello:0.0.1
You have the knative-hello-2
. You can create the subscription to enable the knative-hello-2
service to subscribe to the knative-hello-channel
. The following command creates the subscription:
kn subscription create knative-hello-2-subs \
--channel knative-hello-channel \
--sink knative-hello-2
Feel free to run the following command to verify the created subscriptions:
kn subscription list
The output must be as follows:
NAME CHANNEL SUBSCRIBER ...
knative-hello-2-subs Channel:knative-hello-channel ksvc:knative-hello-2
knative-hello-subs Channel:knative-hello-channel ksvc:knative-hello
When you run the kubectl get pods
command, you can see that there are several pods running for the Knative services.
NAME READY STATUS RESTARTS AGE
knative-hello-00001-deployment-cf6bb989b-2zzxc 2/2 Running 0 2m33s
knative-hello-2-00001-deployment-6d65b95bd8-j4j4l 2/2 Running 0 93s
knative-hello-2-00001-deployment-6d65b95bd8-m4ks5 2/2 Running 0 93s
You can choose one of the pods to verify that the Channel-Subscription mechanism works. You can examine other pods' logs as well.
kubectl logs -f \
knative-hello-2-00001-deployment-xxxx-xxxx \
-c user-container
The logs output must be as follows:
...output omitted...
2022-04-26 13:30:00,289 INFO [eventing-hello] (executor-thread-1) ce-specversion=1.0
2022-04-26 13:30:00,289 INFO [eventing-hello] (executor-thread-1) ce-time=2022-04-26T13:30:00.26845184Z
2022-04-26 13:30:00,289 INFO [eventing-hello] (executor-thread-1) ce-type=dev.knative.sources.ping
2022-04-26 13:30:00,290 INFO [eventing-hello] (executor-thread-1) content-type=null
2022-04-26 13:30:00,290 INFO [eventing-hello] (executor-thread-1) content-length=30
2022-04-26 13:30:00,290 INFO [eventing-hello] (executor-thread-1) POST:{"message": "Hello from KBE!"}
...output omitted...
Important |
Before continuing to the next topic, if you have created the resources in this tutorial so far then you must remove the ping source, channel, and subscriptions you have created.
The output should be as follows:
|
Broker and Trigger
Broker and Trigger provide an event mesh
model. They allow distributing the events uniformly to consumers.
Brokers and Triggers implement the Content Based Router
Enterprise Integration Pattern. They allow custom filtering for the events so that events can be distributed selectively.
- Broker
-
Brokers are Knative custom resources that define an event mesh for collecting a pool of events.
- Trigger
-
Triggers represent a subscription to events from a specific broker. Triggers are like subscriptions with a filtering configuration, they help you to decide which events to subscribe to for a particular business need.
Creating a Broker
You can create a broker called knative-hello-broker
by using the following command:
kn broker create knative-hello-broker
If you have created it then you can verify the broker configuration by using the following command:
kn broker describe knative-hello-broker -o yaml
apiVersion: eventing.knative.dev/v1
kind: Broker
metadata:
annotations:
eventing.knative.dev/broker.class: MTChannelBasedBroker
name: knative-hello-broker
...output omitted...
spec:
config:
apiVersion: v1
kind: ConfigMap
name: config-br-default-channel
namespace: knative-eventing
...output omitted...
Note |
By default, brokers use the in-memory channels on the backend. A set of configurations, which are configured via ConfigMaps, manage this behavior. These configurations are out of the scope of this tutorial. For more information, check out the resources, which are at the end of this tutorial. |
Creating Triggers
Similar to the subscriptions, you must create triggers for each Knative service to create an eventing bridge.
You can run the following command to create a trigger for the knative-hello
service:
kn trigger create knative-hello-trigger \
--broker=knative-hello-broker \
--sink=ksvc:knative-hello \
--filter=type=merhaba
Notice that the trigger uses a filter type=merhaba
. The type is the CloudEvent type that is mapped to the ce-type
HTTP header. A Trigger can filter by any CloudEvent attributes such as type, source, or extension.
You can run a similar command for the knative-hello-2
service, this time for the filter type=hola
:
kn trigger create knative-hello-2-trigger \
--broker=knative-hello-broker \
--sink=ksvc:knative-hello-2 \
--filter=type=hola
The knative-hello
service must handle events with the type merhaba
, and the knative-hello-2
service must handle the ones with the type hola
.
To verify your broker and triggers, you need the broker Kubernetes service URL. You can get the URL by running the following command:
kubectl get broker knative-hello-broker \
-o jsonpath='{.status.address.url}'
This must return an output as follows:
http://broker-ingress.knative-eventing.svc.cluster.local/YOUR_NAMESPACE/knative-hello-broker
The following command runs an application called greeting-requester
, which sends twenty HTTP POST requests to the given URL in a CloudEvent format. If you want to try out this example, replace the YOUR_NAMESPACE with the namespace you are working on.
You can send some greetings in the type "merhaba" by using the following command.
kubectl run greeting-requester \
--image quay.io/redhattraining/kbe-greeting-requester:latest \
--env="BROKER_URL=http://broker-ingress.knative-eventing.svc.cluster.local/YOUR_NAMESPACE/knative-hello-broker" \
--env="GREETING=merhaba" \
--rm=True --attach=true --restart=Never
In this case, knative-hello
service should scale up but the knative-hello-2
service should not.
You can send some greetings in the type "hola" by using the following command.
kubectl run greeting-requester \
--image quay.io/redhattraining/kbe-greeting-requester:latest \
--env="BROKER_URL=http://broker-ingress.knative-eventing.svc.cluster.local/YOUR_NAMESPACE/knative-hello-broker" \
--env="GREETING=hola" \
--rm=True --attach=true
In this case, the knative-hello-2
service should scale up but the knative-hello
service should not. You can also set the GREETING
environment variable in the preceding command to something like bonjour
, and observe the services do not receive any requests.
These examples show that the filtering mechanism of triggers works successfully.