Slack sink - Learning Knative Eventing and the Apache Camel K integration¶
As a bookstore owner, you aim to receive instant notifications in a Slack channel whenever a customer submits a new review comment. By leveraging Knative Eventing and Apache Camel K, you can set up an event-driven service that automates these notifications, ensuring you're always informed.
What Knative features will we learn about?¶
- Knative's ability to connect with third-party services, such as Slack, through event-driven integration using Apache Camel K.
What does the final deliverable look like?¶
When a CloudEvent with the type moderated-comment
and with ce-bad-word-filter
set to bad
is sent, it triggers a message to be sent in a designated Slack channel.
Install prerequisites¶
Prerequisite 1: Install Apache Camel-Kamelets¶
Install Apache Camel K operator on your cluster using any of the methods listed in the official installation docs. We will use the installation via Kustomize:
kubectl create ns camel-k && \
kubectl apply -k github.com/apache/camel-k/install/overlays/kubernetes/descoped?ref=v2.8.0 --server-side
Now you need to setup an IntegrationPlatform
with a container registry. You can read more about it in the official installation docs. For all our needs we only need to create the IntegrationPlatform
CR with a container registry entry. For example let's say we're using a Kind cluster with a local registry named kind-registry
on port 5000
. Then your IntegrationPlatform
CR will look like the following:
apiVersion: camel.apache.org/v1
kind: IntegrationPlatform
metadata:
name: camel-k
namespace: camel-k # Make sure this is the namespace where your operator is running
spec:
build:
registry:
address: kind-registry:5000
insecure: true
Install it with one command:
cat <<EOF | kubectl apply -f -
apiVersion: camel.apache.org/v1
kind: IntegrationPlatform
metadata:
name: camel-k
namespace: camel-k
spec:
build:
registry:
address: kind-registry:5000
insecure: true
EOF
If you are using other container registries, you may need to read more in the container registry configuration docs for Apache Camel K.
Verify
Check the installation status of the operator:
kubectl get deploy -n camel-k
You will see the output:
NAME READY UP-TO-DATE AVAILABLE AGE
camel-k-operator 1/1 1 1 47h
And the IntegrationPlatform:
kubectl get integrationplatforms -n camel-k
You will see the output with the registry address:
kubectl get integrationplatforms -n camel-k
NAME PHASE BUILD STRATEGY PUBLISH STRATEGY REGISTRY ADDRESS DEFAULT RUNTIME CAMEL VERSION
camel-k Ready routine Jib kind-registry:5000 3.15.3 4.8.5
Prerequisite 2: Create a Slack App and Generate an Incoming Webhook URL¶
Follow the instructions here on how to create the Slack workspace and generate an incoming webhook URL for your designated channel where notifications will be sent to.
Verify
You should have a webhook URL that looks like this:
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
Save this URL as you will need it later.
Prerequisite 3: Create a Secret that stores your Slack Credentials¶
We are storing the webhook URL as a secret. Copy and paste your webhook URL into the file slack-sink/application.properties
slack-sink/application.properties
slack.channel=#bookstore-owner
slack.webhook.url=https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
Then run the following command from the start
directory:
kubectl create secret generic slack-credentials --from-file=slack-sink/application.properties
Verify
You should see this message if the secret is created successfully:
secret/slack-credentials created
Implementation¶
Step 0: Learn about Pipe¶
We use a feature called "Pipe" (a.k.a KameletBinding) in Apache Camel K to link event sources and destinations. Specifically, the Pipe connects events from our Broker, our source, to the Slack channel through a Slack sink Kamelet, our destination.
From the sample YAML below, you can see we are telling the pipe to filter on the events that have type "moderated-comment". Pipe will create a Trigger under the hood and route your event to slack-sink.
apiVersion: camel.apache.org/v1
kind: Pipe
metadata:
name: pipe
spec:
source:
ref:
kind: Broker
apiVersion: eventing.knative.dev/v1
name: badword-broker
properties:
type: moderated-comment
sink:
...
If you hope to learn more about it, check out the article Event Sourcing with Apache Camel K and Knative Eventing by Matthias Weßendorf!
Step 1: Create the Broker that can route "bad word" comments to Slack¶
In the current implementation using Apache Camel K, we can only filter based on the CloudEvent's type, such as moderated-comment. Filtering based on event extensions, such as badwordfilter: good
, is not yet supported. This feature will be available in a future update of Apache Camel K. But we can still use an alternative way to achieve this!
Here, we will be connecting bookstore-broker
with a new Broker called badword-broker
. And we will be creating a Trigger that helps us perform the filtering with the extension badwordfilter: good
.
- 1: Create a new file named
slack-sink/config/100-broker.yaml
and add the following content:
slack-sink/config/100-broker.yaml
---
apiVersion: eventing.knative.dev/v1
kind: Broker
metadata:
name: badword-broker
-
2: Apply the YAML file:
kubectl apply -f slack-sink/config/100-broker.yaml
You should see this message if the Broker is created successfully:
broker.eventing.knative.dev/badword-broker created
Alternatively, use the Knative CLI kn
to create the broker:
kn broker create badword-broker
You should see this message if the Broker is created successfully:
Broker 'badword-broker' successfully created in namespace 'default'.
Verify
Run the following command to list the Brokers:
kubectl get brokers
You should see the badword-broker
listed.
NAME URL AGE READY REASON
badword-broker http://broker-ingress.knative-eventing.svc.cluster.local/default/badword-broker 3s True
bookstore-broker http://broker-ingress.knative-eventing.svc.cluster.local/default/bookstore-broker 5h38m True
Troubleshooting
If there are issues, use the following command to diagnose:
kubectl describe broker badword-broker
Step 2: Create Trigger that filters for bad word comments to badword-broker¶
We are creating the Trigger to process the events that have type moderated-comment
, and the extension badwordfilter: bad
and route them to badword-broker
.
Create a Trigger:
- 1: Append the following content to your
slack-sink/config/100-broker.yaml
:
slack-sink/config/100-broker.yaml
---
apiVersion: eventing.knative.dev/v1
kind: Trigger
metadata:
name: badword-noti-trigger
spec:
broker: bookstore-broker
filter:
attributes: # Trigger will filter events based on BOTH the type and badwordfilter attribute
type: moderated-comment # This is the filter that will be applied to the event, only events with the ce-type moderated-comment will be processed
badwordfilter: bad # This is the filter that will be applied to the event, only events with the ce-extension badwordfilter: bad will be processed
subscriber:
ref:
apiVersion: eventing.knative.dev/v1
kind: Broker
name: badword-broker
-
2: Apply the YAML file:
kubectl apply -f slack-sink/config/100-broker.yaml
You should see this message if the Trigger is created successfully:
broker.eventing.knative.dev/badword-broker unchanged trigger.eventing.knative.dev/badword-noti-trigger created
Verify
kubectl get triggers
The Trigger badword-noti-trigger
should have READY
status as True
.
NAME BROKER SUBSCRIBER_URI AGE READY REASON
db-insert-trigger bookstore-broker http://node-server-svc.default.svc.cluster.local/insert 5h41m True
seq-reply-trigger bookstore-broker http://event-display.default.svc.cluster.local 5h39m True
sequence-trigger bookstore-broker http://sequence-kn-sequence-0-kn-channel.default.svc.cluster.local 5h39m True
log-trigger bookstore-broker http://event-display.default.svc.cluster.local 5h41m True
badword-noti-triggerbookstore-broker http://broker-ingress.knative-eventing.svc.cluster.local/default/badword-broker 5h41m True
Step 3: Build the Pipe¶
This setup automatically sends notifications to Slack whenever a new comment that contains "bad word" occur, streamlining the flow of information.
-
1: Make sure you have your k8s secret that contains your Slack webhook Url ready. If not, refer to the Prerequisite 3 section.
-
2: Prepare the YAML configuration for the Slack sink, which will forward events to your Slack channel:
Create a new file named slack-sink/config/100-slack-sink.yaml
and add the following content:
slack-sink/config/100-slack-sink.yaml
apiVersion: camel.apache.org/v1
kind: Pipe
metadata:
name: pipe
annotations:
trait.camel.apache.org/mount.configs: "secret:slack-credentials"
spec:
source:
ref:
kind: Broker
apiVersion: eventing.knative.dev/v1
name: badword-broker
properties:
type: moderated-comment
sink:
ref:
kind: Kamelet
apiVersion: camel.apache.org/v1
name: slack-sink
properties:
channel: ${slack.channel}
webhookUrl: ${slack.webhook.url}
- Apply the configuration to your Kubernetes cluster:
kubectl apply -f slack-sink/config/100-slack-sink.yaml
Verify
You will see this message if the configuration is created successfully:
pipe.camel.apache.org/pipe created
But this process will take a few seconds to complete. You can check the status of the pipe by running the following command:
kubectl get pipe pipe
NAME PHASE REPLICAS
pipe Ready 1
Step 4: Modify the Knative Services to disable scale to zero¶
In this step, we'll configure the notification delivery service to prevent it from scaling down to zero, ensuring timely notifications.
Note
ksvc
stands for Knative Service.
- Check Existing Knative Services:
kubectl get ksvc
You should see a service named pipe
listed:
NAME URL LATESTCREATED LATESTREADY READY REASON
pipe http://pipe.default.svc.cluster.local pipe-00002 pipe-00002 True
- Edit the Knative Service:
To prevent the notification service from scaling down to zero, set the minimum number of pods to keep running.
kubectl patch ksvc pipe --type merge -p '{"spec":{"template":{"metadata":{"annotations":{"autoscaling.knative.dev/min-scale":"1"}}}}}'
Or use the edit command:
kubectl edit ksvc pipe
Add the following annotation:
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/min-scale: "1"
This configuration ensures that Knative will always maintain at least one instance of the service running.
Verify
kubectl get pods
Periodically check the status of the pipe-deployment pods, and see whether they will disappear! If they stay there, then we are good!
Verification¶
Now, you have completed building the sample app. When you submit a "bad" comment, you should receive a notification in your test Slack workspace, achieving the same result as shown in the demo video.
Conclusion¶
In this tutorial, you learned how to set up an event-driven service that automates notifications to a Slack channel using Knative Eventing and Apache Camel K. By leveraging these technologies, you can seamlessly connect your applications to third-party services and facilitate real-time information exchange between them.
Next Step¶
Congratulations on successfully completing the bookstore sample app tutorial! If you want to deepen your understanding of Knative, open your bookstore front end, the demo book we used is a great starting point! Check the book "Building Serverless Applications on Knative" by Evan Anderson.
We've prepared additional challenges that build on top of the existing bookstore app for you to tackle. Some solutions are provided, while others are left open to encourage you to explore your own solutions.