From 68ddf1b859ec1a9bc78bdc641caea96d205d6da1 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Wed, 11 Mar 2020 14:59:47 +0000 Subject: [PATCH 1/5] Added Python Knative Eventing Helloworld Example --- .../helloworld/helloworld-python/Dockerfile | 13 + .../helloworld/helloworld-python/README.md | 343 ++++++++++++++++++ .../helloworld/helloworld-python/_index.md | 8 + .../helloworld-python/helloworld.py | 22 ++ .../helloworld-python/requirements.txt | 1 + .../helloworld-python/sample-app.yaml | 61 ++++ 6 files changed, 448 insertions(+) create mode 100644 docs/eventing/samples/helloworld/helloworld-python/Dockerfile create mode 100644 docs/eventing/samples/helloworld/helloworld-python/README.md create mode 100644 docs/eventing/samples/helloworld/helloworld-python/_index.md create mode 100644 docs/eventing/samples/helloworld/helloworld-python/helloworld.py create mode 100644 docs/eventing/samples/helloworld/helloworld-python/requirements.txt create mode 100644 docs/eventing/samples/helloworld/helloworld-python/sample-app.yaml diff --git a/docs/eventing/samples/helloworld/helloworld-python/Dockerfile b/docs/eventing/samples/helloworld/helloworld-python/Dockerfile new file mode 100644 index 00000000000..ab2c3f2efa5 --- /dev/null +++ b/docs/eventing/samples/helloworld/helloworld-python/Dockerfile @@ -0,0 +1,13 @@ +FROM python:alpine3.7 + +COPY . /app + +WORKDIR /app + +RUN pip install -r requirements.txt + +EXPOSE 8080 + +ENTRYPOINT [ "python" ] + +CMD [ "helloworld.py" ] diff --git a/docs/eventing/samples/helloworld/helloworld-python/README.md b/docs/eventing/samples/helloworld/helloworld-python/README.md new file mode 100644 index 00000000000..8876ada488c --- /dev/null +++ b/docs/eventing/samples/helloworld/helloworld-python/README.md @@ -0,0 +1,343 @@ +A simple web app written in Python that you can use to test knative eventing. It shows how to consume a [CloudEvent](https://cloudevents.io/) in Knative eventing, and optionally how to respond back with another CloudEvent in the http response, by adding the Cloud Eventing headers outlined in the Cloud Events standard definition. + +We will deploy the app as a [Kubernetes Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) along with a [Kubernetes Service](https://kubernetes.io/docs/concepts/services-networking/service/). +However, you can also deploy the app as a [Knative Serving Service](../../../../serving/README.md). + +Follow the steps below to create the sample code and then deploy the app to your +cluster. You can also download a working copy of the sample, by running the +following commands: + +```shell +# Clone the relevant branch version such as "release-0.13" +git clone -b "{{< branch >}}" https://github.com/knative/docs knative-docs +cd knative-docs/docs/eventing/samples/helloworld/helloworld-python +``` + +## Before you begin + +- A Kubernetes cluster with [Knative Eventing](../../../getting-started.md#installing-knative-eventing) installed. +- [Docker](https://www.docker.com) installed and running on your local machine, + and a Docker Hub account configured (we'll use it for a container registry). + +## Recreating the sample code + +1. Create a new file named `helloworld.py` and paste the following code. This + code creates a basic web server which listens on port 8080: + + ```python + from flask import Flask, request, make_response + import uuid + + app = Flask(__name__) + + @app.route('/', methods=['POST']) + def hello_world(): + app.logger.warning(request.data) + # Respond with another event (optional) + response = make_response({ + "msg": "Hi from helloworld-python app!" + }) + response.headers["Ce-Id"] = str(uuid.uuid4()) + response.headers["Ce-specversion"] = "0.3" + response.headers["Ce-Source"] = "knative/eventing/samples/hello-world" + response.headers["Ce-Type"] = "dev.knative.samples.hifromknative" + return response + + if __name__ == '__main__': + app.run(debug=True, host='0.0.0.0', port=8080) + + + ``` + +1. Add a requirements.txt file containing the following contents: + + ```bash + Flask==1.1.1 + ``` + +1. In your project directory, create a file named `Dockerfile` and copy the code + block below into it. For detailed instructions on dockerizing a Go app, see + [Deploying Go servers with Docker](https://blog.golang.org/docker). + + ```docker + FROM python:alpine3.7 + + COPY . /app + + WORKDIR /app + + RUN pip install -r requirements.txt + + EXPOSE 8080 + + ENTRYPOINT [ "python" ] + + CMD [ "helloworld.py" ] + + ``` + +1. Create a new file, `sample-app.yaml` and copy the following service definition + into the file. Make sure to replace `{username}` with your Docker Hub + username. + + ```yaml + # Namespace for sample application with eventing enabled + apiVersion: v1 + kind: Namespace + metadata: + name: knative-samples + labels: + knative-eventing-injection: enabled + --- + # Helloworld-python app deploment + apiVersion: apps/v1 + kind: Deployment + metadata: + name: helloworld-python + namespace: knative-samples + spec: + replicas: 1 + selector: + matchLabels: &labels + app: helloworld-python + template: + metadata: + labels: *labels + spec: + containers: + - name: helloworld-python + image: docker.io/{username}/helloworld-python + imagePullPolicy: IfNotPresent + --- + # Service that exposes helloworld-python app. + # This will be the subscriber for the Trigger + kind: Service + apiVersion: v1 + metadata: + name: helloworld-python + namespace: knative-samples + spec: + selector: + app: helloworld-python + ports: + - protocol: TCP + port: 80 + targetPort: 8080 + --- + # Knative Eventing Trigger to trigger the helloworld-python service + apiVersion: eventing.knative.dev/v1alpha1 + kind: Trigger + metadata: + name: helloworld-python + namespace: knative-samples + spec: + broker: default + filter: + attributes: + type: dev.knative.samples.helloworld + source: dev.knative.samples/helloworldsource + subscriber: + ref: + apiVersion: v1 + kind: Service + name: helloworld-python + ``` + +## Building and deploying the sample + +Once you have recreated the sample code files (or used the files in the sample +folder) you're ready to build and deploy the sample app. + +1. Use Docker to build the sample code into a container. To build and push with + Docker Hub, run these commands replacing `{username}` with your Docker Hub + username: + + ```shell + # Build the container on your local machine + docker build -t {username}/helloworld-python . + + # Push the container to docker registry + docker push {username}/helloworld-python + ``` + +1. After the build has completed and the container is pushed to docker hub, you + can deploy the sample application into your cluster. Ensure that the container image value + in `sample-app.yaml` matches the container you built in the previous step. Apply + the configuration using `kubectl`: + + ```shell + kubectl apply --filename sample-app.yaml + ``` + 1. Above command created a namespace `knative-samples` and labelled it with `knative-eventing-injection=enabled`, to enable eventing in the namespace. Verify using the following command: + ```shell + kubectl get ns knative-samples --show-labels + ``` + 1. It deployed the helloworld-python app as a K8s Deployment and created a K8s service names helloworld-python. Verify using the following command. + ```shell + kubectl --namespace knative-samples get deployments helloworld-python + + kubectl --namespace knative-samples get svc helloworld-python + ``` + 1. It created a Knative Eventing Trigger to route certain events to the helloworld-python application. Make sure that Ready=true + ```shell + kubectl --namespace knative-samples get trigger helloworld-python + ``` +## Send and verify CloudEvents +Once you have deployed the application and verified that the namespace, sample application and trigger are ready, let's send a CloudEvent. + +### Send CloudEvent to the Broker +We can send an http request directly to the [Broker](../../../broker-trigger.md) with correct CloudEvent headers set. + + 1. Deploy a curl pod and SSH into it + ```shell + kubectl --namespace knative-samples run curl --image=radial/busyboxplus:curl -it + ``` + 1. Run the following in the SSH terminal + ```shell + curl -v "default-broker.knative-samples.svc.cluster.local" \ + -X POST \ + -H "Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f79" \ + -H "Ce-specversion: 0.3" \ + -H "Ce-Type: dev.knative.samples.helloworld" \ + -H "Ce-Source: dev.knative.samples/helloworldsource" \ + -H "Content-Type: application/json" \ + -d '{"msg":"Hello World from the curl pod."}' + + exit + ``` +### Verify that event is received by helloworld-python app +Helloworld-python app logs the context and the msg of the above event, and replies back with another event. + 1. Display helloworld-python app logs + ```shell + kubectl --namespace knative-samples logs -l app=helloworld-python --tail=50 + ``` + You should see something similar to: + ```shell + Event received. Context: Context Attributes, + specversion: 0.3 + type: dev.knative.samples.helloworld + source: dev.knative.samples/helloworldsource + id: 536808d3-88be-4077-9d7a-a3f162705f79 + time: 2019-10-04T22:35:26.05871736Z + datacontenttype: application/json + Extensions, + knativearrivaltime: 2019-10-04T22:35:26Z + knativehistory: default-kn2-trigger-kn-channel.knative-samples.svc.cluster.local + traceparent: 00-971d4644229653483d38c46e92a959c7-92c66312e4bb39be-00 + + Hello World Message "Hello World from the curl pod." + Responded with event Validation: valid + Context Attributes, + specversion: 0.2 + type: dev.knative.samples.hifromknative + source: knative/eventing/samples/hello-world + id: 37458d77-01f5-411e-a243-a459bbf79682 + Data, + {"msg":"Hi from Knative!"} + + ``` + Play around with the CloudEvent attributes in the curl command and the trigger specification to understand how [Triggers work](../../../broker-trigger.md#trigger). + +## Verify reply from helloworld-python app +`helloworld-python` app replies back with an event of `type= dev.knative.samples.hifromknative`, and `source=knative/eventing/samples/hello-world`. This event enters the eventing mesh via the Broker and can be delivered to other services using a Trigger + + 1. Deploy a pod that receives any CloudEvent and logs the event to its output. + ```shell + kubectl --namespace knative-samples apply --filename - << END + # event-display app deploment + apiVersion: apps/v1 + kind: Deployment + metadata: + name: event-display + namespace: knative-samples + spec: + replicas: 1 + selector: + matchLabels: &labels + app: event-display + template: + metadata: + labels: *labels + spec: + containers: + - name: helloworld-python + image: gcr.io/knative-releases/github.com/knative/eventing-sources/cmd/event_display + --- + # Service that exposes event-display app. + # This will be the subscriber for the Trigger + kind: Service + apiVersion: v1 + metadata: + name: event-display + namespace: knative-samples + spec: + selector: + app: event-display + ports: + - protocol: TCP + port: 80 + targetPort: 8080 + END + ``` + + 1. Create a trigger to deliver the event to the above service + ```shell + kubectl --namespace knative-samples apply --filename - << END + apiVersion: eventing.knative.dev/v1alpha1 + kind: Trigger + metadata: + name: event-display + namespace: knative-samples + spec: + broker: default + filter: + attributes: + type: dev.knative.samples.hifromknative + source: knative/eventing/samples/hello-world + subscriber: + ref: + apiVersion: v1 + kind: Service + name: event-display + END + ``` + + 1. [Send a CloudEvent to the Broker](###Send-CloudEvent-to-the-Broker) + + 1. Check the logs of event-display service + ```shell + kubectl --namespace knative-samples logs -l app=event-display --tail=50 + ``` + You should see something similar to: + ```shell + cloudevents.Event + Validation: valid + Context Attributes, + specversion: 0.3 + type: dev.knative.samples.hifromknative + source: knative/eventing/samples/hello-world + id: 8a7384b9-8bbe-4634-bf0f-ead07e450b2a + time: 2019-10-04T22:53:39.844943931Z + datacontenttype: application/json + Extensions, + knativearrivaltime: 2019-10-04T22:53:39Z + knativehistory: default-kn2-ingress-kn-channel.knative-samples.svc.cluster.local + traceparent: 00-4b01db030b9ea04bb150b77c8fa86509-2740816590a7604f-00 + Data, + { + "msg": "Hi from helloworld- app!" + } + ``` + + **Note: You could use the above approach to test your applications too.** + + + +## Removing the sample app deployment + +To remove the sample app from your cluster, delete the service record: + +```shell +kubectl delete --filename sample-app.yaml +``` + diff --git a/docs/eventing/samples/helloworld/helloworld-python/_index.md b/docs/eventing/samples/helloworld/helloworld-python/_index.md new file mode 100644 index 00000000000..e5be21926fc --- /dev/null +++ b/docs/eventing/samples/helloworld/helloworld-python/_index.md @@ -0,0 +1,8 @@ +--- +title: "Hello World - Python" +linkTitle: "Python" +weight: 20 +type: "docs" +--- + +{{% readfile file="README.md" %}} diff --git a/docs/eventing/samples/helloworld/helloworld-python/helloworld.py b/docs/eventing/samples/helloworld/helloworld-python/helloworld.py new file mode 100644 index 00000000000..a02024fecb6 --- /dev/null +++ b/docs/eventing/samples/helloworld/helloworld-python/helloworld.py @@ -0,0 +1,22 @@ + +from flask import Flask, request, make_response +import uuid + +app = Flask(__name__) + +@app.route('/', methods=['POST']) +def hello_world(): + app.logger.warning(request.data) + # Respond with another event (optional) + response = make_response({ + "msg": "Hi from helloworld-python app!" + }) + response.headers["Ce-Id"] = str(uuid.uuid4()) + response.headers["Ce-specversion"] = "0.3" + response.headers["Ce-Source"] = "knative/eventing/samples/hello-world" + response.headers["Ce-Type"] = "dev.knative.samples.hifromknative" + return response + +if __name__ == '__main__': + app.run(debug=True, host='0.0.0.0', port=8080) + diff --git a/docs/eventing/samples/helloworld/helloworld-python/requirements.txt b/docs/eventing/samples/helloworld/helloworld-python/requirements.txt new file mode 100644 index 00000000000..32e89684bea --- /dev/null +++ b/docs/eventing/samples/helloworld/helloworld-python/requirements.txt @@ -0,0 +1 @@ +Flask==1.1.1 diff --git a/docs/eventing/samples/helloworld/helloworld-python/sample-app.yaml b/docs/eventing/samples/helloworld/helloworld-python/sample-app.yaml new file mode 100644 index 00000000000..273226dce89 --- /dev/null +++ b/docs/eventing/samples/helloworld/helloworld-python/sample-app.yaml @@ -0,0 +1,61 @@ +# Namespace for sample application with eventing enabled +apiVersion: v1 +kind: Namespace +metadata: + name: knative-samples + labels: + knative-eventing-injection: enabled +--- +# Helloworld-go app deploment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: helloworld-python + namespace: knative-samples +spec: + replicas: 1 + selector: + matchLabels: &labels + app: helloworld-python + template: + metadata: + labels: *labels + spec: + containers: + - name: helloworld-python + image: docker.io/axsauze/helloworld-python + imagePullPolicy: IfNotPresent +--- +# Service that exposes helloworld-go app. +# This will be the subscriber for the Trigger + kind: Service + apiVersion: v1 + metadata: + name: helloworld-python + namespace: knative-samples + spec: + selector: + app: helloworld-python + ports: + - protocol: TCP + port: 80 + targetPort: 8080 +--- +# Knative Eventing Trigger to trigger the helloworld-go service +apiVersion: eventing.knative.dev/v1alpha1 +kind: Trigger +metadata: + name: helloworld-python + namespace: knative-samples +spec: + broker: default + filter: + attributes: + type: dev.knative.samples.helloworld + source: dev.knative.samples/helloworldsource + subscriber: + ref: + apiVersion: v1 + kind: Service + name: helloworld-python + From 8de32ce4cd1656d9654c41a9760abcaecf9ffa82 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Wed, 11 Mar 2020 15:15:43 +0000 Subject: [PATCH 2/5] Update docs/eventing/samples/helloworld/helloworld-python/Dockerfile Co-Authored-By: Matt Moore --- docs/eventing/samples/helloworld/helloworld-python/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/eventing/samples/helloworld/helloworld-python/Dockerfile b/docs/eventing/samples/helloworld/helloworld-python/Dockerfile index ab2c3f2efa5..d1585d84480 100644 --- a/docs/eventing/samples/helloworld/helloworld-python/Dockerfile +++ b/docs/eventing/samples/helloworld/helloworld-python/Dockerfile @@ -1,4 +1,4 @@ -FROM python:alpine3.7 +FROM python:alpine3.7 COPY . /app From ba7ce92a1bb6736f625efe48a23501213dfea10a Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Wed, 11 Mar 2020 15:16:16 +0000 Subject: [PATCH 3/5] Update docs/eventing/samples/helloworld/helloworld-python/Dockerfile Co-Authored-By: Matt Moore --- docs/eventing/samples/helloworld/helloworld-python/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/eventing/samples/helloworld/helloworld-python/Dockerfile b/docs/eventing/samples/helloworld/helloworld-python/Dockerfile index d1585d84480..f75b7068d14 100644 --- a/docs/eventing/samples/helloworld/helloworld-python/Dockerfile +++ b/docs/eventing/samples/helloworld/helloworld-python/Dockerfile @@ -4,7 +4,7 @@ COPY . /app WORKDIR /app -RUN pip install -r requirements.txt +RUN pip install -r requirements.txt EXPOSE 8080 From ea3da4518755b85014396400fe13872668f1b01a Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Wed, 11 Mar 2020 15:16:59 +0000 Subject: [PATCH 4/5] Update docs/eventing/samples/helloworld/helloworld-python/README.md Co-Authored-By: Matt Moore --- docs/eventing/samples/helloworld/helloworld-python/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/eventing/samples/helloworld/helloworld-python/README.md b/docs/eventing/samples/helloworld/helloworld-python/README.md index 8876ada488c..a960edc4964 100644 --- a/docs/eventing/samples/helloworld/helloworld-python/README.md +++ b/docs/eventing/samples/helloworld/helloworld-python/README.md @@ -330,7 +330,6 @@ Helloworld-python app logs the context and the msg of the above event, and repli ``` **Note: You could use the above approach to test your applications too.** - ## Removing the sample app deployment @@ -340,4 +339,3 @@ To remove the sample app from your cluster, delete the service record: ```shell kubectl delete --filename sample-app.yaml ``` - From 82c085edaec1cb74b575b9de453774da797ffa8c Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Wed, 11 Mar 2020 15:17:47 +0000 Subject: [PATCH 5/5] Apply suggestions from code review Co-Authored-By: Matt Moore --- .../samples/helloworld/helloworld-python/Dockerfile | 4 ++-- .../samples/helloworld/helloworld-python/README.md | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/docs/eventing/samples/helloworld/helloworld-python/Dockerfile b/docs/eventing/samples/helloworld/helloworld-python/Dockerfile index f75b7068d14..7648331aadd 100644 --- a/docs/eventing/samples/helloworld/helloworld-python/Dockerfile +++ b/docs/eventing/samples/helloworld/helloworld-python/Dockerfile @@ -8,6 +8,6 @@ RUN pip install -r requirements.txt EXPOSE 8080 -ENTRYPOINT [ "python" ] +ENTRYPOINT [ "python" ] -CMD [ "helloworld.py" ] +CMD [ "helloworld.py" ] diff --git a/docs/eventing/samples/helloworld/helloworld-python/README.md b/docs/eventing/samples/helloworld/helloworld-python/README.md index a960edc4964..3d384cdbd33 100644 --- a/docs/eventing/samples/helloworld/helloworld-python/README.md +++ b/docs/eventing/samples/helloworld/helloworld-python/README.md @@ -54,7 +54,6 @@ cd knative-docs/docs/eventing/samples/helloworld/helloworld-python ```bash Flask==1.1.1 ``` - 1. In your project directory, create a file named `Dockerfile` and copy the code block below into it. For detailed instructions on dockerizing a Go app, see [Deploying Go servers with Docker](https://blog.golang.org/docker). @@ -175,7 +174,6 @@ folder) you're ready to build and deploy the sample app. 1. It deployed the helloworld-python app as a K8s Deployment and created a K8s service names helloworld-python. Verify using the following command. ```shell kubectl --namespace knative-samples get deployments helloworld-python - kubectl --namespace knative-samples get svc helloworld-python ``` 1. It created a Knative Eventing Trigger to route certain events to the helloworld-python application. Make sure that Ready=true @@ -204,9 +202,9 @@ We can send an http request directly to the [Broker](../../../broker-trigger.md) -d '{"msg":"Hello World from the curl pod."}' exit - ``` + ``` ### Verify that event is received by helloworld-python app -Helloworld-python app logs the context and the msg of the above event, and replies back with another event. +Helloworld-python app logs the context and the msg of the above event, and replies back with another event. 1. Display helloworld-python app logs ```shell kubectl --namespace knative-samples logs -l app=helloworld-python --tail=50 @@ -270,7 +268,7 @@ Helloworld-python app logs the context and the msg of the above event, and repli metadata: name: event-display namespace: knative-samples - spec: + spec: selector: app: event-display ports: @@ -279,7 +277,6 @@ Helloworld-python app logs the context and the msg of the above event, and repli targetPort: 8080 END ``` - 1. Create a trigger to deliver the event to the above service ```shell kubectl --namespace knative-samples apply --filename - << END