I’ve been looking at Knative eventing a fair bit lately and one of the things I have been doing is building an eventing demo (the first part of which can be found here). As part of this demo, I wanted to understand how I could get CloudEvents that were being sent by my producer to display in real time via a web UI (event display service UI).
Here is a bit of info and an overview of the approach I took. The code to run through this tutorial can be found here.
Prerequisites and set-up
First, you will need to have Knative and your chosen Gateway provider installed (I tried this with both Istio and Gloo, which both worked fine). You can follow the instructions here.
Initially deploy the 001-namespace.yaml
by running:
kubectl apply -f 001-namespace.yaml
Verify you have a broker:
kubectl -n knative-eventing-websocket-source get broker default
You will see that the broker has a URL, this is what we will use as our SINK in the next step.
Deploy the Blockchain Events Sender Application
The application that sends the events was discussed in my Knative Eventing: Part 1 post and you can find the repo with all the code for this application here.
To get up and running you can simply run the 010-deployment.yaml file. Here is a reminder of what it looks like:
apiVersion: apps/v1
kind: Deployment
metadata:
name: wseventsource
namespace: knative-eventing-websocket-source
spec:
replicas: 1
selector:
matchLabels: &labels
app: wseventsource
template:
metadata:
labels: *labels
spec:
containers:
- name: wseventsource
image: docker.io/josiemundi/wssourcecloudevents:latest
env:
- name: SINK
value: "http://default-broker.knative-eventing-websocket-source.svc.cluster.local"
This is a Kubernetes app deployment. The name of the deployment is wseventsource
and the namespace is knative-eventing-websocket-source
. We have defined an environmental variable of SINK
, for which we set the value
as the address of our broker.
Verify events are being sent by running:
kubectl --namespace knative-eventing-websocket-source logs -l app=wseventsource --tail=100
This is what we currently have deployed:

Add a trigger – Send CloudEvents to Event-Display
Now we can deploy our trigger, which will set our event-display service as the subscriber.
# Knative Eventing Trigger to trigger the helloworld-go service
apiVersion: eventing.knative.dev/v1alpha1
kind: Trigger
metadata:
name: wsevent-trigger
namespace: knative-eventing-websocket-source
spec:
broker: default
filter:
sourceAndType:
type: ""
source: ""
subscriber:
ref:
apiVersion: v1
kind: Service
name: event-display
In the file above, we define our trigger name as wsevent-trigger and the namespace. In spec > filter I am basically specifying for the broker to send all events to the subscriber. The subscriber in this case is a Kubernetes services rather than a Knative Service.
kubectl apply -f 030-trigger.yaml
Now we have the following:

A trigger can exist before the service and vice versa. Let’s set up our event display.
Stream CloudEvents to Event Display service
I used the following packages to build the Event Display service:
- Go SDK for CloudEvents
- kncloudevents – event delivery for CloudEvents (built on top of the prior to build a cloudevents server)
- Event Source – server sent events in go
Originally I deployed my event-display
application as a Knative Service and this was fine but I could only access the events through the logs or by using curl.
Ideally, I wanted to build a stream of events that was push all the way to the UI. However, I discovered that for this use case it wasn’t possible to deploy this way. This is because Knative serving does not allow multiple ports in a service deployment.
I asked the question about it in the Knative Slack channel and the response was mainly to use mux and specify a path (I saw something similar in the sockeye GitHub project).
In the end, I chose to deploy as a native Kubernetes service instead. The reason is that it seemed like the most applicable way to do this, both in terms of functionality and also security. I was a little unsure about the feasibility of using mux in production as you may not want to expose an internal port externally.
For the kncloudevents project, I struggled to find detailed info or examples but the code is built on top of the Go sdk for CloudEvents and there are some detailed docs for the Python version.
We can use it to listen for HTTP cloudevents requests. By default it will listen on port 8080. When we use the StartReceiver
function, this is essentially telling our code to start listening. Because this happens on one port, we need another to ListenAndServe
.
So here are the two yaml files that we deploy for the event-display.
App Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: event-display
namespace: knative-eventing-websocket-source
spec:
replicas: 1
selector:
matchLabels: &labels
app: event-display
template:
metadata:
labels: *labels
spec:
containers:
- name: event-display
image: docker.io/josiemundi/bitcoinfrontendnew
Service Deployment:
apiVersion: v1
kind: Service
metadata:
name: event-display
namespace: knative-eventing-websocket-source
spec:
type: NodePort
ports:
- port: 80
protocol: TCP
targetPort: 8080
name: consumer
- port: 9080
protocol: TCP
targetPort: 9080
nodePort: 31234
name: dashboard
selector:
app: event-display
With everything deployed we now have the following:

Now if you head to the nodeport specified in the yaml:
http://localhost:31234
Next time, we will look at how to send a reply event back into the Knative eventing space.