Sample App Tutorial Page Compilation (#6007)

* feat: add the first three pages of the sample app tutorial

* Apply suggestions from code review

Co-authored-by: Pierangelo Di Pilato <pierangelodipilato@gmail.com>

* fix: fix the review comments in pg0 and pg1

* feat: add blog post 2

* feat: adding the images for page 2

* add: add more pages

* add: adding the rest of the pages

* add: modify the nav

* add: finishing polishing

* fix: update the iframe embedded video link

* fix: fix the video embedding dimension and the access

* fix: link minor error fix

* fix: hide the setup script section

* Apply suggestions from code review

Co-authored-by: Christoph Stäbler <cstabler@redhat.com>

* Update docs/bookstore/page-0/page-0-intro.md

Co-authored-by: Christoph Stäbler <cstabler@redhat.com>

* Update docs/bookstore/page-0.5/pg0.5-env-setup.md

Co-authored-by: Christoph Stäbler <cstabler@redhat.com>

* fix: fix christoph's comment

* fix: Remove all the extra new lines

* fix: update kubernetes to Kubernetes

* Apply suggestions from code review

Co-authored-by: Pierangelo Di Pilato <pierangelodipilato@gmail.com>
Co-authored-by: Christoph Stäbler <cstabler@redhat.com>

* fix: fix the wrong indentation in the yaml files

* Update docs/bookstore/page-2/pg2-sentiment-svc.md

Co-authored-by: Christoph Stäbler <cstabler@redhat.com>

* fix: fix review comments

* fix: change the console output to text - pg0.5

* fix: replace the console output pic with plaintextg for pg1

* fix: replace the console output pic with plaintext for pg 2&3

* fix: replace the console output pic with plaintext for pg 4

* fix: replace the console output pic with plaintext for pg 5

* fix: replace the console output pic with plaintext for pg 6

* fix: replace the console output pic with plaintext for pg 7

* fix: fix christoph's comments

* Apply suggestions from code review

Co-authored-by: Christoph Stäbler <cstabler@redhat.com>

* fix: applying christoph's comments fix

* fix: fix christoph's nit comments + open the link in new tab

* fix: make sure all the command have the same root which is /start

* fix: make all the links open in the new tab

* fix: fix small errors

* fix: remove default namespace

* Update docs/bookstore/page-1/pg1-review-svc-1.md

Co-authored-by: Christoph Stäbler <cstabler@redhat.com>

* Apply suggestions from code review

Co-authored-by: Christoph Stäbler <cstabler@redhat.com>

* fix: update the wording to follow the Knative's branding guideline

* fix: update the wording to follow the Knative's branding guideline

* fix: update the naming of the pages

* fix: fixing the wrong link in the tutorial.md page

* Apply the patch from Christoph

Co-authored-by: Christoph Stäbler <cstabler@redhat.com>

* Apply suggestions from code review

Co-authored-by: Christoph Stäbler <cstabler@redhat.com>

* Update docs/bookstore/page-1/send-review-comment-to-broker.md

Co-authored-by: Pierangelo Di Pilato <pierangelodipilato@gmail.com>

---------

Co-authored-by: Pierangelo Di Pilato <pierangelodipilato@gmail.com>
Co-authored-by: Christoph Stäbler <cstabler@redhat.com>
This commit is contained in:
Leo Li 2024-06-26 03:42:43 -04:00 committed by GitHub
parent ac4af722d0
commit 54207bebd6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
150 changed files with 2799 additions and 81 deletions

View File

@ -20,10 +20,10 @@ The function's output will be only from
---
### Prerequisite 1: Install Knative `func` CLI
Knative Function enables you to easily create, build, and deploy stateless, event-driven functions as [Knative Services](https://knative.dev/docs/serving/services/#:~:text=Knative%20Services%20are%20used%20to,the%20Service%20to%20be%20configured) by using the func CLI.
Knative Function enables you to easily create, build, and deploy stateless, event-driven functions as [Knative Services](https://knative.dev/docs/serving/services/#:~:text=Knative%20Services%20are%20used%20to,the%20Service%20to%20be%20configured){:target="_blank"} by using the func CLI.
In order to do so, you need to install the `func` CLI.
You can follow the [official documentation](https://knative.dev/docs/getting-started/install-func/) to install the `func` CLI.
You can follow the [official documentation](https://knative.dev/docs/getting-started/install-func/){:target="_blank"} to install the `func` CLI.
Running `func version` in your terminal to verify the installation, and you should see the version of the `func` CLI you installed.
@ -55,7 +55,7 @@ func create -l python sentiment-analysis
This command will create a new directory with the name `sentiment-analysis` and a bunch of files in it. The `func` CLI will generate a basic function template for you to start with.
You can find all the supported languages templates [here](https://knative.dev/docs/functions/).
You can find all the supported languages templates [here](https://knative.dev/docs/functions/){:target="_blank"}.
The file tree will look like this:
```bash
@ -175,7 +175,7 @@ setup(
### Step 5: Try to build and run your Knative Function on your local machine
In knative function, there are two ways to build: using the [pack build](https://github.com/knative/func/blob/8f3f718a5a036aa6b6eaa9f70c03aeea740015b9/docs/reference/func_build.md?plain=1#L46) or using the [source-to-image (s2i) build](https://github.com/knative/func/blob/4f48549c8ad4dad34bf750db243d81d503f0090f/docs/reference/func_build.md?plain=1#L43).
In knative function, there are two ways to build: using the [pack build](https://github.com/knative/func/blob/8f3f718a5a036aa6b6eaa9f70c03aeea740015b9/docs/reference/func_build.md?plain=1#L46){:target="_blank"} or using the [source-to-image (s2i) build](https://github.com/knative/func/blob/4f48549c8ad4dad34bf750db243d81d503f0090f/docs/reference/func_build.md?plain=1#L43){:target="_blank"}.
Currently. only the **s2i** build is supported if you need to run setup.py. When building with s2i, the `setup.py` file will be executed automatically after the dependencies have been installed.
@ -255,7 +255,7 @@ Knative function also have an easy way to simulate the CloudEvent, you can use t
func invoke -f=cloudevent --data='{"input": "I love Knative so much"}' --content-type=application/json --type="new-comment" -v
```
where the `-f` flag indicates the type of the data, is either `HTTP` or `cloudevent`, and the `--data` flag is the input text.
You can read more about `func invoke` [here](https://github.com/knative/func/blob/main/docs/reference/func_invoke.md).
You can read more about `func invoke` [here](https://github.com/knative/func/blob/main/docs/reference/func_invoke.md){:target="_blank"}.
In this case, you will get the full CloudEvent response:
@ -302,7 +302,7 @@ NAMESPACE NAME URL
default sentiment-analysis-app http://sentiment-analysis-app.default.10.99.46.8.sslip.io sentiment-analysis-app-00002 sentiment-analysis-app-00002 True
```
Please note: if your URL ends with .svc.cluster.local, that means you can only access the function from within the cluster. You probably forget to configure the network or [start the tunnel](https://knative.dev/docs/getting-started/quickstart-install/#__tabbed_3_2) if you are using minikube.
Please note: if your URL ends with .svc.cluster.local, that means you can only access the function from within the cluster. You probably forget to configure the network or [start the tunnel](https://knative.dev/docs/getting-started/quickstart-install/#__tabbed_3_2){:target="_blank"} if you are using minikube.
### Step 7: Verify the Deployment
After deployment, the `func` CLI provides a URL to access your function. You can verify the function's operation by sending a request with a sample review comment.
@ -340,8 +340,8 @@ Recall note box: you can get the URL to the function by running the following co
kubectl get kservice -A
```
---
Another option is to use curl to send a CloudEvent to the function.
Using curl command to send a CloudEvent to the broker:
Another option is to use curl to send a CloudEvents to the function.
Using curl command to send a CloudEvents to the Broker:
```bash
[root@curler:/]$ curl -v "http://sentiment-analysis-app.default.10.99.46.8.sslip.io" \
-X POST \

View File

@ -4,12 +4,12 @@
To create a Slack workspace, follow these steps:
- Visit [https://slack.com/get-started#/createnew](https://slack.com/get-started#/createnew).
- Visit [https://slack.com/get-started#/createnew](https://slack.com/get-started#/createnew){:target="_blank"}.
- Enter your email address and click Continue, or continue with Apple or Google.
- Check your email for a confirmation code.
- Enter the code on the Slack website.
- Click "Create a Workspace" and follow the prompts.
- For detailed instructions for androids and , refer to [Create a workspace](https://slack.com/help/articles/206845317-Create-a-Slack-workspace).
- For detailed instructions how to create a workspace via the Desktop App, on Android or iOS, refer to [Create a Slack workspace](https://slack.com/help/articles/206845317-Create-a-Slack-workspace){:target="_blank"}.
## Adding Channels to Your Workspace
@ -17,13 +17,13 @@ After creating your Slack workspace, you can add channels by following these ste
- Click the '+' icon next to 'Channels' on the sidebar of your Slack workspace.
- Choose "Create a channel" and specify the channel name and purpose.
- For enterprise grid organizations, refer to [Slack's help article](https://slack.com/help/articles/115001399587-Add-a-channel-to-multiple-workspaces-in-your-Enterprise-Grid-organization) for instructions.
- For enterprise grid organizations, refer to [Slack's help article](https://slack.com/help/articles/115001399587-Add-a-channel-to-multiple-workspaces-in-your-Enterprise-Grid-organization){:target="_blank"} for instructions.
## Setting Up a Webhook for Notifications
To set up a webhook for sending notifications to your Slack workspace:
- Create a [Slack app](https://api.slack.com/apps/new), following the instructions by signing in, adding name and workspace to put the app in.
- Create a [Slack app](https://api.slack.com/apps/new){:target="_blank"}, following the instructions by signing in, adding name and workspace to put the app in.
- After this, you'll be redirected to the setting pages of your new app. Choose **Incoming Webhook** and toggle **Activate Webhook**.
- Scroll down to click the option **Add New Webhook to Workspace**.
![Alt text](./screenshots/select-channel.png)
@ -33,4 +33,4 @@ To set up a webhook for sending notifications to your Slack workspace:
![Alt text](./screenshots/Postman.png)
- Afterwards, the text channel should have a new message
![Alt text](./screenshots/result.png)
- Go to [Slack's webhook documentation](https://api.slack.com/messaging/webhooks) to learn more about setting up webhooks.
- Go to [Slack's webhook documentation](https://api.slack.com/messaging/webhooks){:target="_blank"} to learn more about setting up webhooks.

View File

@ -89,20 +89,20 @@ If the output lists the `BookReviews` table as follows, your database has been c
## Question & Discussion
1. Why did we choose to deploy our PostgreSQL database using a StatefulSet instead of a Knative Service?
We use [StatefulSet](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) for databases instead of Knative Service mainly because databases need to remember data (like a notebook that keeps your notes). StatefulSets are good at remembering things because they can save data and have a special name and place where they live. This is very important for databases.
We use [StatefulSet](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/){:target="_blank"} for databases instead of Knative Service mainly because databases need to remember data (like a notebook that keeps your notes). StatefulSets are good at remembering things because they can save data and have a special name and place where they live. This is very important for databases.
Knative Services are more like notebooks that you use and then throw away when you're done. They're great for tasks that don't need to keep data for a long time. You can make them go away when you don't need them and come back when you do. But databases need to always remember information, so they can't just disappear and come back.
Also, databases often talk in their own special language, not the usual web language (HTTP) that Knative Services are really good at understanding. Because of this, Knative Services aren't the best choice for databases. That's why we choose StatefulSet for databases in Kubernetes.
---
Note box: However, Knative Service supports Volumes and Persistent Volumes, which can be used to store data. You can read more [here](https://knative.dev/docs/serving/services/storage/) about how to use Volumes and Persistent Volumes with Knative Services specially for your use case.
Note box: However, Knative Service supports Volumes and Persistent Volumes, which can be used to store data. You can read more [here](https://knative.dev/docs/serving/services/storage/){:target="_blank"} about how to use Volumes and Persistent Volumes with Knative Services specially for your use case.
---
2. When should I use Knative Service, and what would be the best use case for it?
You can read more about the best use cases for Knative Service [here](https://knative.dev/docs/serving/samples/)!
You can read more about the best use cases for Knative Service [here](https://knative.dev/docs/serving/samples/){:target="_blank"}!
## Conclusion
By following this guide, you have successfully deployed a PostgreSQL server on a Kubernetes cluster, set up persistent storage, and initialized your database using a Kubernetes job. Congratulations! Your bookstore now has the database service.

View File

@ -18,7 +18,7 @@ pnpm dev
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
Open [http://localhost:3000](http://localhost:3000){:target="_blank"} with your browser to see the result.
# Project Structures
@ -33,7 +33,7 @@ This repository contains a Next.js application that utilizes next-themes and Tai
## Prerequisites
- Docker installed on your machine. You can download and install Docker from [here](https://www.docker.com/get-started).
- Docker installed on your machine. You can download and install Docker from [here](https://www.docker.com/get-started){:target="_blank"}.
## Dockerization Steps

View File

@ -1,4 +1,3 @@
apiVersion: apps/v1
kind: Deployment
metadata:

View File

@ -10,7 +10,7 @@ spec:
selector:
matchLabels:
app: node-server
sink: # In this case, the sink is our broker, which is the eventing service that will receive the events
sink: # In this case, the sink is our Broker, which is the eventing service that will receive the events
ref:
apiVersion: eventing.knative.dev/v1
kind: Broker

View File

@ -98,7 +98,7 @@ app.post('/add', async (req, res) => {
const brokerURI = process.env.K_SINK;
if (receivedEvent.type === 'new-review-comment') {
// Forward the event to the broker with the necessary CloudEvent headers
// Forward the event to the Broker with the necessary CloudEvent headers
const response = await fetch(brokerURI, {
method: 'POST',
headers: {

View File

@ -15,7 +15,7 @@ spec:
apiVersion: serving.knative.dev/v1
kind: Service
name: sentiment-analysis-app
reply: # This is the last step of the sequence, it will send the event back to the broker as reply
reply: # This is the last step of the sequence, it will send the event back to the Broker as reply
ref:
kind: Broker
apiVersion: eventing.knative.dev/v1

View File

@ -21,10 +21,10 @@ kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v
kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.14.0/eventing-core.yaml
echo "Knative Eventing installed successfully."
# Install Knative imc broker
# Install Knative imc Broker
kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.14.0/in-memory-channel.yaml
kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.14.0/mt-channel-broker.yaml
echo "Knative in-memory channel and broker installed successfully."
echo "Knative in-memory Channel and Broker installed successfully."
# Detect whether the user has knative function "func" installed
if ! command -v func &> /dev/null

View File

@ -11,7 +11,7 @@ When a CloudEvent with the type `new-review-comment` is sent to the Knative Even
## Install prerequisites
### Prerequisite 1: Install Camel CLI
Install the Camel K CLI (`kamel`) on your local machine. You can find the installation instructions [here](https://camel.apache.org/camel-k/2.2.x/cli/cli.html).
Install the Camel K CLI (`kamel`) on your local machine. You can find the installation instructions [here](https://camel.apache.org/camel-k/2.2.x/cli/cli.html){:target="_blank"}.
**Troubleshot**: If after installation you run `kamel version` and you get an error message, you may need to add the `kamel` binary to your system's PATH. You can do this by moving the `kamel` binary to a directory that is already in your PATH, or by adding the directory where `kamel` is located to your PATH.
@ -29,7 +29,7 @@ $ kamel install --registry docker.io --organization <your-organization> --regist
Replace the placeholders with your actual Docker registry information.
If you are using other container registries, you may need to read more [here](https://camel.apache.org/camel-k/2.2.x/installation/registry/registry.html) for the installation.
If you are using other container registries, you may need to read more [here](https://camel.apache.org/camel-k/2.2.x/installation/registry/registry.html){:target="_blank"} for the installation.
You will see this message if the installation is successful:
@ -43,19 +43,19 @@ Follow the instruction here on how to create the slack workspace and generate an
## Implementation
### Step 1: Create the Broker
This broker is created solely for testing purposes and is intended for temporary use during this part of the tutorial only.
This Broker is created solely for testing purposes and is intended for temporary use during this part of the tutorial only.
**Method 1**: Initialize a broker within your Kubernetes cluster using the Knative CLI:
**Method 1**: Initialize a Broker within your Kubernetes cluster using the Knative CLI:
```bash
$ kn broker create book-review-broker
```
You will see this message if the broker is created successfully:
You will see this message if the Broker is created successfully:
```
Broker book-review-broker successfully created in namespace default.
Broker 'book-review-broker' successfully created in namespace 'default'.
```
**Method 2**: You can create a new YAML file to create the broker:
**Method 2**: You can create a new YAML file to create the Broker:
*new-knative-broker.yaml*
```yaml
@ -70,7 +70,7 @@ After you saved the file, you can apply the configuration to your Kubernetes clu
```bash
$ kubectl apply -f new-knative-broker.yaml
```
You will see this message if the broker is created successfully:
You will see this message if the Broker is created successfully:
```
broker.eventing.knative.dev/book-review-broker created
@ -139,9 +139,9 @@ slack-sink-pipe Ready 1
To trigger notifications, you'll need to simulate an event that matches the criteria set in your Slack sink configuration. For example, submitting a book review could be an event of type `new-review-comment`.
Directly sending CloudEvents to a broker using curl from an external machine (like your local computer) is typically **constrained** due to the networking and security configurations of Kubernetes clusters.
Directly sending CloudEvents to a Broker using curl from an external machine (like your local computer) is typically **constrained** due to the networking and security configurations of Kubernetes clusters.
Therefore, you need to create a new pod in your Kubernetes cluster to send a CloudEvent to the broker. You can use the following command to create a new pod:
Therefore, you need to create a new pod in your Kubernetes cluster to send a CloudEvent to the Broker. You can use the following command to create a new pod:
```bash
$ kubectl run curler --image=radial/busyboxplus:curl -it --restart=Never
@ -154,9 +154,9 @@ If you don't see a command prompt, try pressing enter.
```
Using curl command to send a CloudEvent to the broker:
Using curl command to send a CloudEvent to the Broker:
```bash
[root@curler:/]$ curl -v "<The URI to your broker>" \
[root@curler:/]$ curl -v "<The URI to your Broker>" \
-X POST \
-H "Ce-Id: review1" \
-H "Ce-Specversion: 1.0" \
@ -166,7 +166,7 @@ Using curl command to send a CloudEvent to the broker:
-d 'Hello from Knative!'
```
You can find the URI to your broker by running the following command:
You can find the URI to your Broker by running the following command:
```bash
$ kubectl get broker book-review-broker

View File

@ -89,20 +89,20 @@ If the output lists the `BookReviews` table as follows, your database has been c
## Question & Discussion
1. Why did we choose to deploy our PostgreSQL database using a StatefulSet instead of a Knative Service?
We use [StatefulSet](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) for databases instead of Knative Service mainly because databases need to remember data (like a notebook that keeps your notes). StatefulSets are good at remembering things because they can save data and have a special name and place where they live. This is very important for databases.
We use [StatefulSet](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/){:target="_blank"} for databases instead of Knative Service mainly because databases need to remember data (like a notebook that keeps your notes). StatefulSets are good at remembering things because they can save data and have a special name and place where they live. This is very important for databases.
Knative Services are more like notebooks that you use and then throw away when you're done. They're great for tasks that don't need to keep data for a long time. You can make them go away when you don't need them and come back when you do. But databases need to always remember information, so they can't just disappear and come back.
Also, databases often talk in their own special language, not the usual web language (HTTP) that Knative Services are really good at understanding. Because of this, Knative Services aren't the best choice for databases. That's why we choose StatefulSet for databases in Kubernetes.
---
Note box: However, Knative Service supports Volumes and Persistent Volumes, which can be used to store data. You can read more [here](https://knative.dev/docs/serving/services/storage/) about how to use Volumes and Persistent Volumes with Knative Services specially for your use case.
Note box: However, Knative Service supports Volumes and Persistent Volumes, which can be used to store data. You can read more [here](https://knative.dev/docs/serving/services/storage/){:target="_blank"} about how to use Volumes and Persistent Volumes with Knative Services specially for your use case.
---
2. When should I use Knative Service, and what would be the best use case for it?
You can read more about the best use cases for Knative Service [here](https://knative.dev/docs/serving/samples/)!
You can read more about the best use cases for Knative Service [here](https://knative.dev/docs/serving/samples/{:target="_blank"}!
## Conclusion
By following this guide, you have successfully deployed a PostgreSQL server on a Kubernetes cluster, set up persistent storage, and initialized your database using a Kubernetes job. Congratulations! Your bookstore now has the database service.

View File

@ -18,7 +18,7 @@ pnpm dev
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
Open [http://localhost:3000](http://localhost:3000){:target="_blank"} with your browser to see the result.
# Project Structures
@ -33,7 +33,7 @@ This repository contains a Next.js application that utilizes next-themes and Tai
## Prerequisites
- Docker installed on your machine. You can download and install Docker from [here](https://www.docker.com/get-started).
- Docker installed on your machine. You can download and install Docker from [here](https://www.docker.com/get-started){:target="_blank"}.
## Dockerization Steps

View File

@ -98,7 +98,7 @@ app.post('/add', async (req, res) => {
const brokerURI = process.env.K_SINK;
if (receivedEvent.type === 'new-review-comment') {
// Forward the event to the broker with the necessary CloudEvent headers
// Forward the event to the Broker with the necessary CloudEvent headers
const response = await fetch(brokerURI, {
method: 'POST',
headers: {

View File

@ -21,10 +21,10 @@ kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v
kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.14.0/eventing-core.yaml
echo "Knative Eventing installed successfully."
# Install Knative imc broker
# Install Knative imc Broker
kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.14.0/in-memory-channel.yaml
kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.14.0/mt-channel-broker.yaml
echo "Knative in-memory channel and broker installed successfully."
echo "Knative in-memory Channel and Broker installed successfully."
# Detect whether the user has knative function "func" installed
if ! command -v func &> /dev/null

View File

@ -11,7 +11,7 @@ When a CloudEvent with the type `new-review-comment` is sent to the Knative Even
## Install prerequisites
### Prerequisite 1: Install Camel CLI
Install the Camel K CLI (`kamel`) on your local machine. You can find the installation instructions [here](https://camel.apache.org/camel-k/2.2.x/cli/cli.html).
Install the Camel K CLI (`kamel`) on your local machine. You can find the installation instructions [here](https://camel.apache.org/camel-k/2.2.x/cli/cli.html){:target="_blank"}.
**Troubleshot**: If after installation you run `kamel version` and you get an error message, you may need to add the `kamel` binary to your system's PATH. You can do this by moving the `kamel` binary to a directory that is already in your PATH, or by adding the directory where `kamel` is located to your PATH.
@ -29,7 +29,7 @@ $ kamel install --registry docker.io --organization <your-organization> --regist
Replace the placeholders with your actual Docker registry information.
If you are using other container registries, you may need to read more [here](https://camel.apache.org/camel-k/2.2.x/installation/registry/registry.html) for the installation.
If you are using other container registries, you may need to read more [here](https://camel.apache.org/camel-k/2.2.x/installation/registry/registry.html){:target="_blank"} for the installation.
You will see this message if the installation is successful:
@ -43,19 +43,19 @@ Follow the instruction here on how to create the slack workspace and generate an
## Implementation
### Step 1: Create the Broker
This broker is created solely for testing purposes and is intended for temporary use during this part of the tutorial only.
This Broker is created solely for testing purposes and is intended for temporary use during this part of the tutorial only.
**Method 1**: Initialize a broker within your Kubernetes cluster using the Knative CLI:
**Method 1**: Initialize a Broker within your Kubernetes cluster using the Knative CLI:
```bash
$ kn broker create book-review-broker
```
You will see this message if the broker is created successfully:
You will see this message if the Broker is created successfully:
```
Broker book-review-broker successfully created in namespace default.
Broker 'book-review-broker' successfully created in namespace 'default'.
```
**Method 2**: You can create a new YAML file to create the broker:
**Method 2**: You can create a new YAML file to create the Broker:
*new-knative-broker.yaml*
```yaml
@ -70,7 +70,7 @@ After you saved the file, you can apply the configuration to your Kubernetes clu
```bash
$ kubectl apply -f new-knative-broker.yaml
```
You will see this message if the broker is created successfully:
You will see this message if the Broker is created successfully:
```
broker.eventing.knative.dev/book-review-broker created
@ -79,7 +79,7 @@ broker.eventing.knative.dev/book-review-broker created
### Step 2: Configure the Slack Sink
We use a feature called "Pipe" in Camel K to link event sources and destinations. Specifically, the Pipe connects events from a Broker, our source, to a Slack channel through a Slack sink Kamelet, our destination. This setup automatically sends notifications to Slack whenever new events occur, streamlining the flow of information.
We use a feature called "Pipe" in Apache Camel K to link event sources and destinations. Specifically, the Pipe connects events from a Broker, our source, to a Slack channel through a Slack sink Kamelet, our destination. This setup automatically sends notifications to Slack whenever new events occur, streamlining the flow of information.
1. Create a Slack app and generate an incoming webhook URL for your designated channel where notifications will be sent. Refer to Slack documentation for how to do this.
@ -139,9 +139,9 @@ slack-sink-pipe Ready 1
To trigger notifications, you'll need to simulate an event that matches the criteria set in your Slack sink configuration. For example, submitting a book review could be an event of type `new-review-comment`.
Directly sending CloudEvents to a broker using curl from an external machine (like your local computer) is typically **constrained** due to the networking and security configurations of Kubernetes clusters.
Directly sending CloudEvents to a Broker using curl from an external machine (like your local computer) is typically **constrained** due to the networking and security configurations of Kubernetes clusters.
Therefore, you need to create a new pod in your Kubernetes cluster to send a CloudEvent to the broker. You can use the following command to create a new pod:
Therefore, you need to create a new pod in your Kubernetes cluster to send a CloudEvent to the Broker. You can use the following command to create a new pod:
```bash
$ kubectl run curler --image=radial/busyboxplus:curl -it --restart=Never
@ -154,7 +154,7 @@ If you don't see a command prompt, try pressing enter.
```
Using curl command to send a CloudEvent to the broker:
Using curl command to send a CloudEvents to the Broker:
```bash
[root@curler:/]$ curl -v "<The URI to your broker>" \
-X POST \
@ -166,7 +166,7 @@ Using curl command to send a CloudEvent to the broker:
-d 'Hello from Knative!'
```
You can find the URI to your broker by running the following command:
You can find the URI to your Broker by running the following command:
```bash
$ kubectl get broker book-review-broker

View File

@ -16,4 +16,4 @@
#
slack.channel=#bookstore-owner
slack.webhook.url=
slack.webhook.url=https://hooks.slack.com/services/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

View File

@ -4,12 +4,12 @@
To create a Slack workspace, follow these steps:
- Visit [https://slack.com/get-started#/createnew](https://slack.com/get-started#/createnew).
- Visit [https://slack.com/get-started#/createnew](https://slack.com/get-started#/createnew){:target="_blank"}.
- Enter your email address and click Continue, or continue with Apple or Google.
- Check your email for a confirmation code.
- Enter the code on the Slack website.
- Click "Create a Workspace" and follow the prompts.
- For detailed instructions for androids and , refer to [Create a workspace](https://slack.com/help/articles/206845317-Create-a-Slack-workspace).
- For detailed instructions for androids and , refer to [Create a workspace](https://slack.com/help/articles/206845317-Create-a-Slack-workspace){:target="_blank"}.
## Adding Channels to Your Workspace
@ -17,13 +17,13 @@ After creating your Slack workspace, you can add channels by following these ste
- Click the '+' icon next to 'Channels' on the sidebar of your Slack workspace.
- Choose "Create a channel" and specify the channel name and purpose.
- For enterprise grid organizations, refer to [Slack's help article](https://slack.com/help/articles/115001399587-Add-a-channel-to-multiple-workspaces-in-your-Enterprise-Grid-organization) for instructions.
- For enterprise grid organizations, refer to [Slack's help article](https://slack.com/help/articles/115001399587-Add-a-channel-to-multiple-workspaces-in-your-Enterprise-Grid-organization){:target="_blank"} for instructions.
## Setting Up a Webhook for Notifications
To set up a webhook for sending notifications to your Slack workspace:
- Create a [Slack app](https://api.slack.com/apps/new), following the instructions by signing in, adding name and workspace to put the app in.
- Create a [Slack app](https://api.slack.com/apps/new){:target="_blank"}, following the instructions by signing in, adding name and workspace to put the app in.
- After this, you'll be redirected to the setting pages of your new app. Choose **Incoming Webhook** and toggle **Activate Webhook**.
- Scroll down to click the option **Add New Webhook to Workspace**.
![Alt text](./screenshots/select-channel.png)

View File

@ -20,24 +20,38 @@ nav:
# Getting started
###############################################################################
- Tutorial:
- Tutorial introduction: getting-started/README.md
- Install Knative using quickstart: getting-started/quickstart-install.md
- Knative Functions:
- About Knative Functions: getting-started/about-knative-functions.md
- Installing Knative Functions: getting-started/install-func.md
- Creating a function: getting-started/create-a-function.md
- Building, running, or deploying a function: getting-started/build-run-deploy-func.md
- Knative Serving:
- Deploying a Knative Service: getting-started/first-service.md
- Autoscaling: getting-started/first-autoscale.md
- Traffic splitting: getting-started/first-traffic-split.md
- Knative Eventing:
- About Knative Eventing: getting-started/getting-started-eventing.md
- Sources, Brokers, and Triggers: getting-started/first-broker.md
- Using a Knative Service as a source: getting-started/first-source.md
- Using Triggers and sinks: getting-started/first-trigger.md
- What's Next?: getting-started/next-steps.md
- Clean Up: getting-started/clean-up.md
- Overview: getting-started/tutorial.md
- Quickstart:
- Tutorial introduction: getting-started/README.md
- Install Knative using quickstart: getting-started/quickstart-install.md
- Knative Functions:
- About Knative Functions: getting-started/about-knative-functions.md
- Installing Knative Functions: getting-started/install-func.md
- Creating a function: getting-started/create-a-function.md
- Building, running, or deploying a function: getting-started/build-run-deploy-func.md
- Knative Serving:
- Deploying a Knative Service: getting-started/first-service.md
- Autoscaling: getting-started/first-autoscale.md
- Traffic splitting: getting-started/first-traffic-split.md
- Knative Eventing:
- About Knative Eventing: getting-started/getting-started-eventing.md
- Sources, Brokers, and Triggers: getting-started/first-broker.md
- Using a Knative Service as a source: getting-started/first-source.md
- Using Triggers and sinks: getting-started/first-trigger.md
- What's Next?: getting-started/next-steps.md
- Clean Up: getting-started/clean-up.md
- "E2E tutorial: Knative Bookstore":
- Overview: bookstore/page-0/welcome-knative-bookstore-tutorial.md
- Disclaimer: bookstore/disclaimer/README.md
- Environment Setup: bookstore/page-0.5/environment-setup.md
- 1 - Send Comments to Broker: bookstore/page-1/send-review-comment-to-broker.md
- 2 - Create Sentiment Service: bookstore/page-2/sentiment-analysis-service-for-bookstore-reviews.md
- 3 - Create Bad Word Service: bookstore/page-3/create-bad-word-filter-service.md
- 4 - Create Sequence: bookstore/page-4/create-sequence-to-streamline-ML-workflows.md
- 5 - Create DB service: bookstore/page-5/deploy-database-service.md
- 6 - Advanced event filtering: bookstore/page-6/advanced-event-filtering.md
- 7 - Connect Slack via Camel-K: bookstore/page-7/slack-sink-learning-knative-eventing-and-apache-camel-K-integration.md
- 8 - Extra Challenges: bookstore/extra-challenge/README.md
###############################################################################
# Installing
###############################################################################

View File

@ -0,0 +1,46 @@
# Creating a Slack Workspace
![Image](images/image5.png)
To create a Slack workspace, follow these steps:
1. Visit [https://slack.com/get-started#/createnew](https://slack.com/get-started#/createnew){:target="_blank"}.
2. Enter your email address and click Continue, or continue with Apple or Google.
3. Check your email for a confirmation code.
4. Enter the code on the Slack website.
5. Click "Create a Workspace" and follow the prompts.
6. For detailed instructions how to create a workspace via the Desktop App, Android or iOS, refer to [Create a Slack workspace](https://slack.com/help/articles/206845317-Create-a-Slack-workspace){:target="_blank"}.
## **Adding Channels to Your Workspace**
After creating your Slack workspace, you can add channels by following these steps:
1. Click the '+' icon next to 'Channels' on the sidebar of your Slack workspace.
2. Choose "Create a channel" and specify the channel name and purpose.
3. For enterprise grid organizations, refer to [Slack's help article](https://slack.com/help/articles/115001399587-Add-a-channel-to-multiple-workspaces-in-your-Enterprise-Grid-organization){:target="_blank"} for instructions.
## **Setting Up a Webhook for Notifications**
To set up a webhook for sending notifications to your Slack workspace:
- 1: Create a [Slack app](https://api.slack.com/apps/new){:target="_blank"}, following the instructions by signing in, adding name and workspace to put the app in.
- 2: After this, you'll be redirected to the setting pages of your new app. Choose Incoming Webhook and toggle Activate Webhook.
- 3: Scroll down to click the option Add New Webhook to Workspace.
![Image](images/image3.png)
- 4: The page will give you a link associated with the app you created. This link will be where API requests are sent to send messages to your Slack workspace.
![Image](images/image2.png)
- 5: To test if the webhook works as needed, you can try sending an API request to this link to see if the message goes through. I used Postman to test this. Remember that this is an `application/json` file.
![Image](images/image4.png)
- 6: Afterwards, the text channel should have a new message.
![Image](images/image1.png)
- 7: Go to [Slack's webhook documentation](https://api.slack.com/messaging/webhooks){:target="_blank"} to learn more about setting up webhooks.

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -0,0 +1,57 @@
# **Disclaimer**
![image](images/image2.png)
Hello dear Knative Learners,
Before you begin this tutorial, **please take note of the following disclaimer**. In the spirit of open source, we strive for transparency. This tutorial incorporates many other open source projects, and we are grateful to all the incredible contributors. Your amazing work has made this tutorial possible.
If you're interested in getting started with open source, check out our guide: Get Started with Open Source at Knative.
Thank you, and happy learning!
### **Open Source Libraries Used**
This tutorial makes use of several open source libraries to build the bookstore application. Below are the libraries used along with their respective documentation and project links:
- [Profanity Check](https://pypi.org/project/profanity-check/)
- [Flask](https://flask.palletsprojects.com/en/3.0.x/)
- [CloudEvents](https://cloudevents.io/)
- [TextBlob](https://textblob.readthedocs.io/en/dev/)
- [Node.js](https://nodejs.org/en)
- [Next.js](https://nextjs.org/)
- [PostgreSQL](https://www.postgresql.org/)
- [Apache Camel](https://camel.apache.org/)
### **Music Used in the Demo Video**
The music used in the demo video is sourced from Uppbeat, which provides free music for creators:
- Music: [Trendsetter](https://uppbeat.io/t/mood-maze/trendsetter) by Mood Maze
- License Code: JHDMCOJT3ZC4EVUB
### **Graphic Creation License**
Graphics used in this tutorial were created using Canva:
- Canva License: [Content License Agreement](https://www.canva.com/policies/content-license-agreement)
### **Results of ML Services in This Tutorial**
The results of the sentiment analysis and inappropriate language filter (a.k.a bad word filter) are generated using the open source libraries mentioned above. Knative **is not responsible** for the accuracy or reliability of the output generated by these libraries.
### **General Disclaimer**
This tutorial is provided for educational purposes only. While every effort has been made to ensure the accuracy and reliability of the information provided, the authors and contributors of this tutorial make no guarantees, representations, or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability, or availability of the information contained within the tutorial for any purpose.
By using this tutorial, you acknowledge that:
- You are responsible for verifying the information and results obtained from the tutorial.
- The tutorial may contain links to external websites and resources; the authors and contributors of this tutorial are not responsible for the content, privacy policies, or practices of these external websites and resources.
- The open source libraries used in this tutorial are third-party products; the authors and contributors of this tutorial are not responsible for the performance, accuracy, or reliability of these libraries.
### **Contact**
![image](images/image1.png)
If you have any questions or concerns regarding this disclaimer or the tutorial, please feel free to reach out to the Knative community via the Cloud Native Computing Foundation (CNCF) Slack, particularly the [#knative](https://cloud-native.slack.com/archives/C04LGHDR9K7){:target="_blank"} channel.

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

View File

@ -0,0 +1,130 @@
# **Extra Challenges**
![image](images/image5.png)
Congratulations on completing the bookstore tutorial! Kubernetes and Knative have a high learning curve due to their complexity, but you did it! You should be proud of your accomplishment.
Now it's time to test your mastery of the skills you've learned with Kuack. We've prepared a few extra challenges for you to explore. Take a look and have fun!
## **Challenge 1: Integrate with Another Notification Service as Sink (Telegram)**
![image](images/image6.png)
**Description**
Add Telegram notifications for new comments using Apache Camel K.
**Objective**
Send Telegram notifications for new comments.
**Steps**
1. Create a new event type or filter attribute for Telegram notifications.
2. Set up a Trigger to route these events to a Camel K integration service.
3. Use Apache Camel K to send messages to a Telegram chat by setting up the telegram-sink.
**What You Will Learn**
- Integrating with external notification services using Apache Camel K.
- Using Triggers to route specific events.
- Working with the Telegram API.
**Estimated Time**
0.5-1 hours
## **Challenge 2: Implement Comment Deletion**
![image](images/image1.png)
**Description**
Add functionality to delete comments from the database using an event-driven approach.
**Objective**
Allow users to delete the selected comment.
**Steps**
1. Create a new event type for comment deletion.
2. Set up a Trigger to listen for deletion events.
3. Implement a function in the node-server to handle the deletion and update the database.
**What You will Learn:**
- Creating and handling new event types.
- Setting up Triggers for specific events.
- Performing database operations based on events.
**Estimated Time**
1-2 hours
## **Challenge 3: Format the Output for the Sink**
![image](images/image4.png)
**Description**
Learn how to create an event consumer app that formats event data before sending it to a sink.
**Objective**
Transform event data and send it to the appropriate sink.
**Steps**
1. Create a new function in node-server to consume and transform events.
2. Set up a Trigger to route events (Event X - unformatted) to this transformation service.
3. Implement the transformation logic to convert Event X into Event Y - formatted.
4. Configure the service to send the transformed event (Event Y) to the Slack sink.
5. Ensure the function replies with the transformed event.
**What You Will Learn**
- Creating an event consumer app.
- Adding a new step in a Sequence to process events.
- Transforming events within a service and routing the transformed events to a sink.
- Using Triggers and functions with replies in an event-driven architecture.
**Estimated Time**
1-2 hours
## **Challenge 4: Submit Comments via Telegram**
![image](images/image3.png)
**Description**
Enable users to submit new comments through a Telegram bot using Apache Camel K.
**Objective**
Allow users to send comments via Telegram.
**Steps**
1. Create a Telegram bot and obtain the bot token.
2. Set up an [Apache Camel K Telegram source](https://camel.apache.org/camel-kamelets/4.4.x/telegram-source.html){:target="_blank"} to listen for messages from the Telegram bot.
3. Create a new event type for comments received via Telegram.
4. Set up a Trigger to process these events and route them to the comment handling service.
5. Implement a function in the node-server to handle the new comments and update the database.
**What You Will Learn**
- Creating and configuring a Telegram bot.
- Using Apache Camel K to integrate Telegram as an event source with your application.
- Handling new event types and processing user input from external sources.
**Estimated Time**
2-3 hours
## **Help**
![image](images/image2.png)
Join the supportive Knative community via the Cloud Native Computing Foundation (CNCF) Slack, particularly the [#knative](https://cloud-native.slack.com/archives/C04LGHDR9K7){:target="_blank"} channel. Before posting your questions, please search to see if they've already been answered. Your feedback on this tutorial is invaluable, so don't hesitate to reach out with suggestions or questions.

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

View File

@ -0,0 +1,306 @@
# Environment Setup
![Image](images/image20.png)
In this page, we will be discussing how to set up your environment, and make sure to run up the UI front end and the Book Review Services node server.
## **What does the final deliverable for this section look like?**
- You have a running Kubernetes (k8s) cluster on your local machine, with Knative installed.
- You have your front end application deployed as Kubernetes deployment with port-forwarding to localhost:3000
- You have your Node.js application deployed as Kubernetes deployment with port-forwarding to localhost:8080
We will be fulfilling each requirement with the order above.
## **Clone the Repository**
![Next Step Image](images/image22.png)
```sh
git clone https://github.com/knative/docs.git
```
???+ bug "Troubleshooting"
Having issue with cloning your repo? Check [here](https://docs.github.com/en/repositories/creating-and-managing-repositories/troubleshooting-cloning-errors){:target="_blank"} for help.
!!! warning
**IMPORTANT**: Please take some time to read the [Disclaimer](../disclaimer/README.md){:target="_blank"} before moving to the next page.
## **File Structure**
![Image](images/image21.png)
The code for the sample app is in `docs/code-samples/eventing/bookstore-sample-app`
Under `bookstore-sample-app` folder, there are 2 folders:
* **/solution**: this folder contains all the yaml files, and the code you needed. Check it when you got stuck.
* **/start**: this folder contains the necessary files for you to get started. Save there all the configuration files yourself following the tutorial!
![Image](images/image16.png)
!!! tip
Kuack suggests you to start from **/start**, write all the configuration files as you go over the tutorial, and check solutions when you got stuck.
![Image](images/image1.png)
Always `cd` back to the root directory, which is `/start`, before running any commands.
All the commands in the tutorial are written **assuming you are in the `/start` directory**.
## **Shortcut**
![Image](images/image10.png)
Running `docs/code-samples/eventing/bookstore-sample-app/start/setup.sh` will automatically complete all tasks in this section.
!!! warning
However, if you are not familiar with the process, we recommend reviewing the steps below.
## **Instructions**
### **Task 1: Set Up a Running Kubernetes Cluster with Knative Installed**
![Image](images/image13.png)
Please follow the instructions [here](https://knative.dev/docs/install/){:target="_blank"} to spin up your cluster with Knative installed!
???+ success "Verify"
You should see the pods in the `knative-eventing` and `knative-serving` namespaces running before proceeding.
```
NAMESPACE NAME READY STATUS RESTARTS AGE
knative-eventing eventing-controller-7576f555d5-7c2p2 1/1 Running 0 4m50s
knative-eventing eventing-webhook-5874bb8445-cqcn9 1/1 Running 0 4m50s
knative-eventing imc-controller-8c5d5ddb5-m249l 1/1 Running 0 4m49s
knative-eventing imc-dispatcher-76d9f7464b-dphd6 1/1 Running 0 4m49s
knative-eventing mt-broker-controller-8d8f8d48f-rvlcv 1/1 Running 0 4m48s
knative-eventing mt-broker-filter-85c457f879-dvhnj 1/1 Running 0 4m48s
knative-eventing mt-broker-ingress-5688f4cd68-nm8cc 1/1 Running 0 4m48s
knative-serving activator-55d856fccd-g5qpw 1/1 Running 0 4m53s
knative-serving autoscaler-5fb49c64c7-hrjng 1/1 Running 0 4m53s
knative-serving controller-ddbb9d4f-khttq 1/1 Running 0 4m53s
knative-serving net-kourier-controller-68d89f78d5-hw8r6 1/1 Running 0 4m52s
knative-serving webhook-85b9744fc5-6w9sg 1/1 Running 0 4m53s
kourier-system 3scale-kourier-gateway-dbc5b88f5-7g29n 1/1 Running 0 4m52s
kube-system coredns-5dd5756b68-49xsj 1/1 Running 0 12m
kube-system etcd-minikube 1/1 Running 0 12m
kube-system kube-apiserver-minikube 1/1 Running 0 12m
kube-system kube-controller-manager-minikube 1/1 Running 0 12m
kube-system kube-proxy-tqcvx 1/1 Running 0 12m
kube-system kube-scheduler-minikube 1/1 Running 0 12m
kube-system storage-provisioner 1/1 Running 0 12m
```
#### **Extra Step for Minikube Users:**
![Image](images/image3.png)
Attention! In case you're not using the Knative Quick Start, set up the tunnel manually to connect to services of type `LoadBalancer`:
Run the following command and keep the terminal open:
```shell
minikube tunnel
```
???+ success "Verify"
If there aren't any error messages, it means you have set up the tunnel successfully.
### **Task 2: Running the Bookstore Web App**
![Image](images/image12.png)
The Next.js frontend app is located in the `docs/code-samples/eventing/bookstore-sample-app/start/frontend` folder.
Ensure that port 3000 on your local machine is not being used by another application.
#### **Deploy the Frontend App**
You can either [build the image locally](https://docs.docker.com/get-started/02_our_app/){:target="_blank"} or use our pre-built image. If you are using the pre-built image, you can proceed to the next step.
When ready, run the following command to deploy the frontend app:
```shell
kubectl apply -f frontend/config/100-front-end-deployment.yaml
```
This will create the Deployment and expose it with a Service of type LoadBalancer to receive external traffic:
```
deployment.apps/bookstore-frontend created
service/bookstore-frontend-svc created
```
???+ success "Verify"
Run the following command to check if the pod is running:
```shell
kubectl get pods
```
You will see that your front end pod is running.
```
NAME READY STATUS RESTARTS AGE
bookstore-frontend-7b879ffb78-9bln6 1/1 Running 0 4m37s
```
#### **Port Forwarding (Optional under condition)**
![Image](images/image9.png)
You might need to set up port forwarding to access the app from your local machine.
Check if port forwarding is necessary by running:
```shell
kubectl get services
```
And you will see the following console output:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
bookstore-frontend-svc LoadBalancer 10.99.187.173 <pending> 3000:31600/TCP 27m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 39m
```
!!! note
If the `EXTERNAL-IP` for your frontend service is `127.0.0.1`, port forwarding is not needed.
If port forwarding is required, run the following command:
```shell
kubectl port-forward svc/bookstore-frontend-svc 3000:3000
```
You should see the following output:
```
Forwarding from 127.0.0.1:3000 -> 3000
Forwarding from [::1]:3000 -> 3000
```
**Don't close the terminal when port-forwarding is established.** Start a new terminal to run the next command.
???+ success "Verify"
Visit [http://localhost:3000](http://localhost:3000){:target="_blank"} in your browser. The UI page should appear!
![Image](images/image19.png)
### **Task 3: Running the Book Review Service**
![Image](images/image6.png)
The Node.js server is located in the `node-server` folder.
!!! warning
Ensure that port 8080 on your local machine is not being used by another application.
#### **Deploy the Book Review Service: Node.js Server**
You can either [build the image locally](https://docs.docker.com/get-started/02_our_app/){:target="_blank"} or use our pre-built image. If you are using the pre-built image, you can proceed to the next step.
When ready, run the following command to deploy the Node.js server:
```shell
kubectl apply -f node-server/config/100-deployment.yaml
```
This command will pull the image and deploy it to your cluster as a Deployment. It will also expose it as a LoadBalancer to receive external traffic.
```
deployment.apps/node-server created
service/node-server-svc created
```
???+ success "Verify"
Run the following command to check if the pod is running:
```shell
kubectl get pods
```
You will see that your Node.js server (node-server) pod is running.
```
NAME READY STATUS RESTARTS AGE
bookstore-frontend-7b879ffb78-9bln6 1/1 Running 0 39m
node-server-68bf98cdf4-skjmh 1/1 Running 0 38m
```
#### **Port Forwarding (optional under condition)**
![Image](images/image9.png)
You might need to set up port forwarding to access the app from your local machine.
Check if port forwarding is necessary by running:
```shell
kubectl get services
```
And you will see the following console output:
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
bookstore-frontend-svc LoadBalancer 10.99.187.173 <pending> 3000:31600/TCP 73m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 85m
node-server-svc LoadBalancer 10.101.90.35 <pending> 80:31792/TCP 73m
```
!!! note
If the `EXTERNAL-IP` for your Node.js service is `127.0.0.1`, port forwarding is not needed. If you failed to visit the page `localhost:8080`, you can try to set up port forwarding.
If port forwarding is required, open a new terminal and run:
```shell
kubectl port-forward svc/node-server-svc 8080:80
```
You should see the following output:
```
Forwarding from 127.0.0.1:8080 > 8000
Forwarding from [::1]:8080 > 8000
```
**Don't close the terminal when port-forwarding is established.** Start a new terminal to run the next command.
???+ success "Verify"
Visit [http://localhost:8080](http://localhost:8080){:target="_blank"} in your browser. The Node.js service should be up and running.
And in your front end page, you should see the status turns green and say "Connected to node server".
![Image](images/image18.png)
## **Troubleshooting**
If you encounter any issues during the setup process, refer to the troubleshooting section in the documentation or check the logs of your Kubernetes pods for more details.
???+ bug "Troubleshooting"
To check the logs, use the following command:
```shell
kubectl logs <pod-name>
```
Replace `<pod-name>` with the name of the pod you want to check.
## **Next Step**
![Image](images/image5.png)
You have successfully set up the cluster with Knative installed, and running your front end app and node server. You are all set to start learning. Your journey begins from here.
[Go to Lesson 1 - Send Review Comment to Broker :fontawesome-solid-paper-plane:](../page-1/send-review-comment-to-broker.md){ .md-button .md-button--primary }

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 KiB

View File

@ -0,0 +1,139 @@
# Welcome: Knative Bookstore Tutorial
![Welcome Image](images/1.png)
**Welcome to Knative's End-to-End Sample Application Tutorial!**
- Are you completely new to Knative and unsure where to start?
- Are you considering converting your application to an event-driven architecture but don't know how?
- Are you curious to see what Knative can do in real life?
- Are you new to the cloud computing world and looking to get started with open source?
!!! success "You found the right place"
If any of these resonate with you, you've found the perfect starting point.
In this tutorial, we will construct an online bookstore application. This interactive guide, suitable for beginners and experienced engineers alike, will take you through the steps of building, deploying, and monitoring an application using Knative's powerful features. For those familiar with the process, concise graphics are available to streamline your learning experience.
## **What are we building?**
![App Diagram](images/2.png)
Our App is an online bookstore that sells a single book. Customers can post comments about the book anonymously, with each comment displayed alongside an emoji reflecting the sentiment of the comment. Comments with inappropriate content are automatically filtered out, discarded, and logged in the backend.
As the bookstore owner, you'll receive notifications via Slack each time if a comment containing a "bad word" is submitted.
## **Learning Goal**
![Learning Goal Image](images/3.png)
You will learn Event-Driven Architecture (EDA) and how it contrasts with traditional application designs that use microservices and REST APIs. You'll learn:
- **The Fundamentals of EDA**: Explore the core principles of event-driven architecture and how it enhances responsiveness and scalability in applications.
- **Comparative Insights**: Understand the differences between EDA and traditional architectures, highlighting the benefits and use cases of each.
- **Practical Application**: Discover how to transition your existing applications to an event-driven model, utilizing the powerful features of Knative Eventing.
![Knative Framework](images/4.png)
Knative is a powerful framework that operates on top of Kubernetes. This tutorial will guide you through:
- **Setting Up Your Cluster**: You'll start by spinning up your own Kubernetes cluster, which is the foundation for deploying and managing containers.
- **Exploring Knative**: Gain hands-on experience with key Knative concepts and components.
- **Some example use cases of Knative**.
By the end of this tutorial, you will not only understand these concepts but also feel comfortable implementing them, empowering you to build robust, scalable event-driven applications with Knative.
## **Bookstore Architecture**
![Bookstore Architecture](images/5.png)
The bookstore application consists of the following components:
### User Interface
A frontend Next.js application that interacts with these services. It is a web page where users can select a book to view its details, ratings and reviews.
### Database Service
An in-memory PostgreSQL instance on Kubernetes, storing all user comments.
### Book Reviews Service
A Node.js web server that will perform the event forwarding, database operation, and handling the websocket connection.
### Notification Service
An Apache Camel K pipe that connects our event-driven architecture with a third-party webhook: Slack. It receives the CloudEvent and sends it as a message to a Slack Workspace.
### ML Models Service
There are 2 Machine learning workflows that can conduct sentiment analysis on user's review comment and hateful word sanity check. You will be using a [Knative Sequence](https://knative.dev/docs/eventing/flows/sequence/){:target="_blank"} to make sure they are executed in order.
### Book Store Broker
It acts as the central brain of our event-driven architecture. It connects all the microservices together, receives the event, and makes sure all the events are safely delivered to the correct destination.
### Bad Word Broker
It acts as the bridge between the book store Broker and the Slack Sink, so we can send notification to your Slack when a comment containing "bad word" is submitted.
## **Tutorial Page Structure**
We will be building the sample app in this order:
0. [**Environment Setup**](../page-0.5/environment-setup.md){:target="_blank"}: Set up the environment for the tutorial. This includes installing the cluster, the frontend and the backend.
1. [**Send comments to the Broker**](../page-1/send-review-comment-to-broker.md){:target="_blank"}: Pass reviews from the frontend to event-display via the Broker. This involves learning about Broker, SinkBinding and CloudEvents event types.
2. [**Deploy Sentiment Analysis Service**](../page-2/sentiment-analysis-service-for-bookstore-reviews.md){:target="_blank"}: Gain knowledge on deploying a sentiment analysis service using Knative Function.
3. [**Deploy Bad Word Filter Service**](../page-3/create-bad-word-filter-service.md){:target="_blank"}: Implement a bad word filter service using Knative Function yourself.
4. [**Use a Sequence to Run the ML Workflows in order**](../page-4/create-sequence-to-streamline-ML-workflows.md){:target="_blank"}: Learn how to utilize a Knative Sequence to ensure your ML workflows executes in order.
5. [**Database Deployment**](../page-5//deploy-database-service.md){:target="_blank"}: Understand the deployment of an in-memory PostgreSQL instance using a plain Kubernetes deployment.
6. [**Advanced event filtering**](../page-6/advanced-event-filtering.md){:target="_blank"}: Integrate all components by receiving "analyzed reviews" via Broker (using a Trigger) and storing them into the database. This includes learning about Triggers and Filters.
7. [**Connect with External Services/API**](../page-7/slack-sink-learning-knative-eventing-and-apache-camel-K-integration.md){:target="_blank"}: Learn how to connect your application with external services and APIs using Knative Eventing and Apache Camel K integrations.
8. [**Extra Challenges**](../extra-challenge/README.md){:target="_blank"}: Additional challenges to test your understanding of the concepts learned in the tutorial.
## **How to properly learn?**
### Preview the Final Bookstore: 1-Minute Demo Video
To help you visualize what you'll be creating, we've prepared a brief demo video. This two-minute preview showcases the final bookstore application, providing a clearer understanding of what you can expect to build.
<iframe width="1924" height="500" src="https://www.youtube.com/embed/5D8pTcQSacw" title="Knative E2E Bookstore Tutorial - 1-min Demo" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
???+ bug "Video not working above?"
If the video is not working, you can watch it [here](https://www.youtube.com/watch?v=5D8pTcQSacw&ab_channel=Knative){:target="_blank"}.
### Step-by-Step Guidance for Beginners
![Beginner Guide](images/9.png)
This tutorial is meticulously structured to be beginner-friendly, featuring detailed, step-by-step instructions for building the sample app. Simply follow the sequence we've laid out: each section builds upon the previous, guiding you through the construction of the application. Should you encounter any hurdles, the Knative community is a fantastic resource for support. Don't hesitate to ask questions and seek advice. Check the [Help](#help) section below!
### Accelerated Learning Path for Advanced Users
![Advanced Users Guide](images/10.png)
If you find the tutorial too basic, or if it covers familiar territory, feel free to adjust your learning approach. Each section of the tutorial is accompanied by concise graphics that summarize key concepts. Advanced learners can choose to focus on these graphics to grasp the essentials faster, streamlining the learning experience without sacrificing depth or understanding.
## **Help**
![Help Image](images/11.png)
Join the supportive Knative community via the Cloud Native Computing Foundation (CNCF) Slack, particularly the [#knative](https://cloud-native.slack.com/archives/C04LGHDR9K7){:target="_blank"} channel. Before posting your questions, please search to see if they've already been answered. Your feedback on this tutorial is invaluable, so don't hesitate to reach out with suggestions or questions.
## **Next Step**
![Environment Setup](images/13.png)
Let's set up the environment first.
[Go to Environment Setup :fontawesome-solid-paper-plane:](../page-0.5/environment-setup.md){ .md-button .md-button--primary }

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -0,0 +1,423 @@
# Send Review Comment to Broker
![Image](images/image25.png)
The main dashboard of our bookstore features a comment section where readers can view comments from others and submit their own through a text input area. While the process appears straightforward - click a button, and the comment is posted - the underlying mechanism is powered by a robust event-driven architecture.
## **What Knative features will we learn about?**
- Knative Eventing Broker
- Knative Eventing Sink
- Knative SinkBinding
## **What does the deliverable look like?**
![Image](images/image3.png)
In simple words: after the user clicks on the submit button in the frontend, the comment will show up in the event-display service.
## **Implementation**
### **Step 0: Know the basics**
![Image](images/image6.png)
In the world of microservices and REST APIs, we often refer to requests as the primary method of communication between services. However, in an event-driven architecture, the smallest unit is an event. Knative Eventing adheres to the CloudEvents specification, making it essential to understand this concept before moving forward. Learn more about CloudEvents [here](https://cloudevents.io/){:target="_blank"} before proceeding!
### **Step 1: Understand Book Review Service**
![Image](images/image11.png)
The book review service is our Node.js API server, playing a crucial role in our event-driven architecture. It's essential to understand how it operates, as it receives events and processes them appropriately.
![Image](images/image2.png)
**Key Concepts: Broker and SinkBinding**
Before we dive into the code, let's clarify two important concepts:
- **Broker**: Acts as the central point in the event-driven architecture, routing events to the correct destinations.
- **SinkBinding**: This Knative Eventing component automatically injects the Broker's address into the environment variable `K_SINK`, ensuring that the Node.js server always has the correct address without manual updates.
You will get a deeper understanding along the way.
![Image](images/image12.png)
Let's examine the `node-server/index.js` file, starting with the `/add` function. When a user submits a comment through the frontend, it is first received by this endpoint.
```javascript
app.post('/add', async (req, res) => {
try {
const receivedEvent = HTTP.toEvent({headers: req.headers, body: req.body});
const brokerURI = process.env.K_SINK;
if (receivedEvent.type === 'new-review-comment') {
const response = await fetch(brokerURI, {
method: 'POST',
headers: {
'Content-Type': 'application/cloudevents+json',
'ce-specversion': receivedEvent.specversion,
'ce-type': receivedEvent.type,
'ce-source': receivedEvent.source,
'ce-id': receivedEvent.id,
},
body: JSON.stringify(receivedEvent.data),
});
}
} catch (err) {
console.error(err);
}
});
```
**Receiving Events**: The `/add` endpoint receives events from the frontend. It uses CloudEvents' SDK to convert the incoming request into a CloudEvent object:
```javascript
const receivedEvent = HTTP.toEvent({headers: req.headers, body: req.body});
```
**Determining Broker Address**: The Broker's address is dynamically assigned in the cluster. The Node.js server retrieves this address from the environment variable `K_SINK`:
```javascript
const brokerURI = process.env.K_SINK;
```
You may wonder who told the environment variable about the address? Thats Knative SinkBinding.
**Event Filtering**: The service checks the event type. If it's a `new-review-comment`, it forwards the event to the Broker:
```javascript
if (receivedEvent.type === 'new-review-comment') {
// logic that forwards the event, see below
}
```
**Forwarding Events Logic**: The event is forwarded to the Broker with the appropriate CloudEvent headers:
```javascript
const response = await fetch(brokerURI, {
method: 'POST',
headers: {
'Content-Type': 'application/cloudevents+json',
'ce-specversion': receivedEvent.specversion,
'ce-type': receivedEvent.type,
'ce-source': receivedEvent.source,
'ce-id': receivedEvent.id,
},
body: JSON.stringify(receivedEvent.data),
});
```
![Image](images/image21.png)
**Exploring Other Functions**
The Node.js server contains other functions that follow a similar pattern, with detailed comments explaining their functionality:
- `/insert`: Receives CloudEvents and inserts the payload into the PostgreSQL database.
- `/comment`: Creates a WebSocket connection with the frontend to transport comments from the database.
### **Step 2: Create Broker**
![Image](images/image17.png)
The Broker acts as a router in your event-driven application, receiving events and routing them to the correct destination.
- 1: Create a new YAML file named `node-server/config/200-broker.yaml` and add the following content:
???+ abstract "_node-server/config/200-broker.yaml_"
```yaml
apiVersion: eventing.knative.dev/v1
kind: Broker
metadata:
name: bookstore-broker
```
- 2: Apply the YAML file:
```bash
kubectl apply -f node-server/config/200-broker.yaml
```
You will see the following output:
```
broker.eventing.knative.dev/bookstore-broker created
```
Alternatively, use the [Knative CLI `kn`](https://knative.dev/docs/client/#kn){:target="_blank"} to create the Broker:
```bash
kn broker create bookstore-broker
```
You will see the following output:
```
Broker 'bookstore-broker' successfully created in namespace 'default'.
```
???+ success "Verify"
Running the following command to list the Brokers:
```bash
kubectl get brokers
```
You should see the Broker `bookstore-broker` with `READY` status as `True`.
```
NAME URL AGE READY REASON
bookstore-broker http://broker-ingress.knative-eventing.svc.cluster.local/default/bookstore-broker 7m30s True
```
???+ bug "Troubleshooting"
If there are issues, use the following command to diagnose:
```bash
kubectl describe broker bookstore-broker
```
### **Step 3: Create a SinkBinding between the Node.js server and Broker**
![Image](images/image15.png)
Hardcoding URLs to connect with Kubernetes services in your application can be limiting and inflexible. A SinkBinding dynamically injects the URL of the Kubernetes service into your application.
Learn more about SinkBinding [here](https://knative.dev/docs/eventing/custom-event-source/sinkbinding/){:target="_blank"} and the [spec schema](https://knative.dev/docs/eventing/custom-event-source/sinkbinding/reference/){:target="_blank"}!
**Create a SinkBinding:**
- 1: Create a new YAML file named `300-sinkbinding.yaml` in the `node-server/config` folder and add the following content:
???+ abstract "_node-server/config/300-sinkbinding.yaml_"
```yaml
apiVersion: sources.knative.dev/v1
kind: SinkBinding
metadata:
name: node-sinkbinding
spec:
subject:
apiVersion: apps/v1
kind: Deployment
selector:
matchLabels:
app: node-server
sink: # In this case, the sink is our Broker, which is the eventing service that will receive the events
ref:
apiVersion: eventing.knative.dev/v1
kind: Broker
name: bookstore-broker
```
- 2: Apply the YAML file:
```bash
kubectl apply -f node-server/config/300-sinkbinding.yaml
```
You will see the following output:
```
sinkbinding.sources.knative.dev/node-sinkbinding created
```
???+ success "Verify"
Running the following command to list the sinkbindings:
```bash
kubectl get sinkbindings
```
You should see the sinkbinding `node-sinkbinding` with `READY` status as `True`.
```
NAME SINK AGE READY REASON
node-sinkbinding http://broker-ingress.knative-eventing.svc.cluster.local/default/bookstore-broker 2m43s True
```
### **Step 4: Create event-display service**
![Image](images/image1.png)
Event display is a debugging tool in Knative Eventing that allows you to use it as a temporary destination (a.k.a sink) for your event to go.
**Create an Event Display Service:**
- 1: Create a new YAML file named `100-event-display.yaml` in the `node-server/config` folder and add the following content:
???+ abstract "_node-server/config/100-event-display.yaml_"
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: event-display
spec:
replicas: 1
selector:
matchLabels:
app: event-display
template:
metadata:
labels:
app: event-display
spec:
containers:
- name: event-display
image: gcr.io/knative-releases/knative.dev/eventing-contrib/cmd/event_display
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: event-display
spec:
selector:
app: event-display
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
```
- 2: Apply the YAML file:
```bash
kubectl apply -f node-server/config/100-event-display.yaml
```
You will see the following output:
```
deployment.apps/event-display created
service/event-display created
```
???+ success "Verify"
Running the following command to list the pods:
```bash
kubectl get pods
```
You should see the pod `event-display-XXXXXXX-XXXXX` in "Running" status.
```
NAME READY STATUS RESTARTS AGE
bookstore-frontend-7b879ffb78-9bln6 1/1 Running 0 91m
event-display-55967c745d-bxrgh 1/1 Running 0 4m44s
node-server-644795d698-r9zlr 1/1 Running 0 4m43s
```
### **Step 5: Create a Trigger that connects the Broker and event display**
![Image](images/image9.png)
A Trigger is able to forward the event to the correct destination based on the [CloudEvent's attributes](https://knative.dev/docs/eventing/#:~:text=Knative%20Eventing%20uses%20standard%20HTTP%20POST%20requests%20to%20send%20and%20receive%20events%20between%20event%20producers%20and%20sinks.%20These%20events%20conform%20to%20the%20CloudEvents%20specifications%2C%20which%20enables%20creating%2C%20parsing%2C%20sending%2C%20and%20receiving%20events%20in%20any%20programming%20language.){:target="_blank"}. It is the connector between the Broker and the event destination.
A Filter in the Trigger will **filter the events based on the filter condition**. You will specify your filter condition in the Triggers YAML file. **If no filter is specified, the Trigger will forward all the events that the Broker received.**
![Image](images/image18.png)
There is also a concept called [Channel](https://knative.dev/docs/eventing/channels/){:target="_blank"} in Knative, and generally speaking, you can treat Broker & Trigger without filter the same as Channel & Subscription.
Learn more about Broker & Trigger [here](https://knative.dev/docs/eventing/brokers/){:target="_blank"}!
**Create a Trigger:**
![Image](images/image20.png)
Here we are creating a Trigger that will send all the events to event-display.
![Image](images/image4.png)
- 1: Create a new YAML file named `200-log-trigger.yaml` and add the following content:
???+ abstract "_node-server/config/200-log-trigger.yaml_"
```yaml
# This Trigger subscribes to the Broker and will forward all the events that it received to event-display.
apiVersion: eventing.knative.dev/v1
kind: Trigger
metadata:
name: log-trigger
spec:
broker: bookstore-broker
subscriber:
ref:
apiVersion: v1
kind: Service
name: event-display
```
- 2: Apply the YAML file:
```bash
kubectl apply -f node-server/config/200-log-trigger.yaml
```
You will see the following output:
```
trigger.eventing.knative.dev/log-trigger created
```
???+ success "Verify"
Running the following command to list the Triggers:
```bash
kubectl get triggers
```
The Trigger `log-trigger` should have `READY` status as `True`.
```
NAME BROKER SUBSCRIBER_URI AGE READY REASON
log-trigger bookstore-broker http://event-display.default.svc.cluster.local 6m2s True
```
### **Validate**
![Image](images/image8.png)
Open the logs of the event-display with the following command:
```bash
kubectl logs -l=app=event-display -f
```
???+ success "Verify"
Type something in the comment box in the UI and click the submit button. The comment should appear in the event-display service with the following output:
```plaintext
☁️ cloudevents.Event
Validation: valid
Context Attributes,
specversion: 1.0
type: new-review-comment
source: bookstore-eda
id: unique-comment-id
datacontenttype: application/json
Extensions,
knativearrivaltime: 2024-05-19T05:27:36.232562628Z
Data,
{
"reviewText": "test"
}
```
### **Next Step**
![Image](images/image13.png)
Please make sure you pass the Validate test before proceeding.
[Go to Deploy ML workflow: Sentiment Analysis :fontawesome-solid-paper-plane:](../page-2/sentiment-analysis-service-for-bookstore-reviews.md){ .md-button .md-button--primary }

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -0,0 +1,414 @@
# Sentiment Analysis Service for Bookstore Reviews
![Image1](images/image1.png)
As a bookstore owner, you aim to receive instant notifications in a Slack channel whenever a customer submits a new negative review comment. By leveraging Knative Function, you can set up a serverless function that contains a simple sentiment analysis service to categorize review comments by sentiment.
## **Which Knative features will we learn about?**
The ease to use **Knative Function** to deploy your service, and make it be managed by Knative Serving, which gives you the ability to **auto-scale your service to zero**, and scale up to handle the demand.
## **What does the final deliverable look like?**
![Image8](images/image8.png)
A running serverless Knative Function that contains a python application that receives the new review comments as CloudEvent and returns the sentiment classification of the input text as CloudEvent.
The function's output will be only from:
- Positive
- Neutral
- Negative
## **Install Prerequisites**
### **Prerequisite 1: Install Knative func CLI**
![Image12](images/image12.png)
Knative Function enables you to easily create, build, and deploy stateless, event-driven functions as [Knative Services](https://knative.dev/docs/serving/services/#:~:text=Knative%20Services%20are%20used%20to,the%20Service%20to%20be%20configured){:target="_blank"} by using the func CLI.
In order to do so, you need to install the func CLI. You can follow the [official documentation](https://knative.dev/docs/getting-started/install-func/){:target="_blank"} to install the func CLI.
???+ success "Verify"
Running `func version` in your terminal to verify the installation, and you should see the version of the func CLI you installed.
???+ bug "Troubleshooting"
If you see `command not found`, you may need to add the func CLI to your PATH.
## **Implementation**
![Image3](images/image3.png)
The process is straightforward:
1. Begin by utilizing the `func create` command to generate your code template.
2. Next, incorporate your unique code into this template.
3. Finally, execute `func deploy` to deploy your application seamlessly to the Kubernetes cluster.
This workflow ensures a smooth transition from development to deployment within the Knative Functions ecosystem.
### **Step 1: Create a Knative Function template**
![Image17](images/image17.png)
Create a new function using the func CLI:
```
func create -l <language> <function-name>
```
In this case, we are creating a Python function, so the command will be:
```
func create -l python sentiment-analysis-app
```
This command will create a new directory with the name `sentiment-analysis-app` and a bunch of files in it. The func CLI will generate a basic function template for you to start with.
You can find all the supported language templates [here](https://knative.dev/docs/functions/){:target="_blank"}.
???+ success "Verify"
The file tree will look like this:
```
start/sentiment-analysis-app
├── func.yaml
├── .funcignore
├── .gitignore
├── requirements.txt
├── app.sh
├── test_func.py
├── README.md
├── Procfile
└── func.py
```
### **Step 2: Replace the generated code with the sentiment analysis logic**
![Image14](images/image14.png)
`func.py` is the file that contains the code for the function. You can replace the generated code with the sentiment analysis logic. You can use the following code as a starting point:
???+ abstract "_sentiment-analysis-app/func.py_"
```python
from parliament import Context
from flask import Request, request, jsonify
import json
from textblob import TextBlob
from time import sleep
from cloudevents.http import CloudEvent, to_structured
# The function to convert the sentiment analysis result into a CloudEvent
def create_cloud_event(inputText, badWordResult, data):
attributes = {
"type": "moderated-comment",
"source": "sentiment-analysis",
"datacontenttype": "application/json",
"sentimentResult": data,
"badwordfilter": badWordResult,
}
# Put the sentiment analysis result into a dictionary
data = {
"reviewText": inputText,
"badWordResult": badWordResult,
"sentimentResult": data,
}
# Create a CloudEvent object
event = CloudEvent(attributes, data)
return event
def analyze_sentiment(text):
analysis = TextBlob(text["reviewText"])
sentiment = "neutral"
if analysis.sentiment.polarity > 0:
sentiment = "positive"
elif analysis.sentiment.polarity < 0:
sentiment = "negative"
badWordResult = ""
try:
badWordResult = text["badWordResult"]
except:
pass
# Convert the sentiment into a CloudEvent
sentiment = create_cloud_event(text["reviewText"], badWordResult, sentiment)
return sentiment
def main(context: Context):
"""
Function template
The context parameter contains the Flask request object and any
CloudEvent received with the request.
"""
print("Sentiment Analysis Received CloudEvent: ", context.cloud_event)
# Add your business logic here
return analyze_sentiment(context.cloud_event.data)
```
### **Step 3: Configure the dependencies**
![Image9](images/image9.png)
The `requirements.txt` file contains the dependencies for the function. You can add the following dependencies to the `requirements.txt` file:
???+ abstract "_sentiment-analysis-app/requirements.txt_"
```
Flask==3.0.2
textblob==0.18.0.post0
parliament-functions==0.1.0
cloudevents==1.10.1
```
Knative Function will automatically install the dependencies listed here when you build the function.
### **Step 4: Configure the pre-built environment**
![Image11](images/image11.png)
In order to properly use the `textblob` library, you need to download the corpora, which is a large collection of text data that is used to train the sentiment analysis model. You can do this by creating a new file called `setup.py`, Knative Function will ensure that the `setup.py` file is executed after the dependencies have been installed.
The `setup.py` file should contain the following code for your bookstore:
???+ abstract "_sentiment-analysis-app/setup.py_"
```python
from setuptools import setup, find_packages
from setuptools.command.install import install
import subprocess
class PostInstallCommand(install):
"""Post-installation for installation mode."""
def run(self):
# Call the superclass run method
install.run(self)
# Run the command to download the TextBlob corpora
subprocess.call(['python', '-m', 'textblob.download_corpora', 'lite'])
setup(
name="download_corpora",
version="1.0",
packages=find_packages(),
cmdclass={
'install': PostInstallCommand,
}
)
```
### **Step 5: Build and run your Knative Function locally (Optional)**
??? info "Click here to expand"
![Image4](images/image4.png)
In Knative Function, there are two ways to build: using the [pack build](https://github.com/knative/func/blob/8f3f718a5a036aa6b6eaa9f70c03aeea740015b9/docs/reference/func_build.md?plain=1#L46){:target="_blank"} or using the [source-to-image (s2i) build](https://github.com/knative/func/blob/4f48549c8ad4dad34bf750db243d81d503f0090f/docs/reference/func_build.md?plain=1#L43){:target="_blank"}.
Currently only the s2i build is supported if you need to run `setup.py`. When building with s2i, the `setup.py` file will be executed automatically after the dependencies have been installed.
Before we get started, configure the container registry to push the image to the container registry. You can use the following command to configure the container registry:
```
export FUNC_REGISTRY=<your-container-registry>
```
In this case, we will use the s2i build by adding the flag `-b=s2i`, and `-v` to see the verbose output.
```
func build -b=s2i -v
```
When the build is complete, you will see the following output:
```
🙌 Function built: <Your container registry username>/sentiment-analysis-app:latest
```
This command will build the function and push the image to the container registry. After the build is complete, you can run the function using the following command:
---
**Troubleshooting**
`❗Error: '/home/Kuack/Documents/knative/docs/code-samples' does not contain an initialized function`
**Solution: You may want to check whether you are in the correct directory. You can use the following command to check the current directory. If you are in the right directory, and the error still occurs, try to check your `func.yaml`, as it has to contain the field `created` and the right timestamp to be treated as a valid Knative Function.**
---
```
func run -b=s2i -v
```
In the future, you can skip the step of `func build`, because `func run` will automatically build the function for you.
You will see the following output if the function is running successfully:
```
❗function up-to-date. Force rebuild with --build
Running
on host port 8080
---> Running application from script (app.sh) ...
```
Knative Function has an easy way to simulate the CloudEvent, you can use the following command to simulate the CloudEvent and test your function out:
```
func invoke -f=cloudevent --data='{"reviewText": "I love Knative so much"}' --content-type=application/json --type="new-review-comment" -v
```
where the `-f` flag indicates the type of the data, is either `HTTP` or `cloudevent`, and the `--data` flag is the input text. You can read more about `func invoke` [here](https://github.com/knative/func/blob/main/docs/reference/func_invoke.md){:target="_blank"}.
In this case, you will get the full CloudEvent response:
```
Context Attributes,
specversion: 1.0
type: new-review-comment
source: book-review-broker
id: ebbcd761-3a78-4c44-92e3-de575d1f2d38
time: 2024-05-27T04:44:07.549303Z
datacontenttype: application/json
Extensions,
badwordfilter: good
Data,
{
"reviewText": "I love Knative so much",
"badWordResult": "",
"sentimentResult": "positive"
}
```
### **Step 6: Deploy the function to the cluster**
![Image10](images/image10.png)
!!! note
Please enter `/sentiment-analysis-app` when you are executing the following commands.
After you have finished the code, you can deploy the function to the cluster using the following command:
```bash
func deploy -b=s2i -v
```
???+ success "Verify"
When the deployment is complete, you will see the following output:
```
Function deployed in namespace "default" and exposed at URL:
http://sentiment-analysis-app.default.svc.cluster.local
```
!!! tip
You can find the URL of the Knative Function (Knative Service) by running the following command:
```bash
kubectl get kservice
```
You will see the URL in the output:
```
NAME URL LATESTCREATED LATESTREADY READY REASON
sentiment-analysis-app http://sentiment-analysis-app.default.svc.cluster.local sentiment-analysis-app-00001 sentiment-analysis-app-00001 True
```
## **Knative Serving: scale down to zero**
![Image13](images/image13.png)
If you use the following command to query all the pods in the cluster, you will see that the pod is running:
```bash
kubectl get pods
```
where `-A` is the flag to query all the pods in all namespaces.
And you will find that your sentiment analysis app is running:
```
NAMESPACE NAME READY STATUS RESTARTS AGE
default sentiment-analysis-app-00002-deployment 2/2 Running 0 2m
```
But if you wait for a while without sending any CloudEvent to your function, and query the pods again, you will find that the pod that has your sentiment analysis app **disappeared**!
This is because Knative Serving's autoscaler will **automatically scale down to zero** if there is no request to the function! Learn more at [Knative Autoscaling](https://knative.dev/docs/serving/autoscaling/){:target="_blank"}.
---
## **Verify**
![Image2](images/image2.png)
After deployment, the `func` CLI provides a URL to access your function. You can verify the function's operation by sending a request with a sample review comment.
Simply use Knative Function's command `func invoke` to directly send a CloudEvent to the function on your cluster:
```bash
func invoke -f=cloudevent --data='{"reviewText":"I love Knative so much"}' -v
```
- `-f` flag indicates the type of the data, is either `HTTP` or `cloudevent`
- `--data` flag is the input text
- `-t` flag is the URI to the Knative Function.
???+ success "Verify"
If you see the response, it means that the function is running successfully.
```
Context Attributes,
specversion: 1.0
type: moderated-comment
source: sentiment-analysis
id: 0c2d0659-a30e-4efd-bcce-803f15ff5cc5
time: 2024-06-11T15:12:43.795405Z
datacontenttype: application/json
Extensions,
badwordfilter:
sentimentresult: positive
Data,
{
"reviewText": "I love Knative so much",
"badWordResult": "",
"sentimentResult": "positive"
}
```
![Image16](images/image16.png)
In this tutorial, you learned how to create a serverless function for a simple sentiment analysis service with Knative.
## **Next Step**
![Image5](images/image5.png)
Next, we'll deploy another ML service following the same procedure. We encourage you to try it yourself!
!!! tip
Don't forget to `cd` into the root directory `/start` before proceeding.
If you feel comfortable deploying the other ML service yourself, follow this **simplified guide**:
[Go to Deploy ML workflow: Bad word filter :fontawesome-solid-paper-plane:](../page-3/create-bad-word-filter-service.md){ .md-button .md-button--primary }
If you encounter any issues, don't worry—we have a detailed tutorial ready for you.
[Solution - Go to Deploy ML workflow: Bad word filter :fontawesome-solid-paper-plane:](../page-3/solution-create-bad-word-filter-service.md){ .md-button .md-button--primary }

View File

@ -0,0 +1,178 @@
# Create Bad Word Filter Service
![Image 4](images/image4.png)
As a bookstore owner, you aim to receive instant notifications in a Slack channel whenever a customer submits a new negative review comment. By leveraging Knative Function, you can set up a serverless function that contains a simple bad word filter service to tell whether the text contains any hateful/insultive speech.
If you ever get stuck, check the solution here.
[Solution - Go to Deploy ML workflow: Bad word filter :fontawesome-solid-paper-plane:](../page-3/solution-create-bad-word-filter-service.md){ .md-button .md-button--primary }
## **What Knative features will we learn about?**
- The easiness to use Knative Function to deploy your service, and make it be managed by Knative Serving, which gives you the ability to auto-scale your service to zero, and scale up to handle the demand.
## **What does the final deliverable look like?**
![Image 2](images/image2.png)
A running serverless Knative Function that contains a python application that receives the new review comments as CloudEvent and returns the result that tells your input text contains any inappropriate languages or not. The result is sent back as CloudEvent.
!!! info
We are using the `profanity_check` library to detect the bad words in the text. It is a open source library. Please see the disclaimer here. The result may not be 100% accurate.
The function's output will be only from:
- good
- bad
## **Implementation**
![Image 10](images/image10.png)
The process is straightforward:
1. Begin by utilizing the `func create` command to generate your code template.
2. Next, incorporate your unique code into this template.
3. Finally, execute `func deploy` to deploy your application seamlessly to the Kubernetes cluster.
This workflow ensures a smooth transition from development to deployment within the Knative Functions ecosystem.
---
### **Step 1: Create a Knative Function template**
![Image 6](images/image6.png)
???+ success "Verify"
The file tree will look like this:
```
/start/bad-word-filter
├── func.yaml
├── .funcignore
├── .gitignore
├── requirements.txt
├── app.sh
├── test_func.py
├── README.md
└── Procfile
└── func.py
```
### **Step 2: Replace the generated code with the bad word filter logic**
![Image 5](images/image5.png)
`func.py` is the file that contains the code for the function. You can replace the generated code with the bad word filter logic. You can use the following code as a starting point:
???+ abstract "_bad-word-filter/func.py_"
```python
from parliament import Context
from profanity_check import predict
from cloudevents.http import CloudEvent
# The function to convert the bad word filter result into a CloudEvent
def create_cloud_event(inputText, data):
attributes = {
"type": "new-review-comment",
"source": "book-review-broker",
"datacontenttype": "application/json",
"badwordfilter": data,
}
# Put the bad word filter result into a dictionary
data = {"reviewText": inputText, "badWordResult": data}
# Create a CloudEvent object
event = CloudEvent(attributes, data)
return event
def inappropriate_language_filter(text):
profanity_result = predict([text["reviewText"]])
result = "good"
if profanity_result[0] == 1:
result = "bad"
profanity_event = create_cloud_event(text["reviewText"], result)
return profanity_event
def main(context: Context):
"""
Function template
The context parameter contains the Flask request object and any
CloudEvent received with the request.
"""
print("Received CloudEvent: ", context.cloud_event)
# Add your business logic here
return inappropriate_language_filter(context.cloud_event.data)
```
### **Step 3: Configure the dependencies**
![Image 8](images/image8.png)
???+ abstract "_bad-word-filter/requirements.txt_"
```plaintext
parliament-functions==0.1.0
alt-profanity-check==1.4.1.post1
cloudevents==1.10.1
```
### **Step 4: Deploy the function to the cluster**
![Image 1](images/image1.png)
!!! note
Please enter `/bad-word-filter` when you are executing the following commands.
```plaintext
func deploy -b=s2i -v
```
???+ success "Verify"
Expect to see the following message:
```
Function deployed in namespace "default" and exposed at URL:
http://bad-word-filter.default.svc.cluster.local
```
## **Verify**
![Image 7](images/image7.png)
```plaintext
func invoke -f=cloudevent --data='{"reviewText":"I love Knative so much"}' -v
```
???+ success "Verify"
Expect to receive a CloudEvent response:
```plaintext
Context Attributes,
specversion: 1.0
type: new-review-comment
source: book-review-broker
id: ebbcd761-3a78-4c44-92e3-de575d1f2d38
time: 2024-05-27T04:44:07.549303Z
datacontenttype: application/json
Extensions,
badwordfilter: good
Data,
{
"reviewText": "I love Knative so much",
"badWordResult": "good"
}
```
If you see the response, it means that the function is running successfully.
## **Next Step**
![Image 9](images/image9.png)
In this tutorial, you learned how to create a serverless function for a simple service that can detect inappropriate languages in text with Knative.
Next, we'll be learning how to use Knative Sequence to connect the 2 ML workflows and make sure they are executed in the order you want.
[Go to Create Knative Sequence :fontawesome-solid-paper-plane:](../page-4/create-sequence-to-streamline-ML-workflows.md){ .md-button .md-button--primary }

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Some files were not shown because too many files have changed in this diff Show More