mirror of https://github.com/knative/docs.git
Added Python Example for Knative Eventing (#2299)
* Added Python Knative Eventing Helloworld Example * Update docs/eventing/samples/helloworld/helloworld-python/Dockerfile Co-Authored-By: Matt Moore <mattmoor@vmware.com> * Update docs/eventing/samples/helloworld/helloworld-python/Dockerfile Co-Authored-By: Matt Moore <mattmoor@vmware.com> * Update docs/eventing/samples/helloworld/helloworld-python/README.md Co-Authored-By: Matt Moore <mattmoor@vmware.com> * Apply suggestions from code review Co-Authored-By: Matt Moore <mattmoor@vmware.com> Co-authored-by: Matt Moore <mattmoor@vmware.com>
This commit is contained in:
parent
b00dd3cb20
commit
0b86a4a7e0
|
@ -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" ]
|
|
@ -0,0 +1,338 @@
|
|||
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
|
||||
```
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
title: "Hello World - Python"
|
||||
linkTitle: "Python"
|
||||
weight: 20
|
||||
type: "docs"
|
||||
---
|
||||
|
||||
{{% readfile file="README.md" %}}
|
|
@ -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)
|
||||
|
|
@ -0,0 +1 @@
|
|||
Flask==1.1.1
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue