Funqy Knative Events Binding
Quarkus Funqy Knative Events以Funqy HTTP扩展为基础,允许您在 Funqy 功能内路由和处理 Knative 事件。
Quarkus Funqy Knative Events builds off of the Funqy HTTP extension to allow you to route and process Knative Events within a Funqy function.
本指南通过快速入门代码展示了如何在 Knative 事件中部署和调用 Funqy 功能。
The guide walks through quickstart code to show you how you can deploy and invoke on Funqy functions with Knative Events.
Prerequisites
Unresolved directive in funqy-knative-events.adoc - include::{includes}/prerequisites.adoc[]* 阅读有关 Funqy Basics的信息。这是一篇简短的文章!* 已仔细阅读 Knative Tutorial,特别是 Brokers and Triggers
Unresolved directive in funqy-knative-events.adoc - include::{includes}/prerequisites.adoc[] * Read about Funqy Basics. This is a short read! * Have gone through the Knative Tutorial, specifically Brokers and Triggers
Setting up Knative
在 Minikube 环境中本地设置 Knative 超出了本指南的范围。建议遵循 Red Hat 编写的 thisKnative 教程。它介绍了如何在本地环境中在 Minikube 或 OpenShift 上设置 Knative。
Setting up Knative locally in a Minikube environment is beyond the scope of this guide. It is advised to follow this Knative Tutorial put together by Red Hat. It walks through how to set up Knative on Minikube or OpenShift in a local environment.
特别是,您应运行 Brokers and Triggers教程,因为本指南要求您可以在代理上调用以触发快速入门代码。 |
Specifically you should run the Brokers and Triggers tutorial as this guide requires that you can invoke on a Broker to trigger the quickstart code. |
Read about Cloud Events
Cloud Event specification是一篇很好的文章,可以帮助您对 Knative 事件有更深入的了解。
The Cloud Event specification is a good read to give you an even greater understanding of Knative Events.
The Quickstart
克隆 Git 存储库: git clone {quickstarts-clone-url}
,或下载 {quickstarts-archive-url}[存档]。
Clone the Git repository: git clone {quickstarts-clone-url}
, or download an {quickstarts-archive-url}[archive].
解决方案位于 funqy-knative-events-quickstart
directory.
The solution is located in the funqy-knative-events-quickstart
directory.
The Quickstart Flow
速启的工作原理是使用 curl
手动将包含云事件的 HTTP 请求发送到 Knative 代理。Knative 代理收到请求并触发速启构建的 Funqy 容器启动。事件触发调用 Funqy 函数链。一个函数的输出触发对另一个 Funqy 函数的调用。
The quickstart works by manually sending an HTTP request containing a Cloud Event to the Knative Broker using curl
.
The Knative Broker receives the request and triggers the startup of the Funqy container built by the quickstart.
The event triggers the invocation of a chain of Funqy functions. The output of one function triggers the
invocation of another Funqy function.
Funqy and Cloud Events
在 Knative 事件环境中运行时,Funqy 函数由特定云事件类型触发。一个应用程序/部署中可以有多个 Funqy 函数,但它们必须由特定的云事件类型触发。该规则的例外情况是,如果应用程序中只有一个 Funqy 函数。在这种情况下,事件将被推送到该函数,无论云事件类型是什么。
When living within a Knative Events environment, Funqy functions are triggered by a specific Cloud Event type. You can have multiple Funqy functions within a single application/deployment, but they must be triggered by a specific Cloud Event Type. The exception to this rule is if there is only one Funqy function in the application. In that case, the event is pushed to that function irregardless of the Cloud Event type.
目前,Funqy 仅可使用基于 JSON 的数据。它支持二进制和结构化两种执行模式,但云事件消息的数据组件必须是 JSON。此 JSON 还必须可以编组往返于 Java 参数和函数的返回类型。
Currently, Funqy can only consume JSON-based data. It supports both Binary and Structured mode of execution, but the data component of the Cloud Event message must be JSON. This JSON must also be marshallable to and from the Java parameters and return types of your functions.
The Code
让我们开始查看速启代码,以便您了解 Knative 事件如何映射到 Funqy。打开 SimpleFunctionChain.java
Let’s start looking at our quickstart code so that you can understand how Knative Events map to Funqy. Open up SimpleFunctionChain.java
我们要查看的第一个函数是 defaultChain
.
The first function we’ll look at is defaultChain
.
import io.quarkus.funqy.Funq;
public class SimpleFunctionChain {
@Funq
public String defaultChain(String input) {
log.info("*** defaultChain ***");
return input + "::" + "defaultChain";
}
Funqy 函数有一个默认的云事件映射。默认情况下,云事件类型必须与函数名称匹配才能触发该函数。如果函数返回输出,则会将响应转换为云事件并返回到代理以路由到其他触发器。此响应的默认云事件类型是函数名称 + .output
. 默认云事件源是函数名称。
As is, a Funqy function has a default Cloud Event mapping. By default, the Cloud Event type must match
the function name for the function to trigger. If the function returns output,
the response is converted into a Cloud Event and returned to the Broker to be routed to other triggers.
The default Cloud Event type for this response is the function name + .output
. The default Cloud Event source is the function name.
因此,对于 defaultChain
函数,触发该函数的云事件类型是 defaultChain
. 它生成一个响应,该响应触发了一个新云事件,其类型为 defaultChain.output
,事件源为 defaultChain
.
So, for the defaultChain
function, the Cloud Event type that triggers the function is defaultChain
. It generates
a response that triggers a new Cloud Event whose type is defaultChain.output
and the event source is defaultChain
.
虽然默认映射很简单,但可能并不总是可行。您可以通过配置更改此默认映射。我们看看下一个函数:
While the default mapping is simple, it might not always be feasible. You can change this default mapping through configuration. Let’s look at the next function:
import io.quarkus.funqy.Funq;
public class SimpleFunctionChain {
@Funq
public String configChain(String input) {
log.info("*** configChain ***");
return input + "::" + "configChain";
}
configChain
函数通过 application.properties 中的配置更改了其云事件映射。
The configChain
function has its Cloud Event mapping changed by configuration within application.properties.
quarkus.funqy.knative-events.mapping.configChain.trigger=defaultChain.output
quarkus.funqy.knative-events.mapping.configChain.response-type=annotated
quarkus.funqy.knative-events.mapping.configChain.response-source=configChain
在这种情况下,该配置将传入的云事件类型 defaultChain.output
映射到 configChain
函数。configChain
函数将其响应映射到 annotated
云事件类型和云事件源 configChain
.
In this case, the configuration maps the incoming Cloud Event type defaultChain.output
to the configChain
function.
The configChain
function maps its response to the annotated
Cloud Event type, and the Cloud Event source configChain
.
-
quarkus.funqy.knative-events.mapping.{function name}.trigger
sets the Cloud Event type that triggers a specific function. It is possible to use the special value*
as a catch-all value. The function will in this case be used for all event types. -
quarkus.funqy.knative-events.mapping.{function name}.response-type
sets the Cloud Event type of the response -
quarkus.funqy.knative-events.mapping.{function name}.resource-source
sets the Cloud Event source of the response
Funqy Knative 事件扩展还具有批注来向您的函数执行此云事件映射。查看 annotatedChain
方法
The Funqy Knative Events extension also has annotations to do this Cloud Event mapping to your functions. Take a look at the
annotatedChain
method
import io.quarkus.funqy.Funq;
import io.quarkus.funqy.knative.events.CloudEventMapping;
public class SimpleFunctionChain {
@Funq
@CloudEventMapping(trigger = "annotated", responseSource = "annotated", responseType = "lastChainLink")
public String annotatedChain(String input) {
log.info("*** annotatedChain ***");
return input + "::" + "annotatedChain";
}
如果在函数上使用 @CloudEventMapping
批注,则可以映射云事件类型触发器和云事件响应。在此示例中,annotatedChain
函数将由 annotated
云事件类型触发,并且响应将映射到 lastChainLink
类型和 annotated
云事件源。
If you use the @CloudEventMapping
annotation on your function you can map the Cloud Event type trigger
and the Cloud Event response. In this example the annotatedChain
function will be triggered
by the annotated
Cloud Event type and the response will be mapped to a lastChainLink
type
and annotated
Cloud Event source.
因此,如果您查看 SimpleFunctionChain
中定义的所有函数,您会注意到一个函数触发了下一个函数。触发的最后一个函数是 lastChainLink
.
So, if you look at all the functions defined within SimpleFunctionChain
you’ll notice that one function triggers the next.
The last function that is triggered is lastChainLink
.
import io.quarkus.funqy.Context;
import io.quarkus.funqy.Funq;
public class SimpleFunctionChain {
@Funq
public void lastChainLink(String input, @Context CloudEvent event) {
log.info("*** lastChainLink ***");
log.info(input + "::" + "lastChainLink");
}
}
关于此函数有两件事需要留意。首先,它没有输出。您的函数不必返回输出。其次,函数还有一个额外的 event
参数。
There are two things to notice about this function. One, it has no output. Your functions are not
required to return output. Second, there is an additional event
parameter to the function.
如果您想了解有关传入云事件的其他信息,可以使用 Funqy @Context
批注注入 io.quarkus.funqy.knative.events.CloudEvent
接口。CloudEvent
接口公开关于触发事件的信息。
If you want to know additional information about the incoming Cloud Event, you can inject the
io.quarkus.funqy.knative.events.CloudEvent
interface using the Funqy @Context
annotation. The CloudEvent
interface exposes information
about the triggering event.
public interface CloudEvent {
String id();
String specVersion();
String source();
String subject();
OffsetDateTime time();
}
Dev mode and Testing
Funqy Knative Events 支持开发模式并使用 RestAssured 进行单元测试。您可以使用与 Funqy HTTP 相同的调用模型通过正常的 HTTP 请求或 Cloud Event 二进制模式或结构化模式在 Funqy Knative Events 函数上调用。所有调用模式都同时受支持。
Funqy Knative Events support dev mode and unit testing using RestAssured. You can invoke on Funqy Knative Events functions using the same invocation model as Funqy HTTP using normal HTTP requests, or Cloud Event Binary mode, or Structured Mode. All invocation modes are supported at the same time.
所以,如果您在 FunqyTest.java 中打开单元测试代码,您会看到它只是使用 RestAssured 对函数进行 HTTP 调用以进行测试。
So, if you open up the unit test code in FunqyTest.java you’ll see that its simply using RestAssured to make HTTP invocations to test the functions.
Funqy 还与 Quarkus 开发模式兼容!
Funqy also works with Quarkus Dev mode!
Build the Project
首先构建 Java 工件:
First build the Java artifacts:
Unresolved directive in funqy-knative-events.adoc - include::{includes}/devtools/build.adoc[]
其次,Knative 需要一个 Docker 镜像,因此你需要构建它:
Next, a docker image is required by Knative, so you’ll need to build that next:
docker build -f src/main/docker/Dockerfile.jvm -t yourAccountName/funqy-knative-events-quickstart .
运行 docker build
时,请务必将 yourAccountName
替换为 Docker 或码头帐户名称。Dockerfile 是一个标准的 Quarkus Dockerfile。没有特殊的 Knative 魔术。
Make sure to replace yourAccountName
with your docker or quay account name when you run docker build
. The
Dockerfile is a standard Quarkus dockerfile. No special Knative magic.
将镜像推送到 Docker Hub 或 Quay
Push your image to docker hub or quay
docker push yourAccountName/funqy-knative-events-quickstart
再次,运行 docker push
时,请务必将 yourAccountName
替换为你的 Docker 或 Quay 帐户名称。
Again, make sure to replace yourAccountName
with your docker or quay account name when you run docker push
.
Deploy to Kubernetes/OpenShift
第一步是在我们的命名空间中设置代理。以下是 Knative 命令行的示例命令。
The first step is to set up the broker in our namespace. Following is an example command from the Knative cli.
kn broker create default \
--namespace knativetutorial
我们创建的代理称为 default
,此代理将接收云事件。代理也引用在函数 YAML 文件中。
The broker we have created is called default
, this broker will receive the cloud events.
The broker is also referenced in the function YAML files.
第二步是定义一个 Kubernetes/OpenShift 服务,指向你在构建期间创建和推送的 Docker 镜像。查看 funqy-service.yaml
The second step is to define a Kubernetes/OpenShift service to point to the Docker image you created and pushed during build. Take a look at funqy-service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: funqy-knative-events-quickstart
spec:
template:
metadata:
name: funqy-knative-events-quickstart-v1
annotations:
autoscaling.knative.dev/target: "1"
spec:
containers:
- image: docker.io/yourAccountName/funqy-knative-events-quickstart
这是一个标准的 Kubernetes 服务定义 YAML 文件。
This is a standard Kubernetes service definition YAML file.
确保更改镜像 URL 以指向你先前构建并推送的镜像! |
Make sure you change the image URL to point to the image you built and pushed earlier! |
在我们的快速入门中,一个 Kubernetes 服务将包含所有函数。没有理由不能将此快速入门拆分为多个不同的项目并为每个函数部署一个服务。为了简单起见,并表明不必对每个函数进行部署,快速入门将所有内容组合到一个项目、镜像和服务中。
For our quickstart, one Kubernetes service will contain all functions. There’s no reason you couldn’t break up this quickstart into multiple different projects and deploy a service for each function. For simplicity, and to show that you don’t have to have a deployment per function, the quickstart combines everything into one project, image, and service.
部署服务:
Deploy the service:
kubectl apply -n knativetutorial -f src/main/k8s/funqy-service.yaml
下一步是为每种事件类型部署 Knative 事件触发器。如下面的代码部分所示,每个 Funqy 函数都映射到特定的 Cloud Event 类型。你必须创建 Knative 事件触发器,它将映射 Cloud Event 并将其路由到特定的 Kubernetes 服务。我们有 4 个不同的触发器。
The next step is to deploy Knative Event triggers for each of the event types. As noted in the code section, each Funqy function is mapped to a specific Cloud Event type. You must create Knative Event triggers that map a Cloud Event and route it to a specific Kubernetes service. We have 4 different triggers.
{quickstarts-tree-url}/funqy-quickstarts/funqy-knative-events-quickstart/src/main/k8s/defaultChain-trigger.yaml[defaultChain-trigger.yaml]
apiVersion: eventing.knative.dev/v1alpha1
kind: Trigger
metadata:
name: defaultchain
spec:
broker: default
filter:
attributes:
type: defaultChain
subscriber:
ref:
apiVersion: serving.knative.dev/v1
kind: Service
name: funqy-knative-events-quickstart
spec:filter:attributes:type
将 Cloud Event 类型映射到 spec:subscriber:ref
中定义的 Kubernetes 服务。当 Cloud Event 被推送到代理时,它将触发映射到该事件的服务启动。
The spec:filter:attributes:type
maps a Cloud Event type to the Kubernetes service defined in spec:subscriber:ref
.
When a Cloud Event is pushed to the Broker, it will trigger the spin up of the service mapped to that event.
我们 4 个 Funqy 函数中都有一个触发器 YAML 文件。将它们全部部署出去:
There’s a trigger YAML file for each of our 4 Funqy functions. Deploy them all:
kubectl apply -n knativetutorial -f src/main/k8s/defaultChain-trigger.yaml
kubectl apply -n knativetutorial -f src/main/k8s/configChain-trigger.yaml
kubectl apply -n knativetutorial -f src/main/k8s/annotatedChain-trigger.yaml
kubectl apply -n knativetutorial -f src/main/k8s/lastChainLink-trigger.yaml
Run the demo
你需要两个不同的终端窗口。一个用来对代理服务器执行 curl 请求,另一个用来观察 pod 日志文件,以便你可以看到消息通过 Funqy 函数事件链传递。
You’ll need two different terminal windows. One to do a curl request to the Broker, the other to watch the pod log files, so you can see the messages flowing through the Funqy function event chain.
确保安装了 stern
工具。请参阅 Knative 教程设置,了解有关此工具的信息。运行 sternto,查找 Funqy 部署输出的日志
Make sure you have the stern
tool installed. See the Knative Tutorial setup for information on that. Run stern
to look for logs outputted by our Funqy deployment
stern funq user-container
打开一个单独的终端。你首先需要了解代理服务器的 URL。执行此命令以查找它。
Open a separate terminal. You’ll first need to learn the URL of the broker. Execute this command to find it.
kubectl get broker default -o jsonpath='{.status.address.url}'
此命令将为你提供类似于例如: http://broker-ingress.knative-eventing.svc.cluster.local/knativetutorial/default
的 URL。记住此 URL。
This will provide you a URL similar to e.g.: http://broker-ingress.knative-eventing.svc.cluster.local/knativetutorial/default
. Remember this URL.
接下来我们需要做的是通过 ssh 进入我们的 Kubernetes 集群,以便我们可以向代理服务器发送 curl 请求。以下命令将创建一个简单的 OS pod,以便我们可以对我们的函数进行 curl。
Next thing we need to do is ssh into our Kubernetes cluster so that we can send a curl request to our broker. The following command will create a simple OS pod so we can curl into our functions.
kubectl -n knativetutorial apply -f src/main/k8s/curler.yaml
你可能需要等待几秒钟,直到 curler pod 启动。运行以下命令,以获取对 curler pod 的 bash 访问权限:
You might need to wait a couple of seconds until the curler pod comes up. Run the following to get bash access to the curler pod:
kubectl -n knativetutorial exec -it curler -- /bin/bash
你现在将处于 Kubernetes 集群内的 shell 中。在 shell 内,执行此 curl 命令,代理服务器地址是一个示例,可能根据你的项目或代理服务器名称而有所不同。
You will now be in a shell within the Kubernetes cluster. Within the shell, execute this curl command , the broker address is an example and might differ based on your project or broker name.
curl -v "http://default-broker.knativetutorial.svc.cluster.local" \
-X POST \
-H "Ce-Id: 1234" \
-H "Ce-Specversion: 1.0" \
-H "Ce-Type: defaultChain" \
-H "Ce-Source: curl" \
-H "Content-Type: application/json" \
-d '"Start"'
这会向代理服务器发布一个 Knative 事件,该事件将触发 defaultChain
函数。如前所述, defaultChain
的输出触发了一条事件,该事件发布到 configChain
,然后该事件触发了一条事件,发布到 annotatedChain
,最后再发布到 lastChainLink
函数。你可以在 stern
窗口中看到此流程。应该输出类似于以下的内容。
This posts a Knative Event to the broker, which will trigger the defaultChain
function. As discussed earlier, the output
of defaultChain
triggers an event that is posted to configChain
which triggers an event posted to annotatedChain
then
finally to the lastChainLink
function. You can see this flow in your stern
window. Something like this should
be outputted.
funqy-knative-events-quickstart-v1-deployment-59bb88bcf4-9jwdx user-container 2020-05-12 13:44:02,256 INFO [org.acm.fun.SimpleFunctionChain] (executor-thread-1) *** defaultChain ***
funqy-knative-events-quickstart-v1-deployment-59bb88bcf4-9jwdx user-container 2020-05-12 13:44:02,365 INFO [org.acm.fun.SimpleFunctionChain] (executor-thread-2) *** configChain ***
funqy-knative-events-quickstart-v1-deployment-59bb88bcf4-9jwdx user-container 2020-05-12 13:44:02,394 INFO [org.acm.fun.SimpleFunctionChain] (executor-thread-1) *** annotatedChain ***
funqy-knative-events-quickstart-v1-deployment-59bb88bcf4-9jwdx user-container 2020-05-12 13:44:02,466 INFO [org.acm.fun.SimpleFunctionChain] (executor-thread-2) *** lastChainLink ***
funqy-knative-events-quickstart-v1-deployment-59bb88bcf4-9jwdx user-container 2020-05-12 13:44:02,467 INFO [org.acm.fun.SimpleFunctionChain] (executor-thread-2) Start::defaultChain::configChain::annotatedChain::lastChainLink