Funqy Knative Events Binding

Quarkus Funqy Knative EventsFunqy HTTP扩展为基础,允许您在 Funqy 功能内路由和处理 Knative 事件。 本指南通过快速入门代码展示了如何在 Knative 事件中部署和调用 Funqy 功能。

Prerequisites

如要完成本指南,您需要:

  • Roughly 15 minutes

  • An IDE

  • 安装了 JDK 17+,已正确配置 JAVA_HOME

  • Apache Maven ${proposed-maven-version}

  • 如果你想使用 Quarkus CLI, 则可以选择使用

  • 如果你想构建一个本机可执行文件(或如果你使用本机容器构建,则使用 Docker),则可以选择安装 Mandrel 或 GraalVM 以及 configured appropriately

Setting up Knative

在 Minikube 环境中本地设置 Knative 超出了本指南的范围。建议遵循 Red Hat 编写的 thisKnative 教程。它介绍了如何在本地环境中在 Minikube 或 OpenShift 上设置 Knative。

特别是,您应运行 Brokers and Triggers教程,因为本指南要求您可以在代理上调用以触发快速入门代码。

Read about Cloud Events

Cloud Event specification是一篇很好的文章,可以帮助您对 Knative 事件有更深入的了解。

The Quickstart

克隆 Git 存储库: git clone $${quickstarts-base-url}.git,或下载 $${quickstarts-base-url}/archive/main.zip[存档]。

解决方案位于 funqy-knative-events-quickstart directory.

The Quickstart Flow

速启的工作原理是使用 curl 手动将包含云事件的 HTTP 请求发送到 Knative 代理。Knative 代理收到请求并触发速启构建的 Funqy 容器启动。事件触发调用 Funqy 函数链。一个函数的输出触发对另一个 Funqy 函数的调用。

Funqy and Cloud Events

在 Knative 事件环境中运行时,Funqy 函数由特定云事件类型触发。一个应用程序/部署中可以有多个 Funqy 函数,但它们必须由特定的云事件类型触发。该规则的例外情况是,如果应用程序中只有一个 Funqy 函数。在这种情况下,事件将被推送到该函数,无论云事件类型是什么。

目前,Funqy 仅可使用基于 JSON 的数据。它支持二进制和结构化两种执行模式,但云事件消息的数据组件必须是 JSON。此 JSON 还必须可以编组往返于 Java 参数和函数的返回类型。

The Code

让我们开始查看速启代码,以便您了解 Knative 事件如何映射到 Funqy。打开 SimpleFunctionChain.java

我们要查看的第一个函数是 defaultChain.

import io.quarkus.funqy.Funq;

public class SimpleFunctionChain {
    @Funq
    public String defaultChain(String input) {
        log.info("*** defaultChain ***");
        return input + "::" + "defaultChain";
    }

Funqy 函数有一个默认的云事件映射。默认情况下,云事件类型必须与函数名称匹配才能触发该函数。如果函数返回输出,则会将响应转换为云事件并返回到代理以路由到其他触发器。此响应的默认云事件类型是函数名称 + .output. 默认云事件源是函数名称。

因此,对于 defaultChain 函数,触发该函数的云事件类型是 defaultChain. 它生成一个响应,该响应触发了一个新云事件,其类型为 defaultChain.output,事件源为 defaultChain.

虽然默认映射很简单,但可能并不总是可行。您可以通过配置更改此默认映射。我们看看下一个函数:

import io.quarkus.funqy.Funq;

public class SimpleFunctionChain {
    @Funq
    public String configChain(String input) {
        log.info("*** configChain ***");
        return input + "::" + "configChain";
    }

configChain 函数通过 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.

  • quarkus.funqy.knative-events.mapping.{function name}.trigger 设置触发特定函数的云事件类型。可以使用特殊值 * 作为一个包罗万象的值。在这种情况下,函数将用于所有事件类型。

  • quarkus.funqy.knative-events.mapping.{function name}.response-type 设置响应的云事件类型

  • quarkus.funqy.knative-events.mapping.{function name}.resource-source 设置响应的云事件源

Funqy Knative 事件扩展还具有批注来向您的函数执行此云事件映射。查看 annotatedChain 方法

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 云事件源。

因此,如果您查看 SimpleFunctionChain 中定义的所有函数,您会注意到一个函数触发了下一个函数。触发的最后一个函数是 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 参数。

如果您想了解有关传入云事件的其他信息,可以使用 Funqy @Context 批注注入 io.quarkus.funqy.knative.events.CloudEvent 接口。CloudEvent 接口公开关于触发事件的信息。

public interface CloudEvent {
    String id();
    String specVersion();
    String source();
    String subject();
    OffsetDateTime time();
}

Maven

如果您查看 POM,您会看到它是一个典型的 Quarkus POM,其中引入了一个 Funqy 依赖项:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-funqy-knative-events</artifactId>
</dependency>

Dev mode and Testing

Funqy Knative Events 支持开发模式并使用 RestAssured 进行单元测试。您可以使用与 Funqy HTTP 相同的调用模型通过正常的 HTTP 请求或 Cloud Event 二进制模式或结构化模式在 Funqy Knative Events 函数上调用。所有调用模式都同时受支持。

所以,如果您在 FunqyTest.java 中打开单元测试代码,您会看到它只是使用 RestAssured 对函数进行 HTTP 调用以进行测试。

Funqy 还与 Quarkus 开发模式兼容!

Build the Project

首先构建 Java 工件:

CLI
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

其次,Knative 需要一个 Docker 镜像,因此你需要构建它:

docker build -f src/main/docker/Dockerfile.jvm -t yourAccountName/funqy-knative-events-quickstart .

运行 docker build 时,请务必将 yourAccountName 替换为 Docker 或码头帐户名称。Dockerfile 是一个标准的 Quarkus Dockerfile。没有特殊的 Knative 魔术。

将镜像推送到 Docker Hub 或 Quay

docker push yourAccountName/funqy-knative-events-quickstart

再次,运行 docker push 时,请务必将 yourAccountName 替换为你的 Docker 或 Quay 帐户名称。

Deploy to Kubernetes/OpenShift

第一步是在我们的命名空间中设置代理。以下是 Knative 命令行的示例命令。

kn broker create default \
  --namespace knativetutorial

我们创建的代理称为 default,此代理将接收云事件。代理也引用在函数 YAML 文件中。

第二步是定义一个 Kubernetes/OpenShift 服务,指向你在构建期间创建和推送的 Docker 镜像。查看 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 文件。

确保更改镜像 URL 以指向你先前构建并推送的镜像!

在我们的快速入门中,一个 Kubernetes 服务将包含所有函数。没有理由不能将此快速入门拆分为多个不同的项目并为每个函数部署一个服务。为了简单起见,并表明不必对每个函数进行部署,快速入门将所有内容组合到一个项目、镜像和服务中。

部署服务:

kubectl apply -n knativetutorial -f src/main/k8s/funqy-service.yaml

下一步是为每种事件类型部署 Knative 事件触发器。如下面的代码部分所示,每个 Funqy 函数都映射到特定的 Cloud Event 类型。你必须创建 Knative 事件触发器,它将映射 Cloud Event 并将其路由到特定的 Kubernetes 服务。我们有 4 个不同的触发器。

$${quickstarts-base-url}/tree/main/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 被推送到代理时,它将触发映射到该事件的服务启动。

我们 4 个 Funqy 函数中都有一个触发器 YAML 文件。将它们全部部署出去:

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 函数事件链传递。

确保安装了 stern 工具。请参阅 Knative 教程设置,了解有关此工具的信息。运行 sternto,查找 Funqy 部署输出的日志

stern funq user-container

打开一个单独的终端。你首先需要了解代理服务器的 URL。执行此命令以查找它。

kubectl get broker default -o jsonpath='{.status.address.url}'

此命令将为你提供类似于例如: http://broker-ingress.knative-eventing.svc.cluster.local/knativetutorial/default 的 URL。记住此 URL。

接下来我们需要做的是通过 ssh 进入我们的 Kubernetes 集群,以便我们可以向代理服务器发送 curl 请求。以下命令将创建一个简单的 OS pod,以便我们可以对我们的函数进行 curl。

kubectl -n knativetutorial apply -f src/main/k8s/curler.yaml

你可能需要等待几秒钟,直到 curler pod 启动。运行以下命令,以获取对 curler pod 的 bash 访问权限:

kubectl -n knativetutorial exec -it curler -- /bin/bash

你现在将处于 Kubernetes 集群内的 shell 中。在 shell 内,执行此 curl 命令,代理服务器地址是一个示例,可能根据你的项目或代理服务器名称而有所不同。

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 窗口中看到此流程。应该输出类似于以下的内容。

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