lbroudoux / knative-user-registration

A demonstration on Knative serving and eventing using Quarkus powered apps

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Knative user-registration

This repository holds source code for a demonstration of Knativce Serverless capabilities on OpenShift. It demonstrates basic features of Knative Serving and Eventing modules.

Here's the architecture of the application we're going to deploy and managed with Knative:

Architecture

The application is made of following components:

  • A user-registration microservice that is presenting a REST API for registering new users into a system,
  • A Kafka broker that aims to persist the different events emitted by the user-registration component on registrations,
  • A bunch of event-driven components that consumes events from Kafka to process the registration events.

In the demonstration scenario, we are going to deploy 2 differents revisions of the user-registration service to illustrate traffic distribution and canary release using Knative. Also we're going to use Knative Eventing concepts (Source, Channel and Subscription) to make the events consumers serverless too.

Setup

This current version of the demo was updated for OpenShift 4.9+ cluster. It was initially created at OpenShift 4.5+/4.6 time. It you're running an older version, please navigate to the /openshift-4.6 folder where you'll find previous version of this README.

So you should have an OpenShift 4.9+ cluster (or a Kubernetes one but it's trickier to setup) with the different features enabled:

  • Strimzi.io Operator up and running for providing a Kafka broker to the app,
  • Knative Serving and Eventing installed and deployed in their own namespaces, as well as a KnativeKafka resource created in knative-eventing with spec.source.enabled set to true

You should also have the kn CLI tool available on your laptop or bastion server:

$ kn version
Version:      v20201110-e8b26e18
Build Date:   2020-11-10 10:39:27
Git Revision: e8b26e18
Supported APIs:
* Serving
  - serving.knative.dev/v1 (knative-serving v0.18.0)
* Eventing
  - sources.knative.dev/v1alpha2 (knative-eventing v0.18.0)
  - eventing.knative.dev/v1beta1 (knative-eventing v0.18.0)

Start creating the new project to host our components and the dedicated broker:

oc new-project user-registration-serverless
oc create -f kafka-broker-openshift.yml -n user-registration-serverless

Demonstration

Knative Serving

Deploy version v1 of the user-registration:

$ kn service create user-registration --image quay.io/microcks/quarkus-user-registration:0.1 --env QUARKUS_PROFILE=kube --port 8383 -n user-registration-serverless
Creating service 'user-registration' in namespace 'user-registration-serverless':

  0.039s The Configuration is still working to reflect the latest desired specification.
  0.106s The Route is still working to reflect the latest desired specification.
  0.229s Configuration "user-registration" is waiting for a Revision to become ready.
  9.660s ...
  9.749s Ingress has not yet been reconciled.
  9.850s unsuccessfully observed a new generation
 10.021s Ready to serve.

Service 'user-registration' created to latest revision 'user-registration-wjhqk-1' is available at URL:
http://user-registration-user-registration-serverless.apps.cluster-7eee.7eee.example.opentlc.com

$ kn service update user-registration --tag user-registration-wjhqk-1=v1
Updating Service 'user-registration' in namespace 'user-registration-serverless':

  0.031s The Route is still working to reflect the latest desired specification.
  0.114s Ingress has not yet been reconciled.
  0.136s unsuccessfully observed a new generation
  0.511s Ready to serve.

Service 'user-registration' with latest revision 'user-registration-wjhqk-1' (unchanged) is available at URL:
http://user-registration-user-registration-serverless.apps.cluster-7eee.7eee.example.opentlc.com

$ export APP_URL=`oc get ksvc user-registration -o json -n user-registration-serverless | jq -r '.status.url'`

Play with App through CURL command, registering new users and see the Pods scaling-up and down:

$ curl -XPOST $APP_URL/register -H 'Content-type: application/json' -d '{"fullName":"Laurent Broudoux","email":"laurent.broudoux@gmail.com","age":43}' -s | jq .
{
  "age": 43,
  "email": "laurent.broudoux@gmail.com",
  "fullName": "Laurent Broudoux",
  "id": "c637a5f8-ecfe-45be-b44d-69bf08043603"
}

We've got v1 responses so far with just 4 properties in the response. Deploy version v2 that adds a new property and send events to Kafka. Do not put traffic on this new revision.

$ kn service update user-registration --image quay.io/microcks/quarkus-user-registration:latest --traffic @latest=0 --traffic v1=100
Updating Service 'user-registration' in namespace 'user-registration-serverless':

  0.060s The Configuration is still working to reflect the latest desired specification.
  6.794s Traffic is not yet migrated to the latest revision.
  6.871s Ingress has not yet been reconciled.
  6.978s Ready to serve.

Service 'user-registration' updated to latest revision 'user-registration-mwmrh-3' is available at URL:
http://user-registration-user-registration-serverless.apps.cluster-7eee.7eee.example.opentlc.com

From here, we want to split traffic between the 2 revisions to do a canary release. You can do that through:

the OpenShift console UI, tagging the new revision with v2 (see below image),

Traffic distribution

or through the command line (see below commands):

$ kn service update user-registration --tag user-registration-mwmrh-3=v2
$ kn service update user-registration --traffic v2=10 --traffic v1=90

You can retrieve the specific v2 url and check everything is fine:

$ export APP_V2_URL=`oc get ksvc user-registration -o json -n user-registration-serverless | jq -r '.status.traffic[1].url'`

$ curl -XPOST $APP_V2_URL/register -H 'Content-type: application/json' -d '{"fullName":"Laurent Broudoux","email":"laurent.broudoux@gmail.com","age":43}' -s | jq .
{
  "age": 43,
  "email": "laurent.broudoux@gmail.com",
  "fullName": "Laurent Broudoux",
  "id": "a34d49f4-5332-4919-bd00-35089af32ee4",
  "registrationDate": "1606493455380"
}

Now that you're happy, move traffic from v1 to v2

$ curl -XPOST $APP_URL/register -H 'Content-type: application/json' -d '{"fullName":"Laurent Broudoux","email":"laurent.broudoux@gmail.com","age":43}' -s | jq .
{
  "age": 43,
  "email": "laurent.broudoux@gmail.com",
  "fullName": "Laurent Broudoux",
  "id": "bba6e464-4cb3-4361-ad20-0e3294bdb00f"
}

$ kn service update user-registration --traffic v1=0,v2=100
Updating Service 'user-registration' in namespace 'user-registration-serverless':

  0.057s The Route is still working to reflect the latest desired specification.
  0.134s Ingress has not yet been reconciled.
  0.235s unsuccessfully observed a new generation
  0.591s Ready to serve.

Service 'user-registration' with latest revision 'user-registration-mwmrh-3' (unchanged) is available at URL:
http://user-registration-user-registration-serverless.apps.cluster-7eee.7eee.example.opentlc.com

$ curl -XPOST $APP_URL/register -H 'Content-type: application/json' -d '{"fullName":"Laurent Broudoux","email":"laurent.broudoux@gmail.com","age":43}' -s | jq .
{
  "age": 43,
  "email": "laurent.broudoux@gmail.com",
  "fullName": "Laurent Broudoux",
  "id": "fafc43d4-46e3-4595-b5d5-e17f31ae3fac",
  "registrationDate": "1606493796914"
}

Knative Eventing

Create the Source and the Channel

oc create -f user-signed-up-channel.yml -n user-registration-serverless
oc create -f user-signed-up-source.yml -n user-registration-serverless

Deploy the user-registration-consumer

$ kn service create user-registration-consumer --image quay.io/lbroudoux/user-registration-consumer:latest --port 8484 -n user-registration-serverless

Deploy some other consumer...

$ kn service create event-display --image gcr.io/knative-releases/knative.dev/eventing-contrib/cmd/event_display

Create Subscriptions to bind the Channel to our consumers. You can do that using the OpenShift Console Developer UI by drag-n-dropping connections between the Channel and the Knative Services or with this commands:

oc create -f event-display-subscription.yml -n user-registration-serverless
oc create -f user-registration-consumer-subscription.yml -n user-registration-serverless

Now it's time to demonstrate everything altogether! Be sure that you waited long enough so that there's no pod still running on the different microservices. You should have something like that:

Scale Zero

Then send a request to the App and you should see everything light-up starting with the user-registration component ans just after the 2 events consumers:

$ curl -XPOST $APP_URL/register -H 'Content-type: application/json' -d '{"fullName":"Laurent Broudoux","email":"laurent.broudoux@gmail.com","age":43}' -s | jq .
{
  "age": 43,
  "email": "laurent.broudoux@gmail.com",
  "fullName": "Laurent Broudoux",
  "id": "da4acd59-044b-4c8f-a607-3b568c7cee27",
  "registrationDate": "1606751232863"
}

Scale Up

Check the logs in the event-display-* pod and you should have something like:

☁️  cloudevents.Event
Validation: valid
Context Attributes,
  specversion: 1.0
  type: dev.knative.kafka.event
  source: /apis/v1/namespaces/user-registration-serverless/kafkasources/kafka-source#user-signed-up
  subject: partition:0#2
  id: partition:0/offset:2
  time: 2022-03-30T09:00:16.099Z
Extensions,
  key: 1648630816093
Data,
  {"age":43,"email":"laurent.broudoux@gmail.com","fullName":"Laurent Broudoux","id":"ae63eb76-388e-4874-ade7-831f3fabb194","sendAt":"1648630816093"}

Check the logs in the user-registration-consumer-* pod and you should have something like:

__  ____  __  _____   ___  __ ____  ______
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2022-03-30 09:02:21,363 INFO  [io.quarkus] (main) user-registration-consumer 1.0-SNAPSHOT native (powered by Quarkus 1.9.2.Final) started in 0.033s. Listening on: http://0.0.0.0:8484
2022-03-30 09:02:21,364 INFO  [io.quarkus] (main) Profile prod activated.
2022-03-30 09:02:21,364 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy, resteasy-jackson]
2022-03-30 09:02:22,113 INFO  [org.acm.reg.UserRegistrationResource] (executor-thread-1) cloudEventJson: {"age":41,"email":"laurent.broudoux@gmail.com","fullName":"Laurent Broudoux","id":"ba7267a1-baf1-41f4-ab77-bf0adf9fbf2f","sendAt":"1648630938601"}
2022-03-30 09:02:22,114 INFO  [org.acm.reg.UserRegistrationResource] (executor-thread-1) Processing registration {ba7267a1-baf1-41f4-ab77-bf0adf9fbf2f} for {Laurent Broudoux}

Troubleshoot

Check on Kafka broker

$ oc exec -n user-registration-serverless -it my-cluster-kafka-0 -- /opt/kafka/bin/kafka-console-consumer.sh \
    --bootstrap-server localhost:9092 \
    --from-beginning \
    --property print.key=true \
    --topic user-signed-up

$ oc exec -n user-registration-serverless -it my-cluster-kafka-0 -- /opt/kafka/bin/kafka-console-producer.sh \
    --broker-list my-cluster-kafka-bootstrap:9092 \
    --topic user-signed-up

About

A demonstration on Knative serving and eventing using Quarkus powered apps

License:MIT License


Languages

Language:HTML 59.2%Language:Java 40.8%