Vinculación de los eventos de Funqy Knative
Quarkus Funqy Knative Events se basa en la extensión Funqy HTTP para permitirle enrutar y procesar Knative Events dentro de una función Funqy.
La guía recorre el código de inicio rápido para mostrarte cómo puedes desplegar e invocar en funciones Funqy con Knative Events.
Requisitos previos
To complete this guide, you need:
-
Roughly 1 hour
-
An IDE
-
JDK 11+ installed with
JAVA_HOME
configured appropriately -
Apache Maven 3.8.6
-
Optionally the Quarkus CLI if you want to use it
-
Lea sobre los fundamentos de Funqy. Esta es una lectura corta!
-
Have gone through the Knative Tutorial, specifically Brokers and Triggers
Configuración de Knative
Configurar Knative localmente en un entorno Minikube está más allá del alcance de esta guía. Se recomienda seguir este tutorial de Knative elaborado por Red Hat. Se trata de cómo configurar Knative en Minikube u OpenShift en un entorno local.
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. |
Lea sobre los eventos en la nube
La especificación de los eventos en la nube es una buena lectura para que comprenda mejor los eventos de Knative.
El inicio rápido
Clone el repositorio Git: git clone https://github.com/quarkusio/quarkus-quickstarts.git
o descargue un archivo.
La solución se encuentra en funqy-knative-events-quickstart
directorio.
El flujo de inicio rápido
El quickstart funciona enviando manualmente una petición HTTP que contiene un Cloud Event al Knative Broker usando curl
. El Broker Knative recibe la petición y desencadena el inicio del contenedor Funqy construido por el quickstart. El evento desencadena la invocación de una cadena de funciones Funqy. La salida de una función desencadena la invocación de otra función Funqy.
Eventos de Funqy y Cloud
Cuando viven dentro de un entorno de Knative Events, las funciones de Funqy son activadas por un tipo de Evento de la Nube específico. Puede tener múltiples funciones Funqy dentro de una sola aplicación/despliegue, pero deben ser activadas por un Tipo de Evento de la Nube específico. La excepción a esta regla es si sólo hay una función Funqy en la aplicación. En ese caso, el evento es empujado a esa función independientemente del tipo de Evento en la Nube.
Actualmente, Funqy sólo puede consumir datos basados en JSON. Soporta tanto el modo de ejecución Binario como el Estructurado, pero el componente de datos del mensaje de Evento en la Nube debe ser JSON. Este JSON también debe ser marshallable hacia y desde los parámetros Java y los tipos de retorno de sus funciones.
El Código
Empecemos a ver nuestro código de inicio rápido para que puedas entender cómo los eventos Knative se asignan a Funqy. Abre SimpleFunctionChain.java.
La primera función que veremos es defaultChain
.
import io.quarkus.funqy.Funq;
public class SimpleFunctionChain {
@Funq
public String defaultChain(String input) {
log.info("*** defaultChain ***");
return input + "::" + "defaultChain";
}
Tal y como está, una función Funqy tiene un mapeo de Eventos en la Nube por defecto. Por defecto, el tipo de Cloud Event debe coincidir con el nombre de la función para que esta se active. Si la función devuelve una salida, la respuesta se convierte en un Evento en la Nube y se devuelve al Broker para que se dirija a otros activadores. El tipo de evento en la nube por defecto para esta respuesta es el nombre de la función + .output
. La fuente de eventos en la nube por defecto es el nombre de la función.
Así, para la función defaultChain
, el tipo de Evento en la Nube que desencadena la función es defaultChain
. Genera una respuesta que desencadena un nuevo Evento en la Nube cuyo tipo es defaultChain.output
y el origen del evento es defaultChain
.
Aunque la asignación por defecto es sencilla, puede que no siempre sea factible. Puedes cambiar esta asignación por defecto a través de la configuración. Veamos la siguiente función:
import io.quarkus.funqy.Funq;
public class SimpleFunctionChain {
@Funq
public String configChain(String input) {
log.info("*** configChain ***");
return input + "::" + "configChain";
}
La función configChain
tiene su mapeo de eventos en la nube cambiado por la configuración dentro de 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
En este caso, la configuración asigna el tipo de evento en la nube entrante defaultChain.output
a la función configChain
. La función configChain
asigna su respuesta al tipo de Evento en la Nube annotated
, y la fuente de Evento en la Nube configChain
.
-
quarkus.funqy.knative-events.mapping.{function name}.trigger
establece el tipo de Evento de Nube que desencadena una función específica. Es posible utilizar el valor especial*
como valor general. En este caso, la función se utilizará para todos los tipos de eventos. -
quarkus.funqy.knative-events.mapping.{function name}.response-type
establece el tipo de evento de nube de la respuesta -
quarkus.funqy.knative-events.mapping.{function name}.resource-source
establece la fuente de eventos de la nube de la respuesta
La extensión Funqy Knative Events también tiene anotaciones para hacer este mapeo de Cloud Event a sus funciones. Echa un vistazo al método 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";
}
Si utilizas la anotación @CloudEventMapping
en tu función, puedes asignar el desencadenamiento del tipo de Evento en la Nube y la respuesta del Evento en la Nube. En este ejemplo, la función annotatedChain
será activada por el tipo de evento en la nube annotated
y la respuesta se asignará a un tipo lastChainLink
y a una fuente de evento en la nube annotated
.
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");
}
}
Hay dos cosas que hay que tener en cuenta sobre esta función. Una, no tiene salida. Sus funciones no están obligadas a devolver salida. Segundo, hay un parámetro adicional event
a la función.
Si desea conocer información adicional sobre el evento entrante de la nube, puede inyectar la interfaz io.quarkus.funqy.knative.events.CloudEvent
utilizando la anotación Funqy @Context
. La interfaz CloudEvent
expone información sobre el evento desencadenante.
public interface CloudEvent {
String id();
String specVersion();
String source();
String subject();
OffsetDateTime time();
}
Maven
Si miras el POM, verás que es un típico POM de Quarkus que trae una dependencia de Funqy:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-funqy-knative-events</artifactId>
</dependency>
Modo de desarrollo y pruebas
Funqy Knative Events soporta el modo dev y las pruebas unitarias utilizando RestAssured. Puede invocar en las funciones de Funqy Knative Events usando el mismo modelo de invocación que Funqy HTTP usando peticiones HTTP normales, o el modo binario de Cloud Event, o el modo estructurado. Todos los modos de invocación están soportados al mismo tiempo.
Así, si abres el código de la prueba unitaria en FunqyTest.java verás que simplemente utiliza RestAssured para hacer invocaciones HTTP para probar las funciones.
¡Funqy también funciona con el modo Quarkus Dev!
Construir el proyecto
Primero construya los artefactos Java:
quarkus build
./mvnw install
A continuación, Knative necesita una imagen docker, así que tendrás que construirla:
docker build -f src/main/docker/Dockerfile.jvm -t yourAccountName/funqy-knative-events-quickstart .
Asegúrese de reemplazar yourAccountName
con su nombre de cuenta docker o quay cuando ejecute docker build
. El Dockerfile es un dockerfile estándar de Quarkus. No hay magia especial de Knative.
Envíe su imagen a docker hub o quay
docker push yourAccountName/funqy-knative-events-quickstart
De nuevo, asegúrese de sustituir yourAccountName
por el nombre de su cuenta docker o quay cuando ejecute docker push
.
Despliegue en Kubernetes/OpenShift
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
El broker que hemos creado se llama default
, este broker recibirá los eventos de la nube. El broker también está referenciado en los archivos YAML de la función.
El segundo paso es definir un servicio Kubernetes/OpenShift que apunte a la imagen Docker que creaste y empujaste durante la construcción. Echa un vistazo a 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
Se trata de un archivo YAML estándar de definición de servicios de Kubernetes.
Asegúrate de cambiar la URL de la imagen para que apunte a la imagen que construiste y subiste antes! |
Para nuestro inicio rápido, un servicio de Kubernetes contendrá todas las funciones. No hay ninguna razón por la que no se pueda dividir este inicio rápido en varios proyectos diferentes y desplegar un servicio para cada función. Para simplificar, y para mostrar que no es necesario tener un despliegue por función, el inicio rápido combina todo en un proyecto, imagen y servicio.
Despliegue el servicio:
kubectl apply -n knativetutorial -f src/main/k8s/funqy-service.yaml
El siguiente paso es desplegar los activadores de Knative Event para cada uno de los tipos de eventos. Como se ha indicado en la sección de código, cada función de Funqy se asigna a un tipo de evento de la nube específico. Debes crear desencadenantes Knative Event que mapeen un Cloud Event y lo dirijan a un servicio Kubernetes específico. Tenemos 4 disparadores diferentes.
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
asigna un tipo de evento de nube al servicio de Kubernetes definido en spec:subscriber:ref
. Cuando se envía un evento de la nube al corredor, se activará el giro del servicio asignado a ese evento.
Hay un archivo YAML de activación para cada una de nuestras 4 funciones Funqy. Despliégalos todos:
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
Ejecutar la demo
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.
Asegúrese de que tiene instalada la herramienta stern
. Consulta la configuración del Tutorial Knative para obtener información al respecto. Ejecuta stern para buscar los registros emitidos por nuestro despliegue de Funqy
stern funq user-container
Abra un terminal independiente. Primero tendrás que conocer la URL del broker. Ejecuta este comando para encontrarlo.
kubectl get broker default -o jsonpath='{.status.address.url}'
Esto le proporcionará una URL similar a, por ejemplo http://broker-ingress.knative-eventing.svc.cluster.local/knativetutorial/default
. Recuerde esta URL.
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
Puede que tengas que esperar un par de segundos hasta que aparezca el pod. Ejecute lo siguiente para obtener acceso bash al pod:
kubectl -n knativetutorial exec -it curler -- /bin/bash
Ahora estarás en un shell dentro del cluster de Kubernetes. Dentro del shell, ejecute este comando curl , la dirección del broker es un ejemplo y puede diferir según el nombre de su proyecto o broker.
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"'
Esto envía un Evento Knative al broker, que activará la función defaultChain
. Como se ha comentado anteriormente, la salida de defaultChain
desencadena un evento que se publica en configChain
, que desencadena un evento publicado en annotatedChain
y finalmente en la función lastChainLink
. Puede ver este flujo en su ventana stern
. Algo como esto debería salir.
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